use super::*; use client::{Client, UserStore}; use clock::FakeSystemClock; use gpui::{App, AppContext as _, Entity}; use http_client::FakeHttpClient; use rpc::proto::{self}; use settings::SettingsStore; #[gpui::test] fn test_update_channels(cx: &mut App) { let channel_store = init_test(cx); update_channels( &channel_store, proto::UpdateChannels { channels: vec![ proto::Channel { id: 1, name: "b".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: Vec::new(), channel_order: 1, }, proto::Channel { id: 2, name: "a".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: Vec::new(), channel_order: 2, }, ], ..Default::default() }, cx, ); assert_channels( &channel_store, &[ // (0, "b".to_string()), (0, "a".to_string()), ], cx, ); update_channels( &channel_store, proto::UpdateChannels { channels: vec![ proto::Channel { id: 3, name: "x".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![1], channel_order: 1, }, proto::Channel { id: 4, name: "y".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![2], channel_order: 1, }, ], ..Default::default() }, cx, ); assert_channels( &channel_store, &[ (0, "b".to_string()), (1, "x".to_string()), (0, "a".to_string()), (1, "y".to_string()), ], cx, ); } #[gpui::test] fn test_update_channels_order_independent(cx: &mut App) { /// Based on: https://stackoverflow.com/a/59939809 fn unique_permutations(items: Vec) -> Vec> { if items.len() == 1 { vec![items] } else { let mut output: Vec> = vec![]; for (ix, first) in items.iter().enumerate() { let mut remaining_elements = items.clone(); remaining_elements.remove(ix); for mut permutation in unique_permutations(remaining_elements) { permutation.insert(0, first.clone()); output.push(permutation); } } output } } let test_data = vec![ proto::Channel { id: 6, name: "β".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![1, 3], channel_order: 1, }, proto::Channel { id: 5, name: "α".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![1], channel_order: 2, }, proto::Channel { id: 3, name: "x".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![1], channel_order: 1, }, proto::Channel { id: 4, name: "y".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![2], channel_order: 1, }, proto::Channel { id: 1, name: "b".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: Vec::new(), channel_order: 1, }, proto::Channel { id: 2, name: "a".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: Vec::new(), channel_order: 2, }, ]; let channel_store = init_test(cx); let permutations = unique_permutations(test_data); for test_instance in permutations { channel_store.update(cx, |channel_store, _| channel_store.reset()); update_channels( &channel_store, proto::UpdateChannels { channels: test_instance, ..Default::default() }, cx, ); assert_channels( &channel_store, &[ (0, "b".to_string()), (1, "x".to_string()), (2, "β".to_string()), (1, "α".to_string()), (0, "a".to_string()), (1, "y".to_string()), ], cx, ); } } #[gpui::test] fn test_dangling_channel_paths(cx: &mut App) { let channel_store = init_test(cx); update_channels( &channel_store, proto::UpdateChannels { channels: vec![ proto::Channel { id: 0, name: "a".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![], channel_order: 1, }, proto::Channel { id: 1, name: "b".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![0], channel_order: 1, }, proto::Channel { id: 2, name: "c".to_string(), visibility: proto::ChannelVisibility::Members as i32, parent_path: vec![0, 1], channel_order: 1, }, ], ..Default::default() }, cx, ); // Sanity check assert_channels( &channel_store, &[ // (0, "a".to_string()), (1, "b".to_string()), (2, "c".to_string()), ], cx, ); update_channels( &channel_store, proto::UpdateChannels { delete_channels: vec![1, 2], ..Default::default() }, cx, ); // Make sure that the 1/2/3 path is gone assert_channels(&channel_store, &[(0, "a".to_string())], cx); } fn init_test(cx: &mut App) -> Entity { let settings_store = SettingsStore::test(cx); cx.set_global(settings_store); release_channel::init(semver::Version::new(0, 0, 0), cx); let clock = Arc::new(FakeSystemClock::new()); let http = FakeHttpClient::with_404_response(); let client = Client::new(clock, http, cx); let user_store = cx.new(|cx| UserStore::new(client.clone(), cx)); client::init(&client, cx); crate::init(&client, user_store, cx); ChannelStore::global(cx) } fn update_channels( channel_store: &Entity, message: proto::UpdateChannels, cx: &mut App, ) { let task = channel_store.update(cx, |store, cx| store.update_channels(message, cx)); assert!(task.is_none()); } #[track_caller] fn assert_channels( channel_store: &Entity, expected_channels: &[(usize, String)], cx: &mut App, ) { let actual = channel_store.update(cx, |store, _| { store .ordered_channels() .map(|(depth, channel)| (depth, channel.name.to_string())) .collect::>() }); assert_eq!(actual, expected_channels); }