1use super::*;
2use client::{Client, UserStore};
3use clock::FakeSystemClock;
4use gpui::{App, AppContext as _, Entity, SemanticVersion};
5use http_client::FakeHttpClient;
6use rpc::proto::{self};
7use settings::SettingsStore;
8
9#[gpui::test]
10fn test_update_channels(cx: &mut App) {
11 let channel_store = init_test(cx);
12
13 update_channels(
14 &channel_store,
15 proto::UpdateChannels {
16 channels: vec![
17 proto::Channel {
18 id: 1,
19 name: "b".to_string(),
20 visibility: proto::ChannelVisibility::Members as i32,
21 parent_path: Vec::new(),
22 channel_order: 1,
23 },
24 proto::Channel {
25 id: 2,
26 name: "a".to_string(),
27 visibility: proto::ChannelVisibility::Members as i32,
28 parent_path: Vec::new(),
29 channel_order: 2,
30 },
31 ],
32 ..Default::default()
33 },
34 cx,
35 );
36 assert_channels(
37 &channel_store,
38 &[
39 //
40 (0, "b".to_string()),
41 (0, "a".to_string()),
42 ],
43 cx,
44 );
45
46 update_channels(
47 &channel_store,
48 proto::UpdateChannels {
49 channels: vec![
50 proto::Channel {
51 id: 3,
52 name: "x".to_string(),
53 visibility: proto::ChannelVisibility::Members as i32,
54 parent_path: vec![1],
55 channel_order: 1,
56 },
57 proto::Channel {
58 id: 4,
59 name: "y".to_string(),
60 visibility: proto::ChannelVisibility::Members as i32,
61 parent_path: vec![2],
62 channel_order: 1,
63 },
64 ],
65 ..Default::default()
66 },
67 cx,
68 );
69 assert_channels(
70 &channel_store,
71 &[
72 (0, "b".to_string()),
73 (1, "x".to_string()),
74 (0, "a".to_string()),
75 (1, "y".to_string()),
76 ],
77 cx,
78 );
79}
80
81#[gpui::test]
82fn test_update_channels_order_independent(cx: &mut App) {
83 /// Based on: https://stackoverflow.com/a/59939809
84 fn unique_permutations<T: Clone>(items: Vec<T>) -> Vec<Vec<T>> {
85 if items.len() == 1 {
86 vec![items]
87 } else {
88 let mut output: Vec<Vec<T>> = vec![];
89
90 for (ix, first) in items.iter().enumerate() {
91 let mut remaining_elements = items.clone();
92 remaining_elements.remove(ix);
93 for mut permutation in unique_permutations(remaining_elements) {
94 permutation.insert(0, first.clone());
95 output.push(permutation);
96 }
97 }
98 output
99 }
100 }
101
102 let test_data = vec![
103 proto::Channel {
104 id: 6,
105 name: "β".to_string(),
106 visibility: proto::ChannelVisibility::Members as i32,
107 parent_path: vec![1, 3],
108 channel_order: 1,
109 },
110 proto::Channel {
111 id: 5,
112 name: "α".to_string(),
113 visibility: proto::ChannelVisibility::Members as i32,
114 parent_path: vec![1],
115 channel_order: 2,
116 },
117 proto::Channel {
118 id: 3,
119 name: "x".to_string(),
120 visibility: proto::ChannelVisibility::Members as i32,
121 parent_path: vec![1],
122 channel_order: 1,
123 },
124 proto::Channel {
125 id: 4,
126 name: "y".to_string(),
127 visibility: proto::ChannelVisibility::Members as i32,
128 parent_path: vec![2],
129 channel_order: 1,
130 },
131 proto::Channel {
132 id: 1,
133 name: "b".to_string(),
134 visibility: proto::ChannelVisibility::Members as i32,
135 parent_path: Vec::new(),
136 channel_order: 1,
137 },
138 proto::Channel {
139 id: 2,
140 name: "a".to_string(),
141 visibility: proto::ChannelVisibility::Members as i32,
142 parent_path: Vec::new(),
143 channel_order: 2,
144 },
145 ];
146
147 let channel_store = init_test(cx);
148 let permutations = unique_permutations(test_data);
149
150 for test_instance in permutations {
151 channel_store.update(cx, |channel_store, _| channel_store.reset());
152
153 update_channels(
154 &channel_store,
155 proto::UpdateChannels {
156 channels: test_instance,
157 ..Default::default()
158 },
159 cx,
160 );
161
162 assert_channels(
163 &channel_store,
164 &[
165 (0, "b".to_string()),
166 (1, "x".to_string()),
167 (2, "β".to_string()),
168 (1, "α".to_string()),
169 (0, "a".to_string()),
170 (1, "y".to_string()),
171 ],
172 cx,
173 );
174 }
175}
176
177#[gpui::test]
178fn test_dangling_channel_paths(cx: &mut App) {
179 let channel_store = init_test(cx);
180
181 update_channels(
182 &channel_store,
183 proto::UpdateChannels {
184 channels: vec![
185 proto::Channel {
186 id: 0,
187 name: "a".to_string(),
188 visibility: proto::ChannelVisibility::Members as i32,
189 parent_path: vec![],
190 channel_order: 1,
191 },
192 proto::Channel {
193 id: 1,
194 name: "b".to_string(),
195 visibility: proto::ChannelVisibility::Members as i32,
196 parent_path: vec![0],
197 channel_order: 1,
198 },
199 proto::Channel {
200 id: 2,
201 name: "c".to_string(),
202 visibility: proto::ChannelVisibility::Members as i32,
203 parent_path: vec![0, 1],
204 channel_order: 1,
205 },
206 ],
207 ..Default::default()
208 },
209 cx,
210 );
211 // Sanity check
212 assert_channels(
213 &channel_store,
214 &[
215 //
216 (0, "a".to_string()),
217 (1, "b".to_string()),
218 (2, "c".to_string()),
219 ],
220 cx,
221 );
222
223 update_channels(
224 &channel_store,
225 proto::UpdateChannels {
226 delete_channels: vec![1, 2],
227 ..Default::default()
228 },
229 cx,
230 );
231
232 // Make sure that the 1/2/3 path is gone
233 assert_channels(&channel_store, &[(0, "a".to_string())], cx);
234}
235
236fn init_test(cx: &mut App) -> Entity<ChannelStore> {
237 let settings_store = SettingsStore::test(cx);
238 cx.set_global(settings_store);
239 release_channel::init(SemanticVersion::default(), cx);
240 client::init_settings(cx);
241
242 let clock = Arc::new(FakeSystemClock::new());
243 let http = FakeHttpClient::with_404_response();
244 let client = Client::new(clock, http, cx);
245 let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
246
247 client::init(&client, cx);
248 crate::init(&client, user_store, cx);
249
250 ChannelStore::global(cx)
251}
252
253fn update_channels(
254 channel_store: &Entity<ChannelStore>,
255 message: proto::UpdateChannels,
256 cx: &mut App,
257) {
258 let task = channel_store.update(cx, |store, cx| store.update_channels(message, cx));
259 assert!(task.is_none());
260}
261
262#[track_caller]
263fn assert_channels(
264 channel_store: &Entity<ChannelStore>,
265 expected_channels: &[(usize, String)],
266 cx: &mut App,
267) {
268 let actual = channel_store.update(cx, |store, _| {
269 store
270 .ordered_channels()
271 .map(|(depth, channel)| (depth, channel.name.to_string()))
272 .collect::<Vec<_>>()
273 });
274 assert_eq!(actual, expected_channels);
275}