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}