1use std::path::Path;
2
3use call::ActiveCall;
4use git::status::{FileStatus, StatusCode, TrackedStatus};
5use git_ui::project_diff::ProjectDiff;
6use gpui::{AppContext as _, TestAppContext, VisualTestContext};
7use project::ProjectPath;
8use serde_json::json;
9use util::{path, rel_path::rel_path};
10use workspace::{MultiWorkspace, Workspace};
11
12//
13use crate::TestServer;
14
15#[gpui::test]
16async fn test_project_diff(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
17 let mut server = TestServer::start(cx_a.background_executor.clone()).await;
18 let client_a = server.create_client(cx_a, "user_a").await;
19 let client_b = server.create_client(cx_b, "user_b").await;
20 cx_a.set_name("cx_a");
21 cx_b.set_name("cx_b");
22
23 server
24 .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
25 .await;
26
27 client_a
28 .fs()
29 .insert_tree(
30 path!("/a"),
31 json!({
32 ".git": {},
33 "changed.txt": "after\n",
34 "unchanged.txt": "unchanged\n",
35 "created.txt": "created\n",
36 "secret.pem": "secret-changed\n",
37 }),
38 )
39 .await;
40
41 client_a.fs().set_head_and_index_for_repo(
42 Path::new(path!("/a/.git")),
43 &[
44 ("changed.txt", "before\n".to_string()),
45 ("unchanged.txt", "unchanged\n".to_string()),
46 ("deleted.txt", "deleted\n".to_string()),
47 ("secret.pem", "shh\n".to_string()),
48 ],
49 );
50 let (project_a, worktree_id) = client_a.build_local_project(path!("/a"), cx_a).await;
51 let active_call_a = cx_a.read(ActiveCall::global);
52 let project_id = active_call_a
53 .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
54 .await
55 .unwrap();
56
57 cx_b.update(editor::init);
58 cx_b.update(git_ui::init);
59 let project_b = client_b.join_remote_project(project_id, cx_b).await;
60 let window_b = cx_b.add_window(|window, cx| {
61 let workspace = cx.new(|cx| {
62 Workspace::new(
63 None,
64 project_b.clone(),
65 client_b.app_state.clone(),
66 window,
67 cx,
68 )
69 });
70 MultiWorkspace::new(workspace, window, cx)
71 });
72 let cx_b = &mut VisualTestContext::from_window(*window_b, cx_b);
73 let workspace_b = window_b
74 .root(cx_b)
75 .unwrap()
76 .read_with(cx_b, |multi_workspace, _| {
77 multi_workspace.workspace().clone()
78 });
79
80 cx_b.update(|window, cx| {
81 window
82 .focused(cx)
83 .unwrap()
84 .dispatch_action(&git_ui::project_diff::Diff, window, cx)
85 });
86 let diff = workspace_b.update(cx_b, |workspace, cx| {
87 workspace.active_item(cx).unwrap().act_as::<ProjectDiff>(cx)
88 });
89 let diff = diff.unwrap();
90 cx_b.run_until_parked();
91
92 diff.update(cx_b, |diff, cx| {
93 assert_eq!(
94 diff.excerpt_paths(cx),
95 vec![
96 rel_path("changed.txt").into_arc(),
97 rel_path("deleted.txt").into_arc(),
98 rel_path("created.txt").into_arc()
99 ]
100 );
101 });
102
103 client_a
104 .fs()
105 .insert_tree(
106 path!("/a"),
107 json!({
108 ".git": {},
109 "changed.txt": "before\n",
110 "unchanged.txt": "changed\n",
111 "created.txt": "created\n",
112 "secret.pem": "secret-changed\n",
113 }),
114 )
115 .await;
116 cx_b.run_until_parked();
117
118 project_b.update(cx_b, |project, cx| {
119 let project_path = ProjectPath {
120 worktree_id,
121 path: rel_path("unchanged.txt").into(),
122 };
123 let status = project.project_path_git_status(&project_path, cx);
124 assert_eq!(
125 status.unwrap(),
126 FileStatus::Tracked(TrackedStatus {
127 worktree_status: StatusCode::Modified,
128 index_status: StatusCode::Unmodified,
129 })
130 );
131 });
132
133 diff.update(cx_b, |diff, cx| {
134 assert_eq!(
135 diff.excerpt_paths(cx),
136 vec![
137 rel_path("deleted.txt").into_arc(),
138 rel_path("unchanged.txt").into_arc(),
139 rel_path("created.txt").into_arc()
140 ]
141 );
142 });
143}