multi_workspace_tests.rs

  1use std::path::PathBuf;
  2
  3use super::*;
  4use fs::FakeFs;
  5use gpui::TestAppContext;
  6use project::{DisableAiSettings, ProjectGroupKey};
  7use serde_json::json;
  8use settings::SettingsStore;
  9use util::path;
 10
 11fn init_test(cx: &mut TestAppContext) {
 12    cx.update(|cx| {
 13        let settings_store = SettingsStore::test(cx);
 14        cx.set_global(settings_store);
 15        theme_settings::init(theme::LoadThemes::JustBase, cx);
 16        DisableAiSettings::register(cx);
 17    });
 18}
 19
 20#[gpui::test]
 21async fn test_sidebar_disabled_when_disable_ai_is_enabled(cx: &mut TestAppContext) {
 22    init_test(cx);
 23    let fs = FakeFs::new(cx.executor());
 24    let project = Project::test(fs, [], cx).await;
 25
 26    let (multi_workspace, cx) =
 27        cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));
 28
 29    multi_workspace.read_with(cx, |mw, cx| {
 30        assert!(mw.multi_workspace_enabled(cx));
 31    });
 32
 33    multi_workspace.update_in(cx, |mw, _window, cx| {
 34        mw.open_sidebar(cx);
 35        assert!(mw.sidebar_open());
 36    });
 37
 38    cx.update(|_window, cx| {
 39        DisableAiSettings::override_global(DisableAiSettings { disable_ai: true }, cx);
 40    });
 41    cx.run_until_parked();
 42
 43    multi_workspace.read_with(cx, |mw, cx| {
 44        assert!(
 45            !mw.sidebar_open(),
 46            "Sidebar should be closed when disable_ai is true"
 47        );
 48        assert!(
 49            !mw.multi_workspace_enabled(cx),
 50            "Multi-workspace should be disabled when disable_ai is true"
 51        );
 52    });
 53
 54    multi_workspace.update_in(cx, |mw, window, cx| {
 55        mw.toggle_sidebar(window, cx);
 56    });
 57    multi_workspace.read_with(cx, |mw, _cx| {
 58        assert!(
 59            !mw.sidebar_open(),
 60            "Sidebar should remain closed when toggled with disable_ai true"
 61        );
 62    });
 63
 64    cx.update(|_window, cx| {
 65        DisableAiSettings::override_global(DisableAiSettings { disable_ai: false }, cx);
 66    });
 67    cx.run_until_parked();
 68
 69    multi_workspace.read_with(cx, |mw, cx| {
 70        assert!(
 71            mw.multi_workspace_enabled(cx),
 72            "Multi-workspace should be enabled after re-enabling AI"
 73        );
 74        assert!(
 75            !mw.sidebar_open(),
 76            "Sidebar should still be closed after re-enabling AI (not auto-opened)"
 77        );
 78    });
 79
 80    multi_workspace.update_in(cx, |mw, window, cx| {
 81        mw.toggle_sidebar(window, cx);
 82    });
 83    multi_workspace.read_with(cx, |mw, _cx| {
 84        assert!(
 85            mw.sidebar_open(),
 86            "Sidebar should open when toggled after re-enabling AI"
 87        );
 88    });
 89}
 90
 91#[gpui::test]
 92async fn test_project_group_keys_initial(cx: &mut TestAppContext) {
 93    init_test(cx);
 94    let fs = FakeFs::new(cx.executor());
 95    fs.insert_tree("/root_a", json!({ "file.txt": "" })).await;
 96    let project = Project::test(fs, ["/root_a".as_ref()], cx).await;
 97
 98    let expected_key = project.read_with(cx, |project, cx| project.project_group_key(cx));
 99
100    let (multi_workspace, cx) =
101        cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));
102
103    multi_workspace.update(cx, |mw, cx| {
104        mw.open_sidebar(cx);
105    });
106
107    multi_workspace.read_with(cx, |mw, _cx| {
108        let keys: Vec<&ProjectGroupKey> = mw.project_group_keys().collect();
109        assert_eq!(keys.len(), 1, "should have exactly one key on creation");
110        assert_eq!(*keys[0], expected_key);
111    });
112}
113
114#[gpui::test]
115async fn test_project_group_keys_add_workspace(cx: &mut TestAppContext) {
116    init_test(cx);
117    let fs = FakeFs::new(cx.executor());
118    fs.insert_tree("/root_a", json!({ "file.txt": "" })).await;
119    fs.insert_tree("/root_b", json!({ "file.txt": "" })).await;
120    let project_a = Project::test(fs.clone(), ["/root_a".as_ref()], cx).await;
121    let project_b = Project::test(fs.clone(), ["/root_b".as_ref()], cx).await;
122
123    let key_a = project_a.read_with(cx, |p, cx| p.project_group_key(cx));
124    let key_b = project_b.read_with(cx, |p, cx| p.project_group_key(cx));
125    assert_ne!(
126        key_a, key_b,
127        "different roots should produce different keys"
128    );
129
130    let (multi_workspace, cx) =
131        cx.add_window_view(|window, cx| MultiWorkspace::test_new(project_a, window, cx));
132
133    multi_workspace.update(cx, |mw, cx| {
134        mw.open_sidebar(cx);
135    });
136
137    multi_workspace.read_with(cx, |mw, _cx| {
138        assert_eq!(mw.project_group_keys().count(), 1);
139    });
140
141    // Adding a workspace with a different project root adds a new key.
142    multi_workspace.update_in(cx, |mw, window, cx| {
143        mw.test_add_workspace(project_b, window, cx);
144    });
145
146    multi_workspace.read_with(cx, |mw, _cx| {
147        let keys: Vec<&ProjectGroupKey> = mw.project_group_keys().collect();
148        assert_eq!(
149            keys.len(),
150            2,
151            "should have two keys after adding a second workspace"
152        );
153        assert_eq!(*keys[0], key_b);
154        assert_eq!(*keys[1], key_a);
155    });
156}
157
158#[gpui::test]
159async fn test_open_new_window_does_not_open_sidebar_on_existing_window(cx: &mut TestAppContext) {
160    init_test(cx);
161
162    let app_state = cx.update(AppState::test);
163    let fs = app_state.fs.as_fake();
164    fs.insert_tree(path!("/project_a"), json!({ "file.txt": "" }))
165        .await;
166    fs.insert_tree(path!("/project_b"), json!({ "file.txt": "" }))
167        .await;
168
169    let project = Project::test(app_state.fs.clone(), [path!("/project_a").as_ref()], cx).await;
170
171    let window = cx.add_window(|window, cx| MultiWorkspace::test_new(project, window, cx));
172
173    window
174        .read_with(cx, |mw, _cx| {
175            assert!(!mw.sidebar_open(), "sidebar should start closed",);
176        })
177        .unwrap();
178
179    cx.update(|cx| {
180        open_paths(
181            &[PathBuf::from(path!("/project_b"))],
182            app_state,
183            OpenOptions {
184                open_mode: OpenMode::NewWindow,
185                ..OpenOptions::default()
186            },
187            cx,
188        )
189    })
190    .await
191    .unwrap();
192
193    window
194        .read_with(cx, |mw, _cx| {
195            assert!(
196                !mw.sidebar_open(),
197                "opening a project in a new window must not open the sidebar on the original window",
198            );
199        })
200        .unwrap();
201}
202
203#[gpui::test]
204async fn test_project_group_keys_duplicate_not_added(cx: &mut TestAppContext) {
205    init_test(cx);
206    let fs = FakeFs::new(cx.executor());
207    fs.insert_tree("/root_a", json!({ "file.txt": "" })).await;
208    let project_a = Project::test(fs.clone(), ["/root_a".as_ref()], cx).await;
209    // A second project entity pointing at the same path produces the same key.
210    let project_a2 = Project::test(fs.clone(), ["/root_a".as_ref()], cx).await;
211
212    let key_a = project_a.read_with(cx, |p, cx| p.project_group_key(cx));
213    let key_a2 = project_a2.read_with(cx, |p, cx| p.project_group_key(cx));
214    assert_eq!(key_a, key_a2, "same root path should produce the same key");
215
216    let (multi_workspace, cx) =
217        cx.add_window_view(|window, cx| MultiWorkspace::test_new(project_a, window, cx));
218
219    multi_workspace.update(cx, |mw, cx| {
220        mw.open_sidebar(cx);
221    });
222
223    multi_workspace.update_in(cx, |mw, window, cx| {
224        mw.test_add_workspace(project_a2, window, cx);
225    });
226
227    multi_workspace.read_with(cx, |mw, _cx| {
228        let keys: Vec<&ProjectGroupKey> = mw.project_group_keys().collect();
229        assert_eq!(
230            keys.len(),
231            1,
232            "duplicate key should not be added when a workspace with the same root is inserted"
233        );
234    });
235}