diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 40f1173579..4c1c253471 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -13,8 +13,8 @@ use editor::{ use fs::{FakeFs, Fs as _, LineEnding, RemoveOptions}; use futures::StreamExt as _; use gpui::{ - executor::Deterministic, geometry::vector::vec2f, test::EmptyView, ModelHandle, TestAppContext, - ViewHandle, + executor::Deterministic, geometry::vector::vec2f, test::EmptyView, AppContext, ModelHandle, + TestAppContext, ViewHandle, }; use indoc::indoc; use language::{ @@ -2604,6 +2604,85 @@ async fn test_git_diff_base_change( }); } +#[gpui::test] +async fn test_git_branch_name( + deterministic: Arc, + cx_a: &mut TestAppContext, + cx_b: &mut TestAppContext, +) { + deterministic.forbid_parking(); + let mut server = TestServer::start(&deterministic).await; + let client_a = server.create_client(cx_a, "user_a").await; + let client_b = server.create_client(cx_b, "user_b").await; + server + .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)]) + .await; + let active_call_a = cx_a.read(ActiveCall::global); + + client_a + .fs + .insert_tree( + "/dir", + json!({ + ".git": {}, + }), + ) + .await; + + let (project_local, _worktree_id) = client_a.build_local_project("/dir", cx_a).await; + let project_id = active_call_a + .update(cx_a, |call, cx| { + call.share_project(project_local.clone(), cx) + }) + .await + .unwrap(); + + let project_remote = client_b.build_remote_project(project_id, cx_b).await; + client_a + .fs + .as_fake() + .set_branch_name(Path::new("/dir/.git"), Some("branch-1")) + .await; + + // Wait for it to catch up to the new branch + deterministic.run_until_parked(); + + #[track_caller] + fn assert_branch(branch_name: Option>, project: &Project, cx: &AppContext) { + let branch_name = branch_name.map(Into::into); + let worktrees = project.visible_worktrees(cx).collect::>(); + assert_eq!(worktrees.len(), 1); + let worktree = worktrees[0].clone(); + let root_entry = worktree.read(cx).snapshot().root_git_entry().unwrap(); + assert_eq!(root_entry.branch(), branch_name.map(Into::into)); + } + + // Smoke test branch reading + project_local.read_with(cx_a, |project, cx| { + assert_branch(Some("branch-1"), project, cx) + }); + project_remote.read_with(cx_b, |project, cx| { + assert_branch(Some("branch-1"), project, cx) + }); + + client_a + .fs + .as_fake() + .set_branch_name(Path::new("/dir/.git"), Some("branch-2")) + .await; + + // Wait for buffer_local_a to receive it + deterministic.run_until_parked(); + + // Smoke test branch reading + project_local.read_with(cx_a, |project, cx| { + assert_branch(Some("branch-2"), project, cx) + }); + project_remote.read_with(cx_b, |project, cx| { + assert_branch(Some("branch-2"), project, cx) + }); +} + #[gpui::test(iterations = 10)] async fn test_fs_operations( deterministic: Arc, diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index d856b71e39..945ffaea16 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -619,7 +619,10 @@ impl FakeFs { .boxed() } - pub async fn set_index_for_repo(&self, dot_git: &Path, head_state: &[(&Path, String)]) { + pub fn with_git_state(&self, dot_git: &Path, f: F) + where + F: FnOnce(&mut FakeGitRepositoryState), + { let mut state = self.state.lock(); let entry = state.read_path(dot_git).unwrap(); let mut entry = entry.lock(); @@ -628,12 +631,7 @@ impl FakeFs { let repo_state = git_repo_state.get_or_insert_with(Default::default); let mut repo_state = repo_state.lock(); - repo_state.index_contents.clear(); - repo_state.index_contents.extend( - head_state - .iter() - .map(|(path, content)| (path.to_path_buf(), content.clone())), - ); + f(&mut repo_state); state.emit_event([dot_git]); } else { @@ -641,6 +639,21 @@ impl FakeFs { } } + pub async fn set_branch_name(&self, dot_git: &Path, branch: Option>) { + self.with_git_state(dot_git, |state| state.branch_name = branch.map(Into::into)) + } + + pub async fn set_index_for_repo(&self, dot_git: &Path, head_state: &[(&Path, String)]) { + self.with_git_state(dot_git, |state| { + state.index_contents.clear(); + state.index_contents.extend( + head_state + .iter() + .map(|(path, content)| (path.to_path_buf(), content.clone())), + ); + }); + } + pub fn paths(&self) -> Vec { let mut result = Vec::new(); let mut queue = collections::VecDeque::new(); diff --git a/crates/fs/src/repository.rs b/crates/fs/src/repository.rs index d22d670a8b..5624ce42f1 100644 --- a/crates/fs/src/repository.rs +++ b/crates/fs/src/repository.rs @@ -71,6 +71,7 @@ pub struct FakeGitRepository { #[derive(Debug, Clone, Default)] pub struct FakeGitRepositoryState { pub index_contents: HashMap, + pub branch_name: Option, } impl FakeGitRepository { @@ -89,7 +90,8 @@ impl GitRepository for FakeGitRepository { } fn branch_name(&self) -> Option { - None + let state = self.state.lock(); + state.branch_name.clone() } }