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// }