1use super::*;
2use feature_flags::FeatureFlagAppExt;
3use fs::FakeFs;
4use gpui::TestAppContext;
5use project::DisableAiSettings;
6use settings::SettingsStore;
7
8fn init_test(cx: &mut TestAppContext) {
9 cx.update(|cx| {
10 let settings_store = SettingsStore::test(cx);
11 cx.set_global(settings_store);
12 theme_settings::init(theme::LoadThemes::JustBase, cx);
13 DisableAiSettings::register(cx);
14 cx.update_flags(false, vec!["agent-v2".into()]);
15 });
16}
17
18#[gpui::test]
19async fn test_sidebar_disabled_when_disable_ai_is_enabled(cx: &mut TestAppContext) {
20 init_test(cx);
21 let fs = FakeFs::new(cx.executor());
22 let project = Project::test(fs, [], cx).await;
23
24 let (multi_workspace, cx) =
25 cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));
26
27 multi_workspace.read_with(cx, |mw, cx| {
28 assert!(mw.multi_workspace_enabled(cx));
29 });
30
31 multi_workspace.update_in(cx, |mw, _window, cx| {
32 mw.open_sidebar(cx);
33 assert!(mw.sidebar_open());
34 });
35
36 cx.update(|_window, cx| {
37 DisableAiSettings::override_global(DisableAiSettings { disable_ai: true }, cx);
38 });
39 cx.run_until_parked();
40
41 multi_workspace.read_with(cx, |mw, cx| {
42 assert!(
43 !mw.sidebar_open(),
44 "Sidebar should be closed when disable_ai is true"
45 );
46 assert!(
47 !mw.multi_workspace_enabled(cx),
48 "Multi-workspace should be disabled when disable_ai is true"
49 );
50 });
51
52 multi_workspace.update_in(cx, |mw, window, cx| {
53 mw.toggle_sidebar(window, cx);
54 });
55 multi_workspace.read_with(cx, |mw, _cx| {
56 assert!(
57 !mw.sidebar_open(),
58 "Sidebar should remain closed when toggled with disable_ai true"
59 );
60 });
61
62 cx.update(|_window, cx| {
63 DisableAiSettings::override_global(DisableAiSettings { disable_ai: false }, cx);
64 });
65 cx.run_until_parked();
66
67 multi_workspace.read_with(cx, |mw, cx| {
68 assert!(
69 mw.multi_workspace_enabled(cx),
70 "Multi-workspace should be enabled after re-enabling AI"
71 );
72 assert!(
73 !mw.sidebar_open(),
74 "Sidebar should still be closed after re-enabling AI (not auto-opened)"
75 );
76 });
77
78 multi_workspace.update_in(cx, |mw, window, cx| {
79 mw.toggle_sidebar(window, cx);
80 });
81 multi_workspace.read_with(cx, |mw, _cx| {
82 assert!(
83 mw.sidebar_open(),
84 "Sidebar should open when toggled after re-enabling AI"
85 );
86 });
87}
88
89#[gpui::test]
90async fn test_replace(cx: &mut TestAppContext) {
91 init_test(cx);
92 let fs = FakeFs::new(cx.executor());
93 let project_a = Project::test(fs.clone(), [], cx).await;
94 let project_b = Project::test(fs.clone(), [], cx).await;
95 let project_c = Project::test(fs.clone(), [], cx).await;
96 let project_d = Project::test(fs.clone(), [], cx).await;
97
98 let (multi_workspace, cx) =
99 cx.add_window_view(|window, cx| MultiWorkspace::test_new(project_a.clone(), window, cx));
100
101 let workspace_a_id = multi_workspace.read_with(cx, |mw, _cx| {
102 mw.workspaces()
103 .next()
104 .expect("workspace should exist")
105 .entity_id()
106 });
107
108 // Replace the only workspace (single-workspace case).
109 let workspace_b = multi_workspace.update_in(cx, |mw, window, cx| {
110 let workspace = cx.new(|cx| Workspace::test_new(project_b.clone(), window, cx));
111 mw.replace(workspace.clone(), window, cx);
112 workspace
113 });
114
115 multi_workspace.read_with(cx, |mw, _cx| {
116 assert_eq!(mw.len(), 1);
117 assert_eq!(
118 mw.workspaces()
119 .next()
120 .expect("workspace should exist")
121 .entity_id(),
122 workspace_b.entity_id(),
123 "slot should now be project_b"
124 );
125 assert_ne!(
126 mw.workspaces()
127 .next()
128 .expect("workspace should exist")
129 .entity_id(),
130 workspace_a_id,
131 "project_a should be gone"
132 );
133 });
134
135 // Add project_c as a second workspace, then replace it with project_d.
136 let workspace_c = multi_workspace.update_in(cx, |mw, window, cx| {
137 mw.test_add_workspace(project_c.clone(), window, cx)
138 });
139
140 multi_workspace.read_with(cx, |mw, _cx| {
141 assert_eq!(mw.len(), 2);
142 assert_eq!(
143 mw.workspaces()
144 .position(|workspace| workspace == mw.active_workspace()),
145 Some(1)
146 );
147 });
148
149 let workspace_d = multi_workspace.update_in(cx, |mw, window, cx| {
150 let workspace = cx.new(|cx| Workspace::test_new(project_d.clone(), window, cx));
151 mw.replace(workspace.clone(), window, cx);
152 workspace
153 });
154
155 multi_workspace.read_with(cx, |mw, _cx| {
156 assert_eq!(mw.len(), 2, "should still have 2 workspaces");
157 assert_eq!(
158 mw.workspaces()
159 .position(|workspace| workspace == mw.active_workspace()),
160 Some(1)
161 );
162 assert_eq!(
163 mw.workspaces()
164 .nth(1)
165 .expect("no workspace at index 1")
166 .entity_id(),
167 workspace_d.entity_id(),
168 "active slot should now be project_d"
169 );
170 assert_ne!(
171 mw.workspaces()
172 .nth(1)
173 .expect("no workspace at index 1")
174 .entity_id(),
175 workspace_c.entity_id(),
176 "project_c should be gone"
177 );
178 });
179
180 // Replace with workspace_b which is already in the list — should just switch.
181 multi_workspace.update_in(cx, |mw, window, cx| {
182 mw.replace(workspace_b.clone(), window, cx);
183 });
184
185 multi_workspace.read_with(cx, |mw, _cx| {
186 assert_eq!(mw.len(), 2, "no workspace should be added or removed");
187 assert_eq!(
188 mw.workspaces()
189 .position(|workspace| workspace == mw.active_workspace()),
190 Some(0),
191 "should have switched to workspace_b"
192 );
193 });
194}