channel_buffer_tests.rs

  1//todo(partially ported)
  2// use std::ops::Range;
  3
  4// use crate::{
  5//     rpc::{CLEANUP_TIMEOUT, RECONNECT_TIMEOUT},
  6//     tests::TestServer,
  7// };
  8// use client::{Collaborator, ParticipantIndex, UserId};
  9// use collections::HashMap;
 10// use editor::{Anchor, Editor, ToOffset};
 11// use futures::future;
 12// use gpui::{BackgroundExecutor, Model, TestAppContext, ViewContext};
 13// use rpc::{proto::PeerId, RECEIVE_TIMEOUT};
 14
 15// #[gpui::test]
 16// async fn test_core_channel_buffers(
 17//     executor: BackgroundExecutor,
 18//     cx_a: &mut TestAppContext,
 19//     cx_b: &mut TestAppContext,
 20// ) {
 21//     let mut server = TestServer::start(executor.clone()).await;
 22//     let client_a = server.create_client(cx_a, "user_a").await;
 23//     let client_b = server.create_client(cx_b, "user_b").await;
 24
 25//     let channel_id = server
 26//         .make_channel("zed", None, (&client_a, cx_a), &mut [(&client_b, cx_b)])
 27//         .await;
 28
 29//     // Client A joins the channel buffer
 30//     let channel_buffer_a = client_a
 31//         .channel_store()
 32//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
 33//         .await
 34//         .unwrap();
 35
 36//     // Client A edits the buffer
 37//     let buffer_a = channel_buffer_a.read_with(cx_a, |buffer, _| buffer.buffer());
 38//     buffer_a.update(cx_a, |buffer, cx| {
 39//         buffer.edit([(0..0, "hello world")], None, cx)
 40//     });
 41//     buffer_a.update(cx_a, |buffer, cx| {
 42//         buffer.edit([(5..5, ", cruel")], None, cx)
 43//     });
 44//     buffer_a.update(cx_a, |buffer, cx| {
 45//         buffer.edit([(0..5, "goodbye")], None, cx)
 46//     });
 47//     buffer_a.update(cx_a, |buffer, cx| buffer.undo(cx));
 48//     assert_eq!(buffer_text(&buffer_a, cx_a), "hello, cruel world");
 49//     executor.run_until_parked();
 50
 51//     // Client B joins the channel buffer
 52//     let channel_buffer_b = client_b
 53//         .channel_store()
 54//         .update(cx_b, |store, cx| store.open_channel_buffer(channel_id, cx))
 55//         .await
 56//         .unwrap();
 57//     channel_buffer_b.read_with(cx_b, |buffer, _| {
 58//         assert_collaborators(
 59//             buffer.collaborators(),
 60//             &[client_a.user_id(), client_b.user_id()],
 61//         );
 62//     });
 63
 64//     // Client B sees the correct text, and then edits it
 65//     let buffer_b = channel_buffer_b.read_with(cx_b, |buffer, _| buffer.buffer());
 66//     assert_eq!(
 67//         buffer_b.read_with(cx_b, |buffer, _| buffer.remote_id()),
 68//         buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id())
 69//     );
 70//     assert_eq!(buffer_text(&buffer_b, cx_b), "hello, cruel world");
 71//     buffer_b.update(cx_b, |buffer, cx| {
 72//         buffer.edit([(7..12, "beautiful")], None, cx)
 73//     });
 74
 75//     // Both A and B see the new edit
 76//     executor.run_until_parked();
 77//     assert_eq!(buffer_text(&buffer_a, cx_a), "hello, beautiful world");
 78//     assert_eq!(buffer_text(&buffer_b, cx_b), "hello, beautiful world");
 79
 80//     // Client A closes the channel buffer.
 81//     cx_a.update(|_| drop(channel_buffer_a));
 82//     executor.run_until_parked();
 83
 84//     // Client B sees that client A is gone from the channel buffer.
 85//     channel_buffer_b.read_with(cx_b, |buffer, _| {
 86//         assert_collaborators(&buffer.collaborators(), &[client_b.user_id()]);
 87//     });
 88
 89//     // Client A rejoins the channel buffer
 90//     let _channel_buffer_a = client_a
 91//         .channel_store()
 92//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
 93//         .await
 94//         .unwrap();
 95//     executor.run_until_parked();
 96
 97//     // Sanity test, make sure we saw A rejoining
 98//     channel_buffer_b.read_with(cx_b, |buffer, _| {
 99//         assert_collaborators(
100//             &buffer.collaborators(),
101//             &[client_a.user_id(), client_b.user_id()],
102//         );
103//     });
104
105//     // Client A loses connection.
106//     server.forbid_connections();
107//     server.disconnect_client(client_a.peer_id().unwrap());
108//     executor.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
109
110//     // Client B observes A disconnect
111//     channel_buffer_b.read_with(cx_b, |buffer, _| {
112//         assert_collaborators(&buffer.collaborators(), &[client_b.user_id()]);
113//     });
114
115//     // TODO:
116//     // - Test synchronizing offline updates, what happens to A's channel buffer when A disconnects
117//     // - Test interaction with channel deletion while buffer is open
118// }
119
120// // todo!("collab_ui")
121// // #[gpui::test]
122// // async fn test_channel_notes_participant_indices(
123// //     executor: BackgroundExecutor,
124// //     mut cx_a: &mut TestAppContext,
125// //     mut cx_b: &mut TestAppContext,
126// //     cx_c: &mut TestAppContext,
127// // ) {
128// //     let mut server = TestServer::start(&executor).await;
129// //     let client_a = server.create_client(cx_a, "user_a").await;
130// //     let client_b = server.create_client(cx_b, "user_b").await;
131// //     let client_c = server.create_client(cx_c, "user_c").await;
132
133// //     let active_call_a = cx_a.read(ActiveCall::global);
134// //     let active_call_b = cx_b.read(ActiveCall::global);
135
136// //     cx_a.update(editor::init);
137// //     cx_b.update(editor::init);
138// //     cx_c.update(editor::init);
139
140// //     let channel_id = server
141// //         .make_channel(
142// //             "the-channel",
143// //             None,
144// //             (&client_a, cx_a),
145// //             &mut [(&client_b, cx_b), (&client_c, cx_c)],
146// //         )
147// //         .await;
148
149// //     client_a
150// //         .fs()
151// //         .insert_tree("/root", json!({"file.txt": "123"}))
152// //         .await;
153// //     let (project_a, worktree_id_a) = client_a.build_local_project("/root", cx_a).await;
154// //     let project_b = client_b.build_empty_local_project(cx_b);
155// //     let project_c = client_c.build_empty_local_project(cx_c);
156// //     let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a);
157// //     let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
158// //     let workspace_c = client_c.build_workspace(&project_c, cx_c).root(cx_c);
159
160// //     // Clients A, B, and C open the channel notes
161// //     let channel_view_a = cx_a
162// //         .update(|cx| ChannelView::open(channel_id, workspace_a.clone(), cx))
163// //         .await
164// //         .unwrap();
165// //     let channel_view_b = cx_b
166// //         .update(|cx| ChannelView::open(channel_id, workspace_b.clone(), cx))
167// //         .await
168// //         .unwrap();
169// //     let channel_view_c = cx_c
170// //         .update(|cx| ChannelView::open(channel_id, workspace_c.clone(), cx))
171// //         .await
172// //         .unwrap();
173
174// //     // Clients A, B, and C all insert and select some text
175// //     channel_view_a.update(cx_a, |notes, cx| {
176// //         notes.editor.update(cx, |editor, cx| {
177// //             editor.insert("a", cx);
178// //             editor.change_selections(None, cx, |selections| {
179// //                 selections.select_ranges(vec![0..1]);
180// //             });
181// //         });
182// //     });
183// //     executor.run_until_parked();
184// //     channel_view_b.update(cx_b, |notes, cx| {
185// //         notes.editor.update(cx, |editor, cx| {
186// //             editor.move_down(&Default::default(), cx);
187// //             editor.insert("b", cx);
188// //             editor.change_selections(None, cx, |selections| {
189// //                 selections.select_ranges(vec![1..2]);
190// //             });
191// //         });
192// //     });
193// //     executor.run_until_parked();
194// //     channel_view_c.update(cx_c, |notes, cx| {
195// //         notes.editor.update(cx, |editor, cx| {
196// //             editor.move_down(&Default::default(), cx);
197// //             editor.insert("c", cx);
198// //             editor.change_selections(None, cx, |selections| {
199// //                 selections.select_ranges(vec![2..3]);
200// //             });
201// //         });
202// //     });
203
204// //     // Client A sees clients B and C without assigned colors, because they aren't
205// //     // in a call together.
206// //     executor.run_until_parked();
207// //     channel_view_a.update(cx_a, |notes, cx| {
208// //         notes.editor.update(cx, |editor, cx| {
209// //             assert_remote_selections(editor, &[(None, 1..2), (None, 2..3)], cx);
210// //         });
211// //     });
212
213// //     // Clients A and B join the same call.
214// //     for (call, cx) in [(&active_call_a, &mut cx_a), (&active_call_b, &mut cx_b)] {
215// //         call.update(*cx, |call, cx| call.join_channel(channel_id, cx))
216// //             .await
217// //             .unwrap();
218// //     }
219
220// //     // Clients A and B see each other with two different assigned colors. Client C
221// //     // still doesn't have a color.
222// //     executor.run_until_parked();
223// //     channel_view_a.update(cx_a, |notes, cx| {
224// //         notes.editor.update(cx, |editor, cx| {
225// //             assert_remote_selections(
226// //                 editor,
227// //                 &[(Some(ParticipantIndex(1)), 1..2), (None, 2..3)],
228// //                 cx,
229// //             );
230// //         });
231// //     });
232// //     channel_view_b.update(cx_b, |notes, cx| {
233// //         notes.editor.update(cx, |editor, cx| {
234// //             assert_remote_selections(
235// //                 editor,
236// //                 &[(Some(ParticipantIndex(0)), 0..1), (None, 2..3)],
237// //                 cx,
238// //             );
239// //         });
240// //     });
241
242// //     // Client A shares a project, and client B joins.
243// //     let project_id = active_call_a
244// //         .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
245// //         .await
246// //         .unwrap();
247// //     let project_b = client_b.build_remote_project(project_id, cx_b).await;
248// //     let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
249
250// //     // Clients A and B open the same file.
251// //     let editor_a = workspace_a
252// //         .update(cx_a, |workspace, cx| {
253// //             workspace.open_path((worktree_id_a, "file.txt"), None, true, cx)
254// //         })
255// //         .await
256// //         .unwrap()
257// //         .downcast::<Editor>()
258// //         .unwrap();
259// //     let editor_b = workspace_b
260// //         .update(cx_b, |workspace, cx| {
261// //             workspace.open_path((worktree_id_a, "file.txt"), None, true, cx)
262// //         })
263// //         .await
264// //         .unwrap()
265// //         .downcast::<Editor>()
266// //         .unwrap();
267
268// //     editor_a.update(cx_a, |editor, cx| {
269// //         editor.change_selections(None, cx, |selections| {
270// //             selections.select_ranges(vec![0..1]);
271// //         });
272// //     });
273// //     editor_b.update(cx_b, |editor, cx| {
274// //         editor.change_selections(None, cx, |selections| {
275// //             selections.select_ranges(vec![2..3]);
276// //         });
277// //     });
278// //     executor.run_until_parked();
279
280// //     // Clients A and B see each other with the same colors as in the channel notes.
281// //     editor_a.update(cx_a, |editor, cx| {
282// //         assert_remote_selections(editor, &[(Some(ParticipantIndex(1)), 2..3)], cx);
283// //     });
284// //     editor_b.update(cx_b, |editor, cx| {
285// //         assert_remote_selections(editor, &[(Some(ParticipantIndex(0)), 0..1)], cx);
286// //     });
287// // }
288
289// #[track_caller]
290// fn assert_remote_selections(
291//     editor: &mut Editor,
292//     expected_selections: &[(Option<ParticipantIndex>, Range<usize>)],
293//     cx: &mut ViewContext<Editor>,
294// ) {
295//     let snapshot = editor.snapshot(cx);
296//     let range = Anchor::min()..Anchor::max();
297//     let remote_selections = snapshot
298//         .remote_selections_in_range(&range, editor.collaboration_hub().unwrap(), cx)
299//         .map(|s| {
300//             let start = s.selection.start.to_offset(&snapshot.buffer_snapshot);
301//             let end = s.selection.end.to_offset(&snapshot.buffer_snapshot);
302//             (s.participant_index, start..end)
303//         })
304//         .collect::<Vec<_>>();
305//     assert_eq!(
306//         remote_selections, expected_selections,
307//         "incorrect remote selections"
308//     );
309// }
310
311// #[gpui::test]
312// async fn test_multiple_handles_to_channel_buffer(
313//     deterministic: BackgroundExecutor,
314//     cx_a: &mut TestAppContext,
315// ) {
316//     let mut server = TestServer::start(deterministic.clone()).await;
317//     let client_a = server.create_client(cx_a, "user_a").await;
318
319//     let channel_id = server
320//         .make_channel("the-channel", None, (&client_a, cx_a), &mut [])
321//         .await;
322
323//     let channel_buffer_1 = client_a
324//         .channel_store()
325//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx));
326//     let channel_buffer_2 = client_a
327//         .channel_store()
328//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx));
329//     let channel_buffer_3 = client_a
330//         .channel_store()
331//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx));
332
333//     // All concurrent tasks for opening a channel buffer return the same model handle.
334//     let (channel_buffer, channel_buffer_2, channel_buffer_3) =
335//         future::try_join3(channel_buffer_1, channel_buffer_2, channel_buffer_3)
336//             .await
337//             .unwrap();
338//     let channel_buffer_model_id = channel_buffer.entity_id();
339//     assert_eq!(channel_buffer, channel_buffer_2);
340//     assert_eq!(channel_buffer, channel_buffer_3);
341
342//     channel_buffer.update(cx_a, |buffer, cx| {
343//         buffer.buffer().update(cx, |buffer, cx| {
344//             buffer.edit([(0..0, "hello")], None, cx);
345//         })
346//     });
347//     deterministic.run_until_parked();
348
349//     cx_a.update(|_| {
350//         drop(channel_buffer);
351//         drop(channel_buffer_2);
352//         drop(channel_buffer_3);
353//     });
354//     deterministic.run_until_parked();
355
356//     // The channel buffer can be reopened after dropping it.
357//     let channel_buffer = client_a
358//         .channel_store()
359//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
360//         .await
361//         .unwrap();
362//     assert_ne!(channel_buffer.entity_id(), channel_buffer_model_id);
363//     channel_buffer.update(cx_a, |buffer, cx| {
364//         buffer.buffer().update(cx, |buffer, _| {
365//             assert_eq!(buffer.text(), "hello");
366//         })
367//     });
368// }
369
370// #[gpui::test]
371// async fn test_channel_buffer_disconnect(
372//     deterministic: BackgroundExecutor,
373//     cx_a: &mut TestAppContext,
374//     cx_b: &mut TestAppContext,
375// ) {
376//     let mut server = TestServer::start(deterministic.clone()).await;
377//     let client_a = server.create_client(cx_a, "user_a").await;
378//     let client_b = server.create_client(cx_b, "user_b").await;
379
380//     let channel_id = server
381//         .make_channel(
382//             "the-channel",
383//             None,
384//             (&client_a, cx_a),
385//             &mut [(&client_b, cx_b)],
386//         )
387//         .await;
388
389//     let channel_buffer_a = client_a
390//         .channel_store()
391//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
392//         .await
393//         .unwrap();
394
395//     let channel_buffer_b = client_b
396//         .channel_store()
397//         .update(cx_b, |store, cx| store.open_channel_buffer(channel_id, cx))
398//         .await
399//         .unwrap();
400
401//     server.forbid_connections();
402//     server.disconnect_client(client_a.peer_id().unwrap());
403//     deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
404
405//     channel_buffer_a.update(cx_a, |buffer, cx| {
406//         assert_eq!(buffer.channel(cx).unwrap().name, "the-channel");
407//         assert!(!buffer.is_connected());
408//     });
409
410//     deterministic.run_until_parked();
411
412//     server.allow_connections();
413//     deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
414
415//     deterministic.run_until_parked();
416
417//     client_a
418//         .channel_store()
419//         .update(cx_a, |channel_store, _| {
420//             channel_store.remove_channel(channel_id)
421//         })
422//         .await
423//         .unwrap();
424//     deterministic.run_until_parked();
425
426//     // Channel buffer observed the deletion
427//     channel_buffer_b.update(cx_b, |buffer, cx| {
428//         assert!(buffer.channel(cx).is_none());
429//         assert!(!buffer.is_connected());
430//     });
431// }
432
433// #[gpui::test]
434// async fn test_rejoin_channel_buffer(
435//     deterministic: BackgroundExecutor,
436//     cx_a: &mut TestAppContext,
437//     cx_b: &mut TestAppContext,
438// ) {
439//     let mut server = TestServer::start(deterministic.clone()).await;
440//     let client_a = server.create_client(cx_a, "user_a").await;
441//     let client_b = server.create_client(cx_b, "user_b").await;
442
443//     let channel_id = server
444//         .make_channel(
445//             "the-channel",
446//             None,
447//             (&client_a, cx_a),
448//             &mut [(&client_b, cx_b)],
449//         )
450//         .await;
451
452//     let channel_buffer_a = client_a
453//         .channel_store()
454//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
455//         .await
456//         .unwrap();
457//     let channel_buffer_b = client_b
458//         .channel_store()
459//         .update(cx_b, |store, cx| store.open_channel_buffer(channel_id, cx))
460//         .await
461//         .unwrap();
462
463//     channel_buffer_a.update(cx_a, |buffer, cx| {
464//         buffer.buffer().update(cx, |buffer, cx| {
465//             buffer.edit([(0..0, "1")], None, cx);
466//         })
467//     });
468//     deterministic.run_until_parked();
469
470//     // Client A disconnects.
471//     server.forbid_connections();
472//     server.disconnect_client(client_a.peer_id().unwrap());
473
474//     // Both clients make an edit.
475//     channel_buffer_a.update(cx_a, |buffer, cx| {
476//         buffer.buffer().update(cx, |buffer, cx| {
477//             buffer.edit([(1..1, "2")], None, cx);
478//         })
479//     });
480//     channel_buffer_b.update(cx_b, |buffer, cx| {
481//         buffer.buffer().update(cx, |buffer, cx| {
482//             buffer.edit([(0..0, "0")], None, cx);
483//         })
484//     });
485
486//     // Both clients see their own edit.
487//     deterministic.run_until_parked();
488//     channel_buffer_a.read_with(cx_a, |buffer, cx| {
489//         assert_eq!(buffer.buffer().read(cx).text(), "12");
490//     });
491//     channel_buffer_b.read_with(cx_b, |buffer, cx| {
492//         assert_eq!(buffer.buffer().read(cx).text(), "01");
493//     });
494
495//     // Client A reconnects. Both clients see each other's edits, and see
496//     // the same collaborators.
497//     server.allow_connections();
498//     deterministic.advance_clock(RECEIVE_TIMEOUT);
499//     channel_buffer_a.read_with(cx_a, |buffer, cx| {
500//         assert_eq!(buffer.buffer().read(cx).text(), "012");
501//     });
502//     channel_buffer_b.read_with(cx_b, |buffer, cx| {
503//         assert_eq!(buffer.buffer().read(cx).text(), "012");
504//     });
505
506//     channel_buffer_a.read_with(cx_a, |buffer_a, _| {
507//         channel_buffer_b.read_with(cx_b, |buffer_b, _| {
508//             assert_eq!(buffer_a.collaborators(), buffer_b.collaborators());
509//         });
510//     });
511// }
512
513// #[gpui::test]
514// async fn test_channel_buffers_and_server_restarts(
515//     deterministic: BackgroundExecutor,
516//     cx_a: &mut TestAppContext,
517//     cx_b: &mut TestAppContext,
518//     cx_c: &mut TestAppContext,
519// ) {
520//     let mut server = TestServer::start(deterministic.clone()).await;
521//     let client_a = server.create_client(cx_a, "user_a").await;
522//     let client_b = server.create_client(cx_b, "user_b").await;
523//     let client_c = server.create_client(cx_c, "user_c").await;
524
525//     let channel_id = server
526//         .make_channel(
527//             "the-channel",
528//             None,
529//             (&client_a, cx_a),
530//             &mut [(&client_b, cx_b), (&client_c, cx_c)],
531//         )
532//         .await;
533
534//     let channel_buffer_a = client_a
535//         .channel_store()
536//         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
537//         .await
538//         .unwrap();
539//     let channel_buffer_b = client_b
540//         .channel_store()
541//         .update(cx_b, |store, cx| store.open_channel_buffer(channel_id, cx))
542//         .await
543//         .unwrap();
544//     let _channel_buffer_c = client_c
545//         .channel_store()
546//         .update(cx_c, |store, cx| store.open_channel_buffer(channel_id, cx))
547//         .await
548//         .unwrap();
549
550//     channel_buffer_a.update(cx_a, |buffer, cx| {
551//         buffer.buffer().update(cx, |buffer, cx| {
552//             buffer.edit([(0..0, "1")], None, cx);
553//         })
554//     });
555//     deterministic.run_until_parked();
556
557//     // Client C can't reconnect.
558//     client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
559
560//     // Server stops.
561//     server.reset().await;
562//     deterministic.advance_clock(RECEIVE_TIMEOUT);
563
564//     // While the server is down, both clients make an edit.
565//     channel_buffer_a.update(cx_a, |buffer, cx| {
566//         buffer.buffer().update(cx, |buffer, cx| {
567//             buffer.edit([(1..1, "2")], None, cx);
568//         })
569//     });
570//     channel_buffer_b.update(cx_b, |buffer, cx| {
571//         buffer.buffer().update(cx, |buffer, cx| {
572//             buffer.edit([(0..0, "0")], None, cx);
573//         })
574//     });
575
576//     // Server restarts.
577//     server.start().await.unwrap();
578//     deterministic.advance_clock(CLEANUP_TIMEOUT);
579
580//     // Clients reconnects. Clients A and B see each other's edits, and see
581//     // that client C has disconnected.
582//     channel_buffer_a.read_with(cx_a, |buffer, cx| {
583//         assert_eq!(buffer.buffer().read(cx).text(), "012");
584//     });
585//     channel_buffer_b.read_with(cx_b, |buffer, cx| {
586//         assert_eq!(buffer.buffer().read(cx).text(), "012");
587//     });
588
589//     channel_buffer_a.read_with(cx_a, |buffer_a, _| {
590//         channel_buffer_b.read_with(cx_b, |buffer_b, _| {
591//             assert_collaborators(
592//                 buffer_a.collaborators(),
593//                 &[client_a.user_id(), client_b.user_id()],
594//             );
595//             assert_eq!(buffer_a.collaborators(), buffer_b.collaborators());
596//         });
597//     });
598// }
599
600// //todo!(collab_ui)
601// // #[gpui::test(iterations = 10)]
602// // async fn test_following_to_channel_notes_without_a_shared_project(
603// //     deterministic: BackgroundExecutor,
604// //     mut cx_a: &mut TestAppContext,
605// //     mut cx_b: &mut TestAppContext,
606// //     mut cx_c: &mut TestAppContext,
607// // ) {
608// //     let mut server = TestServer::start(&deterministic).await;
609// //     let client_a = server.create_client(cx_a, "user_a").await;
610// //     let client_b = server.create_client(cx_b, "user_b").await;
611
612// //     let client_c = server.create_client(cx_c, "user_c").await;
613
614// //     cx_a.update(editor::init);
615// //     cx_b.update(editor::init);
616// //     cx_c.update(editor::init);
617// //     cx_a.update(collab_ui::channel_view::init);
618// //     cx_b.update(collab_ui::channel_view::init);
619// //     cx_c.update(collab_ui::channel_view::init);
620
621// //     let channel_1_id = server
622// //         .make_channel(
623// //             "channel-1",
624// //             None,
625// //             (&client_a, cx_a),
626// //             &mut [(&client_b, cx_b), (&client_c, cx_c)],
627// //         )
628// //         .await;
629// //     let channel_2_id = server
630// //         .make_channel(
631// //             "channel-2",
632// //             None,
633// //             (&client_a, cx_a),
634// //             &mut [(&client_b, cx_b), (&client_c, cx_c)],
635// //         )
636// //         .await;
637
638// //     // Clients A, B, and C join a channel.
639// //     let active_call_a = cx_a.read(ActiveCall::global);
640// //     let active_call_b = cx_b.read(ActiveCall::global);
641// //     let active_call_c = cx_c.read(ActiveCall::global);
642// //     for (call, cx) in [
643// //         (&active_call_a, &mut cx_a),
644// //         (&active_call_b, &mut cx_b),
645// //         (&active_call_c, &mut cx_c),
646// //     ] {
647// //         call.update(*cx, |call, cx| call.join_channel(channel_1_id, cx))
648// //             .await
649// //             .unwrap();
650// //     }
651// //     deterministic.run_until_parked();
652
653// //     // Clients A, B, and C all open their own unshared projects.
654// //     client_a.fs().insert_tree("/a", json!({})).await;
655// //     client_b.fs().insert_tree("/b", json!({})).await;
656// //     client_c.fs().insert_tree("/c", json!({})).await;
657// //     let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
658// //     let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
659// //     let (project_c, _) = client_b.build_local_project("/c", cx_c).await;
660// //     let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a);
661// //     let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
662// //     let _workspace_c = client_c.build_workspace(&project_c, cx_c).root(cx_c);
663
664// //     active_call_a
665// //         .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
666// //         .await
667// //         .unwrap();
668
669// //     // Client A opens the notes for channel 1.
670// //     let channel_view_1_a = cx_a
671// //         .update(|cx| ChannelView::open(channel_1_id, workspace_a.clone(), cx))
672// //         .await
673// //         .unwrap();
674// //     channel_view_1_a.update(cx_a, |notes, cx| {
675// //         assert_eq!(notes.channel(cx).unwrap().name, "channel-1");
676// //         notes.editor.update(cx, |editor, cx| {
677// //             editor.insert("Hello from A.", cx);
678// //             editor.change_selections(None, cx, |selections| {
679// //                 selections.select_ranges(vec![3..4]);
680// //             });
681// //         });
682// //     });
683
684// //     // Client B follows client A.
685// //     workspace_b
686// //         .update(cx_b, |workspace, cx| {
687// //             workspace.follow(client_a.peer_id().unwrap(), cx).unwrap()
688// //         })
689// //         .await
690// //         .unwrap();
691
692// //     // Client B is taken to the notes for channel 1, with the same
693// //     // text selected as client A.
694// //     deterministic.run_until_parked();
695// //     let channel_view_1_b = workspace_b.read_with(cx_b, |workspace, cx| {
696// //         assert_eq!(
697// //             workspace.leader_for_pane(workspace.active_pane()),
698// //             Some(client_a.peer_id().unwrap())
699// //         );
700// //         workspace
701// //             .active_item(cx)
702// //             .expect("no active item")
703// //             .downcast::<ChannelView>()
704// //             .expect("active item is not a channel view")
705// //     });
706// //     channel_view_1_b.read_with(cx_b, |notes, cx| {
707// //         assert_eq!(notes.channel(cx).unwrap().name, "channel-1");
708// //         let editor = notes.editor.read(cx);
709// //         assert_eq!(editor.text(cx), "Hello from A.");
710// //         assert_eq!(editor.selections.ranges::<usize>(cx), &[3..4]);
711// //     });
712
713// //     // Client A opens the notes for channel 2.
714// //     let channel_view_2_a = cx_a
715// //         .update(|cx| ChannelView::open(channel_2_id, workspace_a.clone(), cx))
716// //         .await
717// //         .unwrap();
718// //     channel_view_2_a.read_with(cx_a, |notes, cx| {
719// //         assert_eq!(notes.channel(cx).unwrap().name, "channel-2");
720// //     });
721
722// //     // Client B is taken to the notes for channel 2.
723// //     deterministic.run_until_parked();
724// //     let channel_view_2_b = workspace_b.read_with(cx_b, |workspace, cx| {
725// //         assert_eq!(
726// //             workspace.leader_for_pane(workspace.active_pane()),
727// //             Some(client_a.peer_id().unwrap())
728// //         );
729// //         workspace
730// //             .active_item(cx)
731// //             .expect("no active item")
732// //             .downcast::<ChannelView>()
733// //             .expect("active item is not a channel view")
734// //     });
735// //     channel_view_2_b.read_with(cx_b, |notes, cx| {
736// //         assert_eq!(notes.channel(cx).unwrap().name, "channel-2");
737// //     });
738// // }
739
740// //todo!(collab_ui)
741// // #[gpui::test]
742// // async fn test_channel_buffer_changes(
743// //     deterministic: BackgroundExecutor,
744// //     cx_a: &mut TestAppContext,
745// //     cx_b: &mut TestAppContext,
746// // ) {
747// //     let mut server = TestServer::start(&deterministic).await;
748// //     let client_a = server.create_client(cx_a, "user_a").await;
749// //     let client_b = server.create_client(cx_b, "user_b").await;
750
751// //     let channel_id = server
752// //         .make_channel(
753// //             "the-channel",
754// //             None,
755// //             (&client_a, cx_a),
756// //             &mut [(&client_b, cx_b)],
757// //         )
758// //         .await;
759
760// //     let channel_buffer_a = client_a
761// //         .channel_store()
762// //         .update(cx_a, |store, cx| store.open_channel_buffer(channel_id, cx))
763// //         .await
764// //         .unwrap();
765
766// //     // Client A makes an edit, and client B should see that the note has changed.
767// //     channel_buffer_a.update(cx_a, |buffer, cx| {
768// //         buffer.buffer().update(cx, |buffer, cx| {
769// //             buffer.edit([(0..0, "1")], None, cx);
770// //         })
771// //     });
772// //     deterministic.run_until_parked();
773
774// //     let has_buffer_changed = cx_b.update(|cx| {
775// //         client_b
776// //             .channel_store()
777// //             .read(cx)
778// //             .has_channel_buffer_changed(channel_id)
779// //             .unwrap()
780// //     });
781// //     assert!(has_buffer_changed);
782
783// //     // Opening the buffer should clear the changed flag.
784// //     let project_b = client_b.build_empty_local_project(cx_b);
785// //     let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
786// //     let channel_view_b = cx_b
787// //         .update(|cx| ChannelView::open(channel_id, workspace_b.clone(), cx))
788// //         .await
789// //         .unwrap();
790// //     deterministic.run_until_parked();
791
792// //     let has_buffer_changed = cx_b.update(|cx| {
793// //         client_b
794// //             .channel_store()
795// //             .read(cx)
796// //             .has_channel_buffer_changed(channel_id)
797// //             .unwrap()
798// //     });
799// //     assert!(!has_buffer_changed);
800
801// //     // Editing the channel while the buffer is open should not show that the buffer has changed.
802// //     channel_buffer_a.update(cx_a, |buffer, cx| {
803// //         buffer.buffer().update(cx, |buffer, cx| {
804// //             buffer.edit([(0..0, "2")], None, cx);
805// //         })
806// //     });
807// //     deterministic.run_until_parked();
808
809// //     let has_buffer_changed = cx_b.read(|cx| {
810// //         client_b
811// //             .channel_store()
812// //             .read(cx)
813// //             .has_channel_buffer_changed(channel_id)
814// //             .unwrap()
815// //     });
816// //     assert!(!has_buffer_changed);
817
818// //     deterministic.advance_clock(ACKNOWLEDGE_DEBOUNCE_INTERVAL);
819
820// //     // Test that the server is tracking things correctly, and we retain our 'not changed'
821// //     // state across a disconnect
822// //     server.simulate_long_connection_interruption(client_b.peer_id().unwrap(), &deterministic);
823// //     let has_buffer_changed = cx_b.read(|cx| {
824// //         client_b
825// //             .channel_store()
826// //             .read(cx)
827// //             .has_channel_buffer_changed(channel_id)
828// //             .unwrap()
829// //     });
830// //     assert!(!has_buffer_changed);
831
832// //     // Closing the buffer should re-enable change tracking
833// //     cx_b.update(|cx| {
834// //         workspace_b.update(cx, |workspace, cx| {
835// //             workspace.close_all_items_and_panes(&Default::default(), cx)
836// //         });
837
838// //         drop(channel_view_b)
839// //     });
840
841// //     deterministic.run_until_parked();
842
843// //     channel_buffer_a.update(cx_a, |buffer, cx| {
844// //         buffer.buffer().update(cx, |buffer, cx| {
845// //             buffer.edit([(0..0, "3")], None, cx);
846// //         })
847// //     });
848// //     deterministic.run_until_parked();
849
850// //     let has_buffer_changed = cx_b.read(|cx| {
851// //         client_b
852// //             .channel_store()
853// //             .read(cx)
854// //             .has_channel_buffer_changed(channel_id)
855// //             .unwrap()
856// //     });
857// //     assert!(has_buffer_changed);
858// // }
859
860// #[track_caller]
861// fn assert_collaborators(collaborators: &HashMap<PeerId, Collaborator>, ids: &[Option<UserId>]) {
862//     let mut user_ids = collaborators
863//         .values()
864//         .map(|collaborator| collaborator.user_id)
865//         .collect::<Vec<_>>();
866//     user_ids.sort();
867//     assert_eq!(
868//         user_ids,
869//         ids.into_iter().map(|id| id.unwrap()).collect::<Vec<_>>()
870//     );
871// }
872
873// fn buffer_text(channel_buffer: &Model<language::Buffer>, cx: &mut TestAppContext) -> String {
874//     channel_buffer.read_with(cx, |buffer, _| buffer.text())
875// }