integration_tests.rs

   1use crate::{
   2    rpc::{CLEANUP_TIMEOUT, RECONNECT_TIMEOUT},
   3    tests::{TestClient, TestServer},
   4};
   5use call::{room, ActiveCall, ParticipantLocation, Room};
   6use client::{User, RECEIVE_TIMEOUT};
   7use collections::HashSet;
   8use editor::{
   9    test::editor_test_context::EditorTestContext, ConfirmCodeAction, ConfirmCompletion,
  10    ConfirmRename, Editor, ExcerptRange, MultiBuffer, Redo, Rename, ToOffset, ToggleCodeActions,
  11    Undo,
  12};
  13use fs::{repository::GitFileStatus, FakeFs, Fs as _, LineEnding, RemoveOptions};
  14use futures::StreamExt as _;
  15use gpui::{
  16    executor::Deterministic, geometry::vector::vec2f, test::EmptyView, AppContext, ModelHandle,
  17    TestAppContext, ViewHandle,
  18};
  19use indoc::indoc;
  20use language::{
  21    language_settings::{AllLanguageSettings, Formatter},
  22    tree_sitter_rust, Anchor, Diagnostic, DiagnosticEntry, FakeLspAdapter, Language,
  23    LanguageConfig, OffsetRangeExt, Point, Rope,
  24};
  25use live_kit_client::MacOSDisplay;
  26use lsp::LanguageServerId;
  27use project::{search::SearchQuery, DiagnosticSummary, HoverBlockKind, Project, ProjectPath};
  28use rand::prelude::*;
  29use serde_json::json;
  30use settings::SettingsStore;
  31use std::{
  32    cell::{Cell, RefCell},
  33    env, future, mem,
  34    path::{Path, PathBuf},
  35    rc::Rc,
  36    sync::{
  37        atomic::{AtomicBool, Ordering::SeqCst},
  38        Arc,
  39    },
  40};
  41use unindent::Unindent as _;
  42use workspace::{item::ItemHandle as _, shared_screen::SharedScreen, SplitDirection, Workspace};
  43
  44#[ctor::ctor]
  45fn init_logger() {
  46    if std::env::var("RUST_LOG").is_ok() {
  47        env_logger::init();
  48    }
  49}
  50
  51#[gpui::test(iterations = 10)]
  52async fn test_basic_calls(
  53    deterministic: Arc<Deterministic>,
  54    cx_a: &mut TestAppContext,
  55    cx_b: &mut TestAppContext,
  56    cx_b2: &mut TestAppContext,
  57    cx_c: &mut TestAppContext,
  58) {
  59    deterministic.forbid_parking();
  60    let mut server = TestServer::start(&deterministic).await;
  61
  62    let client_a = server.create_client(cx_a, "user_a").await;
  63    let client_b = server.create_client(cx_b, "user_b").await;
  64    let client_c = server.create_client(cx_c, "user_c").await;
  65    server
  66        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
  67        .await;
  68
  69    let active_call_a = cx_a.read(ActiveCall::global);
  70    let active_call_b = cx_b.read(ActiveCall::global);
  71    let active_call_c = cx_c.read(ActiveCall::global);
  72
  73    // Call user B from client A.
  74    active_call_a
  75        .update(cx_a, |call, cx| {
  76            call.invite(client_b.user_id().unwrap(), None, cx)
  77        })
  78        .await
  79        .unwrap();
  80    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
  81    deterministic.run_until_parked();
  82    assert_eq!(
  83        room_participants(&room_a, cx_a),
  84        RoomParticipants {
  85            remote: Default::default(),
  86            pending: vec!["user_b".to_string()]
  87        }
  88    );
  89
  90    // User B receives the call.
  91    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
  92    let call_b = incoming_call_b.next().await.unwrap().unwrap();
  93    assert_eq!(call_b.calling_user.github_login, "user_a");
  94
  95    // User B connects via another client and also receives a ring on the newly-connected client.
  96    let _client_b2 = server.create_client(cx_b2, "user_b").await;
  97    let active_call_b2 = cx_b2.read(ActiveCall::global);
  98    let mut incoming_call_b2 = active_call_b2.read_with(cx_b2, |call, _| call.incoming());
  99    deterministic.run_until_parked();
 100    let call_b2 = incoming_call_b2.next().await.unwrap().unwrap();
 101    assert_eq!(call_b2.calling_user.github_login, "user_a");
 102
 103    // User B joins the room using the first client.
 104    active_call_b
 105        .update(cx_b, |call, cx| call.accept_incoming(cx))
 106        .await
 107        .unwrap();
 108    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 109    assert!(incoming_call_b.next().await.unwrap().is_none());
 110
 111    deterministic.run_until_parked();
 112    assert_eq!(
 113        room_participants(&room_a, cx_a),
 114        RoomParticipants {
 115            remote: vec!["user_b".to_string()],
 116            pending: Default::default()
 117        }
 118    );
 119    assert_eq!(
 120        room_participants(&room_b, cx_b),
 121        RoomParticipants {
 122            remote: vec!["user_a".to_string()],
 123            pending: Default::default()
 124        }
 125    );
 126
 127    // Call user C from client B.
 128    let mut incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
 129    active_call_b
 130        .update(cx_b, |call, cx| {
 131            call.invite(client_c.user_id().unwrap(), None, cx)
 132        })
 133        .await
 134        .unwrap();
 135
 136    deterministic.run_until_parked();
 137    assert_eq!(
 138        room_participants(&room_a, cx_a),
 139        RoomParticipants {
 140            remote: vec!["user_b".to_string()],
 141            pending: vec!["user_c".to_string()]
 142        }
 143    );
 144    assert_eq!(
 145        room_participants(&room_b, cx_b),
 146        RoomParticipants {
 147            remote: vec!["user_a".to_string()],
 148            pending: vec!["user_c".to_string()]
 149        }
 150    );
 151
 152    // User C receives the call, but declines it.
 153    let call_c = incoming_call_c.next().await.unwrap().unwrap();
 154    assert_eq!(call_c.calling_user.github_login, "user_b");
 155    active_call_c.update(cx_c, |call, _| call.decline_incoming().unwrap());
 156    assert!(incoming_call_c.next().await.unwrap().is_none());
 157
 158    deterministic.run_until_parked();
 159    assert_eq!(
 160        room_participants(&room_a, cx_a),
 161        RoomParticipants {
 162            remote: vec!["user_b".to_string()],
 163            pending: Default::default()
 164        }
 165    );
 166    assert_eq!(
 167        room_participants(&room_b, cx_b),
 168        RoomParticipants {
 169            remote: vec!["user_a".to_string()],
 170            pending: Default::default()
 171        }
 172    );
 173
 174    // Call user C again from user A.
 175    active_call_a
 176        .update(cx_a, |call, cx| {
 177            call.invite(client_c.user_id().unwrap(), None, cx)
 178        })
 179        .await
 180        .unwrap();
 181
 182    deterministic.run_until_parked();
 183    assert_eq!(
 184        room_participants(&room_a, cx_a),
 185        RoomParticipants {
 186            remote: vec!["user_b".to_string()],
 187            pending: vec!["user_c".to_string()]
 188        }
 189    );
 190    assert_eq!(
 191        room_participants(&room_b, cx_b),
 192        RoomParticipants {
 193            remote: vec!["user_a".to_string()],
 194            pending: vec!["user_c".to_string()]
 195        }
 196    );
 197
 198    // User C accepts the call.
 199    let call_c = incoming_call_c.next().await.unwrap().unwrap();
 200    assert_eq!(call_c.calling_user.github_login, "user_a");
 201    active_call_c
 202        .update(cx_c, |call, cx| call.accept_incoming(cx))
 203        .await
 204        .unwrap();
 205    assert!(incoming_call_c.next().await.unwrap().is_none());
 206    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 207
 208    deterministic.run_until_parked();
 209    assert_eq!(
 210        room_participants(&room_a, cx_a),
 211        RoomParticipants {
 212            remote: vec!["user_b".to_string(), "user_c".to_string()],
 213            pending: Default::default()
 214        }
 215    );
 216    assert_eq!(
 217        room_participants(&room_b, cx_b),
 218        RoomParticipants {
 219            remote: vec!["user_a".to_string(), "user_c".to_string()],
 220            pending: Default::default()
 221        }
 222    );
 223    assert_eq!(
 224        room_participants(&room_c, cx_c),
 225        RoomParticipants {
 226            remote: vec!["user_a".to_string(), "user_b".to_string()],
 227            pending: Default::default()
 228        }
 229    );
 230
 231    // User A shares their screen
 232    let display = MacOSDisplay::new();
 233    let events_b = active_call_events(cx_b);
 234    let events_c = active_call_events(cx_c);
 235    active_call_a
 236        .update(cx_a, |call, cx| {
 237            call.room().unwrap().update(cx, |room, cx| {
 238                room.set_display_sources(vec![display.clone()]);
 239                room.share_screen(cx)
 240            })
 241        })
 242        .await
 243        .unwrap();
 244
 245    deterministic.run_until_parked();
 246
 247    // User B observes the remote screen sharing track.
 248    assert_eq!(events_b.borrow().len(), 1);
 249    let event_b = events_b.borrow().first().unwrap().clone();
 250    if let call::room::Event::RemoteVideoTracksChanged { participant_id } = event_b {
 251        assert_eq!(participant_id, client_a.peer_id().unwrap());
 252        room_b.read_with(cx_b, |room, _| {
 253            assert_eq!(
 254                room.remote_participants()[&client_a.user_id().unwrap()]
 255                    .tracks
 256                    .len(),
 257                1
 258            );
 259        });
 260    } else {
 261        panic!("unexpected event")
 262    }
 263
 264    // User C observes the remote screen sharing track.
 265    assert_eq!(events_c.borrow().len(), 1);
 266    let event_c = events_c.borrow().first().unwrap().clone();
 267    if let call::room::Event::RemoteVideoTracksChanged { participant_id } = event_c {
 268        assert_eq!(participant_id, client_a.peer_id().unwrap());
 269        room_c.read_with(cx_c, |room, _| {
 270            assert_eq!(
 271                room.remote_participants()[&client_a.user_id().unwrap()]
 272                    .tracks
 273                    .len(),
 274                1
 275            );
 276        });
 277    } else {
 278        panic!("unexpected event")
 279    }
 280
 281    // User A leaves the room.
 282    active_call_a
 283        .update(cx_a, |call, cx| {
 284            let hang_up = call.hang_up(cx);
 285            assert!(call.room().is_none());
 286            hang_up
 287        })
 288        .await
 289        .unwrap();
 290    deterministic.run_until_parked();
 291    assert_eq!(
 292        room_participants(&room_a, cx_a),
 293        RoomParticipants {
 294            remote: Default::default(),
 295            pending: Default::default()
 296        }
 297    );
 298    assert_eq!(
 299        room_participants(&room_b, cx_b),
 300        RoomParticipants {
 301            remote: vec!["user_c".to_string()],
 302            pending: Default::default()
 303        }
 304    );
 305    assert_eq!(
 306        room_participants(&room_c, cx_c),
 307        RoomParticipants {
 308            remote: vec!["user_b".to_string()],
 309            pending: Default::default()
 310        }
 311    );
 312
 313    // User B gets disconnected from the LiveKit server, which causes them
 314    // to automatically leave the room. User C leaves the room as well because
 315    // nobody else is in there.
 316    server
 317        .test_live_kit_server
 318        .disconnect_client(client_b.user_id().unwrap().to_string())
 319        .await;
 320    deterministic.run_until_parked();
 321    active_call_b.read_with(cx_b, |call, _| assert!(call.room().is_none()));
 322    active_call_c.read_with(cx_c, |call, _| assert!(call.room().is_none()));
 323    assert_eq!(
 324        room_participants(&room_a, cx_a),
 325        RoomParticipants {
 326            remote: Default::default(),
 327            pending: Default::default()
 328        }
 329    );
 330    assert_eq!(
 331        room_participants(&room_b, cx_b),
 332        RoomParticipants {
 333            remote: Default::default(),
 334            pending: Default::default()
 335        }
 336    );
 337    assert_eq!(
 338        room_participants(&room_c, cx_c),
 339        RoomParticipants {
 340            remote: Default::default(),
 341            pending: Default::default()
 342        }
 343    );
 344}
 345
 346#[gpui::test(iterations = 10)]
 347async fn test_calling_multiple_users_simultaneously(
 348    deterministic: Arc<Deterministic>,
 349    cx_a: &mut TestAppContext,
 350    cx_b: &mut TestAppContext,
 351    cx_c: &mut TestAppContext,
 352    cx_d: &mut TestAppContext,
 353) {
 354    deterministic.forbid_parking();
 355    let mut server = TestServer::start(&deterministic).await;
 356
 357    let client_a = server.create_client(cx_a, "user_a").await;
 358    let client_b = server.create_client(cx_b, "user_b").await;
 359    let client_c = server.create_client(cx_c, "user_c").await;
 360    let client_d = server.create_client(cx_d, "user_d").await;
 361    server
 362        .make_contacts(&mut [
 363            (&client_a, cx_a),
 364            (&client_b, cx_b),
 365            (&client_c, cx_c),
 366            (&client_d, cx_d),
 367        ])
 368        .await;
 369
 370    let active_call_a = cx_a.read(ActiveCall::global);
 371    let active_call_b = cx_b.read(ActiveCall::global);
 372    let active_call_c = cx_c.read(ActiveCall::global);
 373    let active_call_d = cx_d.read(ActiveCall::global);
 374
 375    // Simultaneously call user B and user C from client A.
 376    let b_invite = active_call_a.update(cx_a, |call, cx| {
 377        call.invite(client_b.user_id().unwrap(), None, cx)
 378    });
 379    let c_invite = active_call_a.update(cx_a, |call, cx| {
 380        call.invite(client_c.user_id().unwrap(), None, cx)
 381    });
 382    b_invite.await.unwrap();
 383    c_invite.await.unwrap();
 384
 385    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 386    deterministic.run_until_parked();
 387    assert_eq!(
 388        room_participants(&room_a, cx_a),
 389        RoomParticipants {
 390            remote: Default::default(),
 391            pending: vec!["user_b".to_string(), "user_c".to_string()]
 392        }
 393    );
 394
 395    // Call client D from client A.
 396    active_call_a
 397        .update(cx_a, |call, cx| {
 398            call.invite(client_d.user_id().unwrap(), None, cx)
 399        })
 400        .await
 401        .unwrap();
 402    deterministic.run_until_parked();
 403    assert_eq!(
 404        room_participants(&room_a, cx_a),
 405        RoomParticipants {
 406            remote: Default::default(),
 407            pending: vec![
 408                "user_b".to_string(),
 409                "user_c".to_string(),
 410                "user_d".to_string()
 411            ]
 412        }
 413    );
 414
 415    // Accept the call on all clients simultaneously.
 416    let accept_b = active_call_b.update(cx_b, |call, cx| call.accept_incoming(cx));
 417    let accept_c = active_call_c.update(cx_c, |call, cx| call.accept_incoming(cx));
 418    let accept_d = active_call_d.update(cx_d, |call, cx| call.accept_incoming(cx));
 419    accept_b.await.unwrap();
 420    accept_c.await.unwrap();
 421    accept_d.await.unwrap();
 422
 423    deterministic.run_until_parked();
 424
 425    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 426    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 427    let room_d = active_call_d.read_with(cx_d, |call, _| call.room().unwrap().clone());
 428    assert_eq!(
 429        room_participants(&room_a, cx_a),
 430        RoomParticipants {
 431            remote: vec![
 432                "user_b".to_string(),
 433                "user_c".to_string(),
 434                "user_d".to_string(),
 435            ],
 436            pending: Default::default()
 437        }
 438    );
 439    assert_eq!(
 440        room_participants(&room_b, cx_b),
 441        RoomParticipants {
 442            remote: vec![
 443                "user_a".to_string(),
 444                "user_c".to_string(),
 445                "user_d".to_string(),
 446            ],
 447            pending: Default::default()
 448        }
 449    );
 450    assert_eq!(
 451        room_participants(&room_c, cx_c),
 452        RoomParticipants {
 453            remote: vec![
 454                "user_a".to_string(),
 455                "user_b".to_string(),
 456                "user_d".to_string(),
 457            ],
 458            pending: Default::default()
 459        }
 460    );
 461    assert_eq!(
 462        room_participants(&room_d, cx_d),
 463        RoomParticipants {
 464            remote: vec![
 465                "user_a".to_string(),
 466                "user_b".to_string(),
 467                "user_c".to_string(),
 468            ],
 469            pending: Default::default()
 470        }
 471    );
 472}
 473
 474#[gpui::test(iterations = 10)]
 475async fn test_room_uniqueness(
 476    deterministic: Arc<Deterministic>,
 477    cx_a: &mut TestAppContext,
 478    cx_a2: &mut TestAppContext,
 479    cx_b: &mut TestAppContext,
 480    cx_b2: &mut TestAppContext,
 481    cx_c: &mut TestAppContext,
 482) {
 483    deterministic.forbid_parking();
 484    let mut server = TestServer::start(&deterministic).await;
 485    let client_a = server.create_client(cx_a, "user_a").await;
 486    let _client_a2 = server.create_client(cx_a2, "user_a").await;
 487    let client_b = server.create_client(cx_b, "user_b").await;
 488    let _client_b2 = server.create_client(cx_b2, "user_b").await;
 489    let client_c = server.create_client(cx_c, "user_c").await;
 490    server
 491        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
 492        .await;
 493
 494    let active_call_a = cx_a.read(ActiveCall::global);
 495    let active_call_a2 = cx_a2.read(ActiveCall::global);
 496    let active_call_b = cx_b.read(ActiveCall::global);
 497    let active_call_b2 = cx_b2.read(ActiveCall::global);
 498    let active_call_c = cx_c.read(ActiveCall::global);
 499
 500    // Call user B from client A.
 501    active_call_a
 502        .update(cx_a, |call, cx| {
 503            call.invite(client_b.user_id().unwrap(), None, cx)
 504        })
 505        .await
 506        .unwrap();
 507
 508    // Ensure a new room can't be created given user A just created one.
 509    active_call_a2
 510        .update(cx_a2, |call, cx| {
 511            call.invite(client_c.user_id().unwrap(), None, cx)
 512        })
 513        .await
 514        .unwrap_err();
 515    active_call_a2.read_with(cx_a2, |call, _| assert!(call.room().is_none()));
 516
 517    // User B receives the call from user A.
 518    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 519    let call_b1 = incoming_call_b.next().await.unwrap().unwrap();
 520    assert_eq!(call_b1.calling_user.github_login, "user_a");
 521
 522    // Ensure calling users A and B from client C fails.
 523    active_call_c
 524        .update(cx_c, |call, cx| {
 525            call.invite(client_a.user_id().unwrap(), None, cx)
 526        })
 527        .await
 528        .unwrap_err();
 529    active_call_c
 530        .update(cx_c, |call, cx| {
 531            call.invite(client_b.user_id().unwrap(), None, cx)
 532        })
 533        .await
 534        .unwrap_err();
 535
 536    // Ensure User B can't create a room while they still have an incoming call.
 537    active_call_b2
 538        .update(cx_b2, |call, cx| {
 539            call.invite(client_c.user_id().unwrap(), None, cx)
 540        })
 541        .await
 542        .unwrap_err();
 543    active_call_b2.read_with(cx_b2, |call, _| assert!(call.room().is_none()));
 544
 545    // User B joins the room and calling them after they've joined still fails.
 546    active_call_b
 547        .update(cx_b, |call, cx| call.accept_incoming(cx))
 548        .await
 549        .unwrap();
 550    active_call_c
 551        .update(cx_c, |call, cx| {
 552            call.invite(client_b.user_id().unwrap(), None, cx)
 553        })
 554        .await
 555        .unwrap_err();
 556
 557    // Ensure User B can't create a room while they belong to another room.
 558    active_call_b2
 559        .update(cx_b2, |call, cx| {
 560            call.invite(client_c.user_id().unwrap(), None, cx)
 561        })
 562        .await
 563        .unwrap_err();
 564    active_call_b2.read_with(cx_b2, |call, _| assert!(call.room().is_none()));
 565
 566    // Client C can successfully call client B after client B leaves the room.
 567    active_call_b
 568        .update(cx_b, |call, cx| call.hang_up(cx))
 569        .await
 570        .unwrap();
 571    deterministic.run_until_parked();
 572    active_call_c
 573        .update(cx_c, |call, cx| {
 574            call.invite(client_b.user_id().unwrap(), None, cx)
 575        })
 576        .await
 577        .unwrap();
 578    deterministic.run_until_parked();
 579    let call_b2 = incoming_call_b.next().await.unwrap().unwrap();
 580    assert_eq!(call_b2.calling_user.github_login, "user_c");
 581}
 582
 583#[gpui::test(iterations = 10)]
 584async fn test_client_disconnecting_from_room(
 585    deterministic: Arc<Deterministic>,
 586    cx_a: &mut TestAppContext,
 587    cx_b: &mut TestAppContext,
 588) {
 589    deterministic.forbid_parking();
 590    let mut server = TestServer::start(&deterministic).await;
 591    let client_a = server.create_client(cx_a, "user_a").await;
 592    let client_b = server.create_client(cx_b, "user_b").await;
 593    server
 594        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
 595        .await;
 596
 597    let active_call_a = cx_a.read(ActiveCall::global);
 598    let active_call_b = cx_b.read(ActiveCall::global);
 599
 600    // Call user B from client A.
 601    active_call_a
 602        .update(cx_a, |call, cx| {
 603            call.invite(client_b.user_id().unwrap(), None, cx)
 604        })
 605        .await
 606        .unwrap();
 607    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 608
 609    // User B receives the call and joins the room.
 610    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 611    incoming_call_b.next().await.unwrap().unwrap();
 612    active_call_b
 613        .update(cx_b, |call, cx| call.accept_incoming(cx))
 614        .await
 615        .unwrap();
 616    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 617    deterministic.run_until_parked();
 618    assert_eq!(
 619        room_participants(&room_a, cx_a),
 620        RoomParticipants {
 621            remote: vec!["user_b".to_string()],
 622            pending: Default::default()
 623        }
 624    );
 625    assert_eq!(
 626        room_participants(&room_b, cx_b),
 627        RoomParticipants {
 628            remote: vec!["user_a".to_string()],
 629            pending: Default::default()
 630        }
 631    );
 632
 633    // User A automatically reconnects to the room upon disconnection.
 634    server.disconnect_client(client_a.peer_id().unwrap());
 635    deterministic.advance_clock(RECEIVE_TIMEOUT);
 636    deterministic.run_until_parked();
 637    assert_eq!(
 638        room_participants(&room_a, cx_a),
 639        RoomParticipants {
 640            remote: vec!["user_b".to_string()],
 641            pending: Default::default()
 642        }
 643    );
 644    assert_eq!(
 645        room_participants(&room_b, cx_b),
 646        RoomParticipants {
 647            remote: vec!["user_a".to_string()],
 648            pending: Default::default()
 649        }
 650    );
 651
 652    // When user A disconnects, both client A and B clear their room on the active call.
 653    server.forbid_connections();
 654    server.disconnect_client(client_a.peer_id().unwrap());
 655    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
 656    active_call_a.read_with(cx_a, |call, _| assert!(call.room().is_none()));
 657    active_call_b.read_with(cx_b, |call, _| assert!(call.room().is_none()));
 658    assert_eq!(
 659        room_participants(&room_a, cx_a),
 660        RoomParticipants {
 661            remote: Default::default(),
 662            pending: Default::default()
 663        }
 664    );
 665    assert_eq!(
 666        room_participants(&room_b, cx_b),
 667        RoomParticipants {
 668            remote: Default::default(),
 669            pending: Default::default()
 670        }
 671    );
 672
 673    // Allow user A to reconnect to the server.
 674    server.allow_connections();
 675    deterministic.advance_clock(RECEIVE_TIMEOUT);
 676
 677    // Call user B again from client A.
 678    active_call_a
 679        .update(cx_a, |call, cx| {
 680            call.invite(client_b.user_id().unwrap(), None, cx)
 681        })
 682        .await
 683        .unwrap();
 684    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 685
 686    // User B receives the call and joins the room.
 687    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 688    incoming_call_b.next().await.unwrap().unwrap();
 689    active_call_b
 690        .update(cx_b, |call, cx| call.accept_incoming(cx))
 691        .await
 692        .unwrap();
 693    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 694    deterministic.run_until_parked();
 695    assert_eq!(
 696        room_participants(&room_a, cx_a),
 697        RoomParticipants {
 698            remote: vec!["user_b".to_string()],
 699            pending: Default::default()
 700        }
 701    );
 702    assert_eq!(
 703        room_participants(&room_b, cx_b),
 704        RoomParticipants {
 705            remote: vec!["user_a".to_string()],
 706            pending: Default::default()
 707        }
 708    );
 709
 710    // User B gets disconnected from the LiveKit server, which causes it
 711    // to automatically leave the room.
 712    server
 713        .test_live_kit_server
 714        .disconnect_client(client_b.user_id().unwrap().to_string())
 715        .await;
 716    deterministic.run_until_parked();
 717    active_call_a.update(cx_a, |call, _| assert!(call.room().is_none()));
 718    active_call_b.update(cx_b, |call, _| assert!(call.room().is_none()));
 719    assert_eq!(
 720        room_participants(&room_a, cx_a),
 721        RoomParticipants {
 722            remote: Default::default(),
 723            pending: Default::default()
 724        }
 725    );
 726    assert_eq!(
 727        room_participants(&room_b, cx_b),
 728        RoomParticipants {
 729            remote: Default::default(),
 730            pending: Default::default()
 731        }
 732    );
 733}
 734
 735#[gpui::test(iterations = 10)]
 736async fn test_server_restarts(
 737    deterministic: Arc<Deterministic>,
 738    cx_a: &mut TestAppContext,
 739    cx_b: &mut TestAppContext,
 740    cx_c: &mut TestAppContext,
 741    cx_d: &mut TestAppContext,
 742) {
 743    deterministic.forbid_parking();
 744    let mut server = TestServer::start(&deterministic).await;
 745    let client_a = server.create_client(cx_a, "user_a").await;
 746    client_a
 747        .fs
 748        .insert_tree("/a", json!({ "a.txt": "a-contents" }))
 749        .await;
 750
 751    // Invite client B to collaborate on a project
 752    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
 753
 754    let client_b = server.create_client(cx_b, "user_b").await;
 755    let client_c = server.create_client(cx_c, "user_c").await;
 756    let client_d = server.create_client(cx_d, "user_d").await;
 757    server
 758        .make_contacts(&mut [
 759            (&client_a, cx_a),
 760            (&client_b, cx_b),
 761            (&client_c, cx_c),
 762            (&client_d, cx_d),
 763        ])
 764        .await;
 765
 766    let active_call_a = cx_a.read(ActiveCall::global);
 767    let active_call_b = cx_b.read(ActiveCall::global);
 768    let active_call_c = cx_c.read(ActiveCall::global);
 769    let active_call_d = cx_d.read(ActiveCall::global);
 770
 771    // User A calls users B, C, and D.
 772    active_call_a
 773        .update(cx_a, |call, cx| {
 774            call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
 775        })
 776        .await
 777        .unwrap();
 778    active_call_a
 779        .update(cx_a, |call, cx| {
 780            call.invite(client_c.user_id().unwrap(), Some(project_a.clone()), cx)
 781        })
 782        .await
 783        .unwrap();
 784    active_call_a
 785        .update(cx_a, |call, cx| {
 786            call.invite(client_d.user_id().unwrap(), Some(project_a.clone()), cx)
 787        })
 788        .await
 789        .unwrap();
 790    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
 791
 792    // User B receives the call and joins the room.
 793    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
 794    assert!(incoming_call_b.next().await.unwrap().is_some());
 795    active_call_b
 796        .update(cx_b, |call, cx| call.accept_incoming(cx))
 797        .await
 798        .unwrap();
 799    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
 800
 801    // User C receives the call and joins the room.
 802    let mut incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
 803    assert!(incoming_call_c.next().await.unwrap().is_some());
 804    active_call_c
 805        .update(cx_c, |call, cx| call.accept_incoming(cx))
 806        .await
 807        .unwrap();
 808    let room_c = active_call_c.read_with(cx_c, |call, _| call.room().unwrap().clone());
 809
 810    // User D receives the call but doesn't join the room yet.
 811    let mut incoming_call_d = active_call_d.read_with(cx_d, |call, _| call.incoming());
 812    assert!(incoming_call_d.next().await.unwrap().is_some());
 813
 814    deterministic.run_until_parked();
 815    assert_eq!(
 816        room_participants(&room_a, cx_a),
 817        RoomParticipants {
 818            remote: vec!["user_b".to_string(), "user_c".to_string()],
 819            pending: vec!["user_d".to_string()]
 820        }
 821    );
 822    assert_eq!(
 823        room_participants(&room_b, cx_b),
 824        RoomParticipants {
 825            remote: vec!["user_a".to_string(), "user_c".to_string()],
 826            pending: vec!["user_d".to_string()]
 827        }
 828    );
 829    assert_eq!(
 830        room_participants(&room_c, cx_c),
 831        RoomParticipants {
 832            remote: vec!["user_a".to_string(), "user_b".to_string()],
 833            pending: vec!["user_d".to_string()]
 834        }
 835    );
 836
 837    // The server is torn down.
 838    server.reset().await;
 839
 840    // Users A and B reconnect to the call. User C has troubles reconnecting, so it leaves the room.
 841    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
 842    deterministic.advance_clock(RECONNECT_TIMEOUT);
 843    assert_eq!(
 844        room_participants(&room_a, cx_a),
 845        RoomParticipants {
 846            remote: vec!["user_b".to_string(), "user_c".to_string()],
 847            pending: vec!["user_d".to_string()]
 848        }
 849    );
 850    assert_eq!(
 851        room_participants(&room_b, cx_b),
 852        RoomParticipants {
 853            remote: vec!["user_a".to_string(), "user_c".to_string()],
 854            pending: vec!["user_d".to_string()]
 855        }
 856    );
 857    assert_eq!(
 858        room_participants(&room_c, cx_c),
 859        RoomParticipants {
 860            remote: vec![],
 861            pending: vec![]
 862        }
 863    );
 864
 865    // User D is notified again of the incoming call and accepts it.
 866    assert!(incoming_call_d.next().await.unwrap().is_some());
 867    active_call_d
 868        .update(cx_d, |call, cx| call.accept_incoming(cx))
 869        .await
 870        .unwrap();
 871    deterministic.run_until_parked();
 872    let room_d = active_call_d.read_with(cx_d, |call, _| call.room().unwrap().clone());
 873    assert_eq!(
 874        room_participants(&room_a, cx_a),
 875        RoomParticipants {
 876            remote: vec![
 877                "user_b".to_string(),
 878                "user_c".to_string(),
 879                "user_d".to_string(),
 880            ],
 881            pending: vec![]
 882        }
 883    );
 884    assert_eq!(
 885        room_participants(&room_b, cx_b),
 886        RoomParticipants {
 887            remote: vec![
 888                "user_a".to_string(),
 889                "user_c".to_string(),
 890                "user_d".to_string(),
 891            ],
 892            pending: vec![]
 893        }
 894    );
 895    assert_eq!(
 896        room_participants(&room_c, cx_c),
 897        RoomParticipants {
 898            remote: vec![],
 899            pending: vec![]
 900        }
 901    );
 902    assert_eq!(
 903        room_participants(&room_d, cx_d),
 904        RoomParticipants {
 905            remote: vec![
 906                "user_a".to_string(),
 907                "user_b".to_string(),
 908                "user_c".to_string(),
 909            ],
 910            pending: vec![]
 911        }
 912    );
 913
 914    // The server finishes restarting, cleaning up stale connections.
 915    server.start().await.unwrap();
 916    deterministic.advance_clock(CLEANUP_TIMEOUT);
 917    assert_eq!(
 918        room_participants(&room_a, cx_a),
 919        RoomParticipants {
 920            remote: vec!["user_b".to_string(), "user_d".to_string()],
 921            pending: vec![]
 922        }
 923    );
 924    assert_eq!(
 925        room_participants(&room_b, cx_b),
 926        RoomParticipants {
 927            remote: vec!["user_a".to_string(), "user_d".to_string()],
 928            pending: vec![]
 929        }
 930    );
 931    assert_eq!(
 932        room_participants(&room_c, cx_c),
 933        RoomParticipants {
 934            remote: vec![],
 935            pending: vec![]
 936        }
 937    );
 938    assert_eq!(
 939        room_participants(&room_d, cx_d),
 940        RoomParticipants {
 941            remote: vec!["user_a".to_string(), "user_b".to_string()],
 942            pending: vec![]
 943        }
 944    );
 945
 946    // User D hangs up.
 947    active_call_d
 948        .update(cx_d, |call, cx| call.hang_up(cx))
 949        .await
 950        .unwrap();
 951    deterministic.run_until_parked();
 952    assert_eq!(
 953        room_participants(&room_a, cx_a),
 954        RoomParticipants {
 955            remote: vec!["user_b".to_string()],
 956            pending: vec![]
 957        }
 958    );
 959    assert_eq!(
 960        room_participants(&room_b, cx_b),
 961        RoomParticipants {
 962            remote: vec!["user_a".to_string()],
 963            pending: vec![]
 964        }
 965    );
 966    assert_eq!(
 967        room_participants(&room_c, cx_c),
 968        RoomParticipants {
 969            remote: vec![],
 970            pending: vec![]
 971        }
 972    );
 973    assert_eq!(
 974        room_participants(&room_d, cx_d),
 975        RoomParticipants {
 976            remote: vec![],
 977            pending: vec![]
 978        }
 979    );
 980
 981    // User B calls user D again.
 982    active_call_b
 983        .update(cx_b, |call, cx| {
 984            call.invite(client_d.user_id().unwrap(), None, cx)
 985        })
 986        .await
 987        .unwrap();
 988
 989    // User D receives the call but doesn't join the room yet.
 990    let mut incoming_call_d = active_call_d.read_with(cx_d, |call, _| call.incoming());
 991    assert!(incoming_call_d.next().await.unwrap().is_some());
 992    deterministic.run_until_parked();
 993    assert_eq!(
 994        room_participants(&room_a, cx_a),
 995        RoomParticipants {
 996            remote: vec!["user_b".to_string()],
 997            pending: vec!["user_d".to_string()]
 998        }
 999    );
1000    assert_eq!(
1001        room_participants(&room_b, cx_b),
1002        RoomParticipants {
1003            remote: vec!["user_a".to_string()],
1004            pending: vec!["user_d".to_string()]
1005        }
1006    );
1007
1008    // The server is torn down.
1009    server.reset().await;
1010
1011    // Users A and B have troubles reconnecting, so they leave the room.
1012    client_a.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1013    client_b.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1014    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
1015    deterministic.advance_clock(RECONNECT_TIMEOUT);
1016    assert_eq!(
1017        room_participants(&room_a, cx_a),
1018        RoomParticipants {
1019            remote: vec![],
1020            pending: vec![]
1021        }
1022    );
1023    assert_eq!(
1024        room_participants(&room_b, cx_b),
1025        RoomParticipants {
1026            remote: vec![],
1027            pending: vec![]
1028        }
1029    );
1030
1031    // User D is notified again of the incoming call but doesn't accept it.
1032    assert!(incoming_call_d.next().await.unwrap().is_some());
1033
1034    // The server finishes restarting, cleaning up stale connections and canceling the
1035    // call to user D because the room has become empty.
1036    server.start().await.unwrap();
1037    deterministic.advance_clock(CLEANUP_TIMEOUT);
1038    assert!(incoming_call_d.next().await.unwrap().is_none());
1039}
1040
1041#[gpui::test(iterations = 10)]
1042async fn test_calls_on_multiple_connections(
1043    deterministic: Arc<Deterministic>,
1044    cx_a: &mut TestAppContext,
1045    cx_b1: &mut TestAppContext,
1046    cx_b2: &mut TestAppContext,
1047) {
1048    deterministic.forbid_parking();
1049    let mut server = TestServer::start(&deterministic).await;
1050    let client_a = server.create_client(cx_a, "user_a").await;
1051    let client_b1 = server.create_client(cx_b1, "user_b").await;
1052    let client_b2 = server.create_client(cx_b2, "user_b").await;
1053    server
1054        .make_contacts(&mut [(&client_a, cx_a), (&client_b1, cx_b1)])
1055        .await;
1056
1057    let active_call_a = cx_a.read(ActiveCall::global);
1058    let active_call_b1 = cx_b1.read(ActiveCall::global);
1059    let active_call_b2 = cx_b2.read(ActiveCall::global);
1060    let mut incoming_call_b1 = active_call_b1.read_with(cx_b1, |call, _| call.incoming());
1061    let mut incoming_call_b2 = active_call_b2.read_with(cx_b2, |call, _| call.incoming());
1062    assert!(incoming_call_b1.next().await.unwrap().is_none());
1063    assert!(incoming_call_b2.next().await.unwrap().is_none());
1064
1065    // Call user B from client A, ensuring both clients for user B ring.
1066    active_call_a
1067        .update(cx_a, |call, cx| {
1068            call.invite(client_b1.user_id().unwrap(), None, cx)
1069        })
1070        .await
1071        .unwrap();
1072    deterministic.run_until_parked();
1073    assert!(incoming_call_b1.next().await.unwrap().is_some());
1074    assert!(incoming_call_b2.next().await.unwrap().is_some());
1075
1076    // User B declines the call on one of the two connections, causing both connections
1077    // to stop ringing.
1078    active_call_b2.update(cx_b2, |call, _| call.decline_incoming().unwrap());
1079    deterministic.run_until_parked();
1080    assert!(incoming_call_b1.next().await.unwrap().is_none());
1081    assert!(incoming_call_b2.next().await.unwrap().is_none());
1082
1083    // Call user B again from client A.
1084    active_call_a
1085        .update(cx_a, |call, cx| {
1086            call.invite(client_b1.user_id().unwrap(), None, cx)
1087        })
1088        .await
1089        .unwrap();
1090    deterministic.run_until_parked();
1091    assert!(incoming_call_b1.next().await.unwrap().is_some());
1092    assert!(incoming_call_b2.next().await.unwrap().is_some());
1093
1094    // User B accepts the call on one of the two connections, causing both connections
1095    // to stop ringing.
1096    active_call_b2
1097        .update(cx_b2, |call, cx| call.accept_incoming(cx))
1098        .await
1099        .unwrap();
1100    deterministic.run_until_parked();
1101    assert!(incoming_call_b1.next().await.unwrap().is_none());
1102    assert!(incoming_call_b2.next().await.unwrap().is_none());
1103
1104    // User B disconnects the client that is not on the call. Everything should be fine.
1105    client_b1.disconnect(&cx_b1.to_async());
1106    deterministic.advance_clock(RECEIVE_TIMEOUT);
1107    client_b1
1108        .authenticate_and_connect(false, &cx_b1.to_async())
1109        .await
1110        .unwrap();
1111
1112    // User B hangs up, and user A calls them again.
1113    active_call_b2
1114        .update(cx_b2, |call, cx| call.hang_up(cx))
1115        .await
1116        .unwrap();
1117    deterministic.run_until_parked();
1118    active_call_a
1119        .update(cx_a, |call, cx| {
1120            call.invite(client_b1.user_id().unwrap(), None, cx)
1121        })
1122        .await
1123        .unwrap();
1124    deterministic.run_until_parked();
1125    assert!(incoming_call_b1.next().await.unwrap().is_some());
1126    assert!(incoming_call_b2.next().await.unwrap().is_some());
1127
1128    // User A cancels the call, causing both connections to stop ringing.
1129    active_call_a
1130        .update(cx_a, |call, cx| {
1131            call.cancel_invite(client_b1.user_id().unwrap(), cx)
1132        })
1133        .await
1134        .unwrap();
1135    deterministic.run_until_parked();
1136    assert!(incoming_call_b1.next().await.unwrap().is_none());
1137    assert!(incoming_call_b2.next().await.unwrap().is_none());
1138
1139    // User A calls user B again.
1140    active_call_a
1141        .update(cx_a, |call, cx| {
1142            call.invite(client_b1.user_id().unwrap(), None, cx)
1143        })
1144        .await
1145        .unwrap();
1146    deterministic.run_until_parked();
1147    assert!(incoming_call_b1.next().await.unwrap().is_some());
1148    assert!(incoming_call_b2.next().await.unwrap().is_some());
1149
1150    // User A hangs up, causing both connections to stop ringing.
1151    active_call_a
1152        .update(cx_a, |call, cx| call.hang_up(cx))
1153        .await
1154        .unwrap();
1155    deterministic.run_until_parked();
1156    assert!(incoming_call_b1.next().await.unwrap().is_none());
1157    assert!(incoming_call_b2.next().await.unwrap().is_none());
1158
1159    // User A calls user B again.
1160    active_call_a
1161        .update(cx_a, |call, cx| {
1162            call.invite(client_b1.user_id().unwrap(), None, cx)
1163        })
1164        .await
1165        .unwrap();
1166    deterministic.run_until_parked();
1167    assert!(incoming_call_b1.next().await.unwrap().is_some());
1168    assert!(incoming_call_b2.next().await.unwrap().is_some());
1169
1170    // User A disconnects, causing both connections to stop ringing.
1171    server.forbid_connections();
1172    server.disconnect_client(client_a.peer_id().unwrap());
1173    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1174    assert!(incoming_call_b1.next().await.unwrap().is_none());
1175    assert!(incoming_call_b2.next().await.unwrap().is_none());
1176
1177    // User A reconnects automatically, then calls user B again.
1178    server.allow_connections();
1179    deterministic.advance_clock(RECEIVE_TIMEOUT);
1180    active_call_a
1181        .update(cx_a, |call, cx| {
1182            call.invite(client_b1.user_id().unwrap(), None, cx)
1183        })
1184        .await
1185        .unwrap();
1186    deterministic.run_until_parked();
1187    assert!(incoming_call_b1.next().await.unwrap().is_some());
1188    assert!(incoming_call_b2.next().await.unwrap().is_some());
1189
1190    // User B disconnects all clients, causing user A to no longer see a pending call for them.
1191    server.forbid_connections();
1192    server.disconnect_client(client_b1.peer_id().unwrap());
1193    server.disconnect_client(client_b2.peer_id().unwrap());
1194    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1195    active_call_a.read_with(cx_a, |call, _| assert!(call.room().is_none()));
1196}
1197
1198#[gpui::test(iterations = 10)]
1199async fn test_share_project(
1200    deterministic: Arc<Deterministic>,
1201    cx_a: &mut TestAppContext,
1202    cx_b: &mut TestAppContext,
1203    cx_c: &mut TestAppContext,
1204) {
1205    deterministic.forbid_parking();
1206    let (window_b, _) = cx_b.add_window(|_| EmptyView);
1207    let mut server = TestServer::start(&deterministic).await;
1208    let client_a = server.create_client(cx_a, "user_a").await;
1209    let client_b = server.create_client(cx_b, "user_b").await;
1210    let client_c = server.create_client(cx_c, "user_c").await;
1211    server
1212        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1213        .await;
1214    let active_call_a = cx_a.read(ActiveCall::global);
1215    let active_call_b = cx_b.read(ActiveCall::global);
1216    let active_call_c = cx_c.read(ActiveCall::global);
1217
1218    client_a
1219        .fs
1220        .insert_tree(
1221            "/a",
1222            json!({
1223                ".gitignore": "ignored-dir",
1224                "a.txt": "a-contents",
1225                "b.txt": "b-contents",
1226                "ignored-dir": {
1227                    "c.txt": "",
1228                    "d.txt": "",
1229                }
1230            }),
1231        )
1232        .await;
1233
1234    // Invite client B to collaborate on a project
1235    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1236    active_call_a
1237        .update(cx_a, |call, cx| {
1238            call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
1239        })
1240        .await
1241        .unwrap();
1242
1243    // Join that project as client B
1244    let incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
1245    deterministic.run_until_parked();
1246    let call = incoming_call_b.borrow().clone().unwrap();
1247    assert_eq!(call.calling_user.github_login, "user_a");
1248    let initial_project = call.initial_project.unwrap();
1249    active_call_b
1250        .update(cx_b, |call, cx| call.accept_incoming(cx))
1251        .await
1252        .unwrap();
1253    let client_b_peer_id = client_b.peer_id().unwrap();
1254    let project_b = client_b
1255        .build_remote_project(initial_project.id, cx_b)
1256        .await;
1257    let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
1258
1259    deterministic.run_until_parked();
1260    project_a.read_with(cx_a, |project, _| {
1261        let client_b_collaborator = project.collaborators().get(&client_b_peer_id).unwrap();
1262        assert_eq!(client_b_collaborator.replica_id, replica_id_b);
1263    });
1264    project_b.read_with(cx_b, |project, cx| {
1265        let worktree = project.worktrees(cx).next().unwrap().read(cx);
1266        assert_eq!(
1267            worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
1268            [
1269                Path::new(".gitignore"),
1270                Path::new("a.txt"),
1271                Path::new("b.txt"),
1272                Path::new("ignored-dir"),
1273                Path::new("ignored-dir/c.txt"),
1274                Path::new("ignored-dir/d.txt"),
1275            ]
1276        );
1277    });
1278
1279    // Open the same file as client B and client A.
1280    let buffer_b = project_b
1281        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
1282        .await
1283        .unwrap();
1284    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "b-contents"));
1285    project_a.read_with(cx_a, |project, cx| {
1286        assert!(project.has_open_buffer((worktree_id, "b.txt"), cx))
1287    });
1288    let buffer_a = project_a
1289        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
1290        .await
1291        .unwrap();
1292
1293    let editor_b = cx_b.add_view(window_b, |cx| Editor::for_buffer(buffer_b, None, cx));
1294
1295    // Client A sees client B's selection
1296    deterministic.run_until_parked();
1297    buffer_a.read_with(cx_a, |buffer, _| {
1298        buffer
1299            .snapshot()
1300            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1301            .count()
1302            == 1
1303    });
1304
1305    // Edit the buffer as client B and see that edit as client A.
1306    editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
1307    deterministic.run_until_parked();
1308    buffer_a.read_with(cx_a, |buffer, _| {
1309        assert_eq!(buffer.text(), "ok, b-contents")
1310    });
1311
1312    // Client B can invite client C on a project shared by client A.
1313    active_call_b
1314        .update(cx_b, |call, cx| {
1315            call.invite(client_c.user_id().unwrap(), Some(project_b.clone()), cx)
1316        })
1317        .await
1318        .unwrap();
1319
1320    let incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
1321    deterministic.run_until_parked();
1322    let call = incoming_call_c.borrow().clone().unwrap();
1323    assert_eq!(call.calling_user.github_login, "user_b");
1324    let initial_project = call.initial_project.unwrap();
1325    active_call_c
1326        .update(cx_c, |call, cx| call.accept_incoming(cx))
1327        .await
1328        .unwrap();
1329    let _project_c = client_c
1330        .build_remote_project(initial_project.id, cx_c)
1331        .await;
1332
1333    // Client B closes the editor, and client A sees client B's selections removed.
1334    cx_b.update(move |_| drop(editor_b));
1335    deterministic.run_until_parked();
1336    buffer_a.read_with(cx_a, |buffer, _| {
1337        buffer
1338            .snapshot()
1339            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
1340            .count()
1341            == 0
1342    });
1343}
1344
1345#[gpui::test(iterations = 10)]
1346async fn test_unshare_project(
1347    deterministic: Arc<Deterministic>,
1348    cx_a: &mut TestAppContext,
1349    cx_b: &mut TestAppContext,
1350    cx_c: &mut TestAppContext,
1351) {
1352    deterministic.forbid_parking();
1353    let mut server = TestServer::start(&deterministic).await;
1354    let client_a = server.create_client(cx_a, "user_a").await;
1355    let client_b = server.create_client(cx_b, "user_b").await;
1356    let client_c = server.create_client(cx_c, "user_c").await;
1357    server
1358        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1359        .await;
1360
1361    let active_call_a = cx_a.read(ActiveCall::global);
1362    let active_call_b = cx_b.read(ActiveCall::global);
1363
1364    client_a
1365        .fs
1366        .insert_tree(
1367            "/a",
1368            json!({
1369                "a.txt": "a-contents",
1370                "b.txt": "b-contents",
1371            }),
1372        )
1373        .await;
1374
1375    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1376    let project_id = active_call_a
1377        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1378        .await
1379        .unwrap();
1380    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1381    let project_b = client_b.build_remote_project(project_id, cx_b).await;
1382    deterministic.run_until_parked();
1383    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1384
1385    project_b
1386        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
1387        .await
1388        .unwrap();
1389
1390    // When client B leaves the room, the project becomes read-only.
1391    active_call_b
1392        .update(cx_b, |call, cx| call.hang_up(cx))
1393        .await
1394        .unwrap();
1395    deterministic.run_until_parked();
1396    assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
1397
1398    // Client C opens the project.
1399    let project_c = client_c.build_remote_project(project_id, cx_c).await;
1400
1401    // When client A unshares the project, client C's project becomes read-only.
1402    project_a
1403        .update(cx_a, |project, cx| project.unshare(cx))
1404        .unwrap();
1405    deterministic.run_until_parked();
1406    assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
1407    assert!(project_c.read_with(cx_c, |project, _| project.is_read_only()));
1408
1409    // Client C can open the project again after client A re-shares.
1410    let project_id = active_call_a
1411        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1412        .await
1413        .unwrap();
1414    let project_c2 = client_c.build_remote_project(project_id, cx_c).await;
1415    deterministic.run_until_parked();
1416    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1417    project_c2
1418        .update(cx_c, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
1419        .await
1420        .unwrap();
1421
1422    // When client A (the host) leaves the room, the project gets unshared and guests are notified.
1423    active_call_a
1424        .update(cx_a, |call, cx| call.hang_up(cx))
1425        .await
1426        .unwrap();
1427    deterministic.run_until_parked();
1428    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1429    project_c2.read_with(cx_c, |project, _| {
1430        assert!(project.is_read_only());
1431        assert!(project.collaborators().is_empty());
1432    });
1433}
1434
1435#[gpui::test(iterations = 10)]
1436async fn test_host_disconnect(
1437    deterministic: Arc<Deterministic>,
1438    cx_a: &mut TestAppContext,
1439    cx_b: &mut TestAppContext,
1440    cx_c: &mut TestAppContext,
1441) {
1442    deterministic.forbid_parking();
1443    let mut server = TestServer::start(&deterministic).await;
1444    let client_a = server.create_client(cx_a, "user_a").await;
1445    let client_b = server.create_client(cx_b, "user_b").await;
1446    let client_c = server.create_client(cx_c, "user_c").await;
1447    server
1448        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
1449        .await;
1450
1451    cx_b.update(editor::init);
1452
1453    client_a
1454        .fs
1455        .insert_tree(
1456            "/a",
1457            json!({
1458                "a.txt": "a-contents",
1459                "b.txt": "b-contents",
1460            }),
1461        )
1462        .await;
1463
1464    let active_call_a = cx_a.read(ActiveCall::global);
1465    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
1466    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1467    let project_id = active_call_a
1468        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1469        .await
1470        .unwrap();
1471
1472    let project_b = client_b.build_remote_project(project_id, cx_b).await;
1473    deterministic.run_until_parked();
1474    assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
1475
1476    let (window_id_b, workspace_b) =
1477        cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
1478    let editor_b = workspace_b
1479        .update(cx_b, |workspace, cx| {
1480            workspace.open_path((worktree_id, "b.txt"), None, true, cx)
1481        })
1482        .await
1483        .unwrap()
1484        .downcast::<Editor>()
1485        .unwrap();
1486    assert!(cx_b
1487        .read_window(window_id_b, |cx| editor_b.is_focused(cx))
1488        .unwrap());
1489    editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
1490    assert!(cx_b.is_window_edited(workspace_b.window_id()));
1491
1492    // Drop client A's connection. Collaborators should disappear and the project should not be shown as shared.
1493    server.forbid_connections();
1494    server.disconnect_client(client_a.peer_id().unwrap());
1495    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1496    project_a.read_with(cx_a, |project, _| project.collaborators().is_empty());
1497    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1498    project_b.read_with(cx_b, |project, _| project.is_read_only());
1499    assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
1500
1501    // Ensure client B's edited state is reset and that the whole window is blurred.
1502    cx_b.read_window(window_id_b, |cx| {
1503        assert_eq!(cx.focused_view_id(), None);
1504    });
1505    assert!(!cx_b.is_window_edited(workspace_b.window_id()));
1506
1507    // Ensure client B is not prompted to save edits when closing window after disconnecting.
1508    let can_close = workspace_b
1509        .update(cx_b, |workspace, cx| workspace.prepare_to_close(true, cx))
1510        .await
1511        .unwrap();
1512    assert!(can_close);
1513
1514    // Allow client A to reconnect to the server.
1515    server.allow_connections();
1516    deterministic.advance_clock(RECEIVE_TIMEOUT);
1517
1518    // Client B calls client A again after they reconnected.
1519    let active_call_b = cx_b.read(ActiveCall::global);
1520    active_call_b
1521        .update(cx_b, |call, cx| {
1522            call.invite(client_a.user_id().unwrap(), None, cx)
1523        })
1524        .await
1525        .unwrap();
1526    deterministic.run_until_parked();
1527    active_call_a
1528        .update(cx_a, |call, cx| call.accept_incoming(cx))
1529        .await
1530        .unwrap();
1531
1532    active_call_a
1533        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1534        .await
1535        .unwrap();
1536
1537    // Drop client A's connection again. We should still unshare it successfully.
1538    server.forbid_connections();
1539    server.disconnect_client(client_a.peer_id().unwrap());
1540    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
1541    project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
1542}
1543
1544#[gpui::test(iterations = 10)]
1545async fn test_project_reconnect(
1546    deterministic: Arc<Deterministic>,
1547    cx_a: &mut TestAppContext,
1548    cx_b: &mut TestAppContext,
1549) {
1550    deterministic.forbid_parking();
1551    let mut server = TestServer::start(&deterministic).await;
1552    let client_a = server.create_client(cx_a, "user_a").await;
1553    let client_b = server.create_client(cx_b, "user_b").await;
1554    server
1555        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
1556        .await;
1557
1558    cx_b.update(editor::init);
1559
1560    client_a
1561        .fs
1562        .insert_tree(
1563            "/root-1",
1564            json!({
1565                "dir1": {
1566                    "a.txt": "a",
1567                    "b.txt": "b",
1568                    "subdir1": {
1569                        "c.txt": "c",
1570                        "d.txt": "d",
1571                        "e.txt": "e",
1572                    }
1573                },
1574                "dir2": {
1575                    "v.txt": "v",
1576                },
1577                "dir3": {
1578                    "w.txt": "w",
1579                    "x.txt": "x",
1580                    "y.txt": "y",
1581                },
1582                "dir4": {
1583                    "z.txt": "z",
1584                },
1585            }),
1586        )
1587        .await;
1588    client_a
1589        .fs
1590        .insert_tree(
1591            "/root-2",
1592            json!({
1593                "2.txt": "2",
1594            }),
1595        )
1596        .await;
1597    client_a
1598        .fs
1599        .insert_tree(
1600            "/root-3",
1601            json!({
1602                "3.txt": "3",
1603            }),
1604        )
1605        .await;
1606
1607    let active_call_a = cx_a.read(ActiveCall::global);
1608    let (project_a1, _) = client_a.build_local_project("/root-1/dir1", cx_a).await;
1609    let (project_a2, _) = client_a.build_local_project("/root-2", cx_a).await;
1610    let (project_a3, _) = client_a.build_local_project("/root-3", cx_a).await;
1611    let worktree_a1 =
1612        project_a1.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
1613    let project1_id = active_call_a
1614        .update(cx_a, |call, cx| call.share_project(project_a1.clone(), cx))
1615        .await
1616        .unwrap();
1617    let project2_id = active_call_a
1618        .update(cx_a, |call, cx| call.share_project(project_a2.clone(), cx))
1619        .await
1620        .unwrap();
1621    let project3_id = active_call_a
1622        .update(cx_a, |call, cx| call.share_project(project_a3.clone(), cx))
1623        .await
1624        .unwrap();
1625
1626    let project_b1 = client_b.build_remote_project(project1_id, cx_b).await;
1627    let project_b2 = client_b.build_remote_project(project2_id, cx_b).await;
1628    let project_b3 = client_b.build_remote_project(project3_id, cx_b).await;
1629    deterministic.run_until_parked();
1630
1631    let worktree1_id = worktree_a1.read_with(cx_a, |worktree, _| {
1632        assert!(worktree.as_local().unwrap().is_shared());
1633        worktree.id()
1634    });
1635    let (worktree_a2, _) = project_a1
1636        .update(cx_a, |p, cx| {
1637            p.find_or_create_local_worktree("/root-1/dir2", true, cx)
1638        })
1639        .await
1640        .unwrap();
1641    deterministic.run_until_parked();
1642    let worktree2_id = worktree_a2.read_with(cx_a, |tree, _| {
1643        assert!(tree.as_local().unwrap().is_shared());
1644        tree.id()
1645    });
1646    deterministic.run_until_parked();
1647    project_b1.read_with(cx_b, |project, cx| {
1648        assert!(project.worktree_for_id(worktree2_id, cx).is_some())
1649    });
1650
1651    let buffer_a1 = project_a1
1652        .update(cx_a, |p, cx| p.open_buffer((worktree1_id, "a.txt"), cx))
1653        .await
1654        .unwrap();
1655    let buffer_b1 = project_b1
1656        .update(cx_b, |p, cx| p.open_buffer((worktree1_id, "a.txt"), cx))
1657        .await
1658        .unwrap();
1659
1660    // Drop client A's connection.
1661    server.forbid_connections();
1662    server.disconnect_client(client_a.peer_id().unwrap());
1663    deterministic.advance_clock(RECEIVE_TIMEOUT);
1664    project_a1.read_with(cx_a, |project, _| {
1665        assert!(project.is_shared());
1666        assert_eq!(project.collaborators().len(), 1);
1667    });
1668    project_b1.read_with(cx_b, |project, _| {
1669        assert!(!project.is_read_only());
1670        assert_eq!(project.collaborators().len(), 1);
1671    });
1672    worktree_a1.read_with(cx_a, |tree, _| {
1673        assert!(tree.as_local().unwrap().is_shared())
1674    });
1675
1676    // While client A is disconnected, add and remove files from client A's project.
1677    client_a
1678        .fs
1679        .insert_tree(
1680            "/root-1/dir1/subdir2",
1681            json!({
1682                "f.txt": "f-contents",
1683                "g.txt": "g-contents",
1684                "h.txt": "h-contents",
1685                "i.txt": "i-contents",
1686            }),
1687        )
1688        .await;
1689    client_a
1690        .fs
1691        .remove_dir(
1692            "/root-1/dir1/subdir1".as_ref(),
1693            RemoveOptions {
1694                recursive: true,
1695                ..Default::default()
1696            },
1697        )
1698        .await
1699        .unwrap();
1700
1701    // While client A is disconnected, add and remove worktrees from client A's project.
1702    project_a1.update(cx_a, |project, cx| {
1703        project.remove_worktree(worktree2_id, cx)
1704    });
1705    let (worktree_a3, _) = project_a1
1706        .update(cx_a, |p, cx| {
1707            p.find_or_create_local_worktree("/root-1/dir3", true, cx)
1708        })
1709        .await
1710        .unwrap();
1711    worktree_a3
1712        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
1713        .await;
1714    let worktree3_id = worktree_a3.read_with(cx_a, |tree, _| {
1715        assert!(!tree.as_local().unwrap().is_shared());
1716        tree.id()
1717    });
1718    deterministic.run_until_parked();
1719
1720    // While client A is disconnected, close project 2
1721    cx_a.update(|_| drop(project_a2));
1722
1723    // While client A is disconnected, mutate a buffer on both the host and the guest.
1724    buffer_a1.update(cx_a, |buf, cx| buf.edit([(0..0, "W")], None, cx));
1725    buffer_b1.update(cx_b, |buf, cx| buf.edit([(1..1, "Z")], None, cx));
1726    deterministic.run_until_parked();
1727
1728    // Client A reconnects. Their project is re-shared, and client B re-joins it.
1729    server.allow_connections();
1730    client_a
1731        .authenticate_and_connect(false, &cx_a.to_async())
1732        .await
1733        .unwrap();
1734    deterministic.run_until_parked();
1735    project_a1.read_with(cx_a, |project, cx| {
1736        assert!(project.is_shared());
1737        assert!(worktree_a1.read(cx).as_local().unwrap().is_shared());
1738        assert_eq!(
1739            worktree_a1
1740                .read(cx)
1741                .snapshot()
1742                .paths()
1743                .map(|p| p.to_str().unwrap())
1744                .collect::<Vec<_>>(),
1745            vec![
1746                "a.txt",
1747                "b.txt",
1748                "subdir2",
1749                "subdir2/f.txt",
1750                "subdir2/g.txt",
1751                "subdir2/h.txt",
1752                "subdir2/i.txt"
1753            ]
1754        );
1755        assert!(worktree_a3.read(cx).as_local().unwrap().is_shared());
1756        assert_eq!(
1757            worktree_a3
1758                .read(cx)
1759                .snapshot()
1760                .paths()
1761                .map(|p| p.to_str().unwrap())
1762                .collect::<Vec<_>>(),
1763            vec!["w.txt", "x.txt", "y.txt"]
1764        );
1765    });
1766    project_b1.read_with(cx_b, |project, cx| {
1767        assert!(!project.is_read_only());
1768        assert_eq!(
1769            project
1770                .worktree_for_id(worktree1_id, cx)
1771                .unwrap()
1772                .read(cx)
1773                .snapshot()
1774                .paths()
1775                .map(|p| p.to_str().unwrap())
1776                .collect::<Vec<_>>(),
1777            vec![
1778                "a.txt",
1779                "b.txt",
1780                "subdir2",
1781                "subdir2/f.txt",
1782                "subdir2/g.txt",
1783                "subdir2/h.txt",
1784                "subdir2/i.txt"
1785            ]
1786        );
1787        assert!(project.worktree_for_id(worktree2_id, cx).is_none());
1788        assert_eq!(
1789            project
1790                .worktree_for_id(worktree3_id, cx)
1791                .unwrap()
1792                .read(cx)
1793                .snapshot()
1794                .paths()
1795                .map(|p| p.to_str().unwrap())
1796                .collect::<Vec<_>>(),
1797            vec!["w.txt", "x.txt", "y.txt"]
1798        );
1799    });
1800    project_b2.read_with(cx_b, |project, _| assert!(project.is_read_only()));
1801    project_b3.read_with(cx_b, |project, _| assert!(!project.is_read_only()));
1802    buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WaZ"));
1803    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "WaZ"));
1804
1805    // Drop client B's connection.
1806    server.forbid_connections();
1807    server.disconnect_client(client_b.peer_id().unwrap());
1808    deterministic.advance_clock(RECEIVE_TIMEOUT);
1809
1810    // While client B is disconnected, add and remove files from client A's project
1811    client_a
1812        .fs
1813        .insert_file("/root-1/dir1/subdir2/j.txt", "j-contents".into())
1814        .await;
1815    client_a
1816        .fs
1817        .remove_file("/root-1/dir1/subdir2/i.txt".as_ref(), Default::default())
1818        .await
1819        .unwrap();
1820
1821    // While client B is disconnected, add and remove worktrees from client A's project.
1822    let (worktree_a4, _) = project_a1
1823        .update(cx_a, |p, cx| {
1824            p.find_or_create_local_worktree("/root-1/dir4", true, cx)
1825        })
1826        .await
1827        .unwrap();
1828    deterministic.run_until_parked();
1829    let worktree4_id = worktree_a4.read_with(cx_a, |tree, _| {
1830        assert!(tree.as_local().unwrap().is_shared());
1831        tree.id()
1832    });
1833    project_a1.update(cx_a, |project, cx| {
1834        project.remove_worktree(worktree3_id, cx)
1835    });
1836    deterministic.run_until_parked();
1837
1838    // While client B is disconnected, mutate a buffer on both the host and the guest.
1839    buffer_a1.update(cx_a, |buf, cx| buf.edit([(1..1, "X")], None, cx));
1840    buffer_b1.update(cx_b, |buf, cx| buf.edit([(2..2, "Y")], None, cx));
1841    deterministic.run_until_parked();
1842
1843    // While disconnected, close project 3
1844    cx_a.update(|_| drop(project_a3));
1845
1846    // Client B reconnects. They re-join the room and the remaining shared project.
1847    server.allow_connections();
1848    client_b
1849        .authenticate_and_connect(false, &cx_b.to_async())
1850        .await
1851        .unwrap();
1852    deterministic.run_until_parked();
1853    project_b1.read_with(cx_b, |project, cx| {
1854        assert!(!project.is_read_only());
1855        assert_eq!(
1856            project
1857                .worktree_for_id(worktree1_id, cx)
1858                .unwrap()
1859                .read(cx)
1860                .snapshot()
1861                .paths()
1862                .map(|p| p.to_str().unwrap())
1863                .collect::<Vec<_>>(),
1864            vec![
1865                "a.txt",
1866                "b.txt",
1867                "subdir2",
1868                "subdir2/f.txt",
1869                "subdir2/g.txt",
1870                "subdir2/h.txt",
1871                "subdir2/j.txt"
1872            ]
1873        );
1874        assert!(project.worktree_for_id(worktree2_id, cx).is_none());
1875        assert_eq!(
1876            project
1877                .worktree_for_id(worktree4_id, cx)
1878                .unwrap()
1879                .read(cx)
1880                .snapshot()
1881                .paths()
1882                .map(|p| p.to_str().unwrap())
1883                .collect::<Vec<_>>(),
1884            vec!["z.txt"]
1885        );
1886    });
1887    project_b3.read_with(cx_b, |project, _| assert!(project.is_read_only()));
1888    buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WXaYZ"));
1889    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "WXaYZ"));
1890}
1891
1892#[gpui::test(iterations = 10)]
1893async fn test_active_call_events(
1894    deterministic: Arc<Deterministic>,
1895    cx_a: &mut TestAppContext,
1896    cx_b: &mut TestAppContext,
1897) {
1898    deterministic.forbid_parking();
1899    let mut server = TestServer::start(&deterministic).await;
1900    let client_a = server.create_client(cx_a, "user_a").await;
1901    let client_b = server.create_client(cx_b, "user_b").await;
1902    client_a.fs.insert_tree("/a", json!({})).await;
1903    client_b.fs.insert_tree("/b", json!({})).await;
1904
1905    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
1906    let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
1907
1908    server
1909        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
1910        .await;
1911    let active_call_a = cx_a.read(ActiveCall::global);
1912    let active_call_b = cx_b.read(ActiveCall::global);
1913
1914    let events_a = active_call_events(cx_a);
1915    let events_b = active_call_events(cx_b);
1916
1917    let project_a_id = active_call_a
1918        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
1919        .await
1920        .unwrap();
1921    deterministic.run_until_parked();
1922    assert_eq!(mem::take(&mut *events_a.borrow_mut()), vec![]);
1923    assert_eq!(
1924        mem::take(&mut *events_b.borrow_mut()),
1925        vec![room::Event::RemoteProjectShared {
1926            owner: Arc::new(User {
1927                id: client_a.user_id().unwrap(),
1928                github_login: "user_a".to_string(),
1929                avatar: None,
1930            }),
1931            project_id: project_a_id,
1932            worktree_root_names: vec!["a".to_string()],
1933        }]
1934    );
1935
1936    let project_b_id = active_call_b
1937        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
1938        .await
1939        .unwrap();
1940    deterministic.run_until_parked();
1941    assert_eq!(
1942        mem::take(&mut *events_a.borrow_mut()),
1943        vec![room::Event::RemoteProjectShared {
1944            owner: Arc::new(User {
1945                id: client_b.user_id().unwrap(),
1946                github_login: "user_b".to_string(),
1947                avatar: None,
1948            }),
1949            project_id: project_b_id,
1950            worktree_root_names: vec!["b".to_string()]
1951        }]
1952    );
1953    assert_eq!(mem::take(&mut *events_b.borrow_mut()), vec![]);
1954
1955    // Sharing a project twice is idempotent.
1956    let project_b_id_2 = active_call_b
1957        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
1958        .await
1959        .unwrap();
1960    assert_eq!(project_b_id_2, project_b_id);
1961    deterministic.run_until_parked();
1962    assert_eq!(mem::take(&mut *events_a.borrow_mut()), vec![]);
1963    assert_eq!(mem::take(&mut *events_b.borrow_mut()), vec![]);
1964}
1965
1966fn active_call_events(cx: &mut TestAppContext) -> Rc<RefCell<Vec<room::Event>>> {
1967    let events = Rc::new(RefCell::new(Vec::new()));
1968    let active_call = cx.read(ActiveCall::global);
1969    cx.update({
1970        let events = events.clone();
1971        |cx| {
1972            cx.subscribe(&active_call, move |_, event, _| {
1973                events.borrow_mut().push(event.clone())
1974            })
1975            .detach()
1976        }
1977    });
1978    events
1979}
1980
1981#[gpui::test(iterations = 10)]
1982async fn test_room_location(
1983    deterministic: Arc<Deterministic>,
1984    cx_a: &mut TestAppContext,
1985    cx_b: &mut TestAppContext,
1986) {
1987    deterministic.forbid_parking();
1988    let mut server = TestServer::start(&deterministic).await;
1989    let client_a = server.create_client(cx_a, "user_a").await;
1990    let client_b = server.create_client(cx_b, "user_b").await;
1991    client_a.fs.insert_tree("/a", json!({})).await;
1992    client_b.fs.insert_tree("/b", json!({})).await;
1993
1994    let active_call_a = cx_a.read(ActiveCall::global);
1995    let active_call_b = cx_b.read(ActiveCall::global);
1996
1997    let a_notified = Rc::new(Cell::new(false));
1998    cx_a.update({
1999        let notified = a_notified.clone();
2000        |cx| {
2001            cx.observe(&active_call_a, move |_, _| notified.set(true))
2002                .detach()
2003        }
2004    });
2005
2006    let b_notified = Rc::new(Cell::new(false));
2007    cx_b.update({
2008        let b_notified = b_notified.clone();
2009        |cx| {
2010            cx.observe(&active_call_b, move |_, _| b_notified.set(true))
2011                .detach()
2012        }
2013    });
2014
2015    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
2016    active_call_a
2017        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
2018        .await
2019        .unwrap();
2020    let (project_b, _) = client_b.build_local_project("/b", cx_b).await;
2021
2022    server
2023        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2024        .await;
2025    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
2026    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
2027    deterministic.run_until_parked();
2028    assert!(a_notified.take());
2029    assert_eq!(
2030        participant_locations(&room_a, cx_a),
2031        vec![("user_b".to_string(), ParticipantLocation::External)]
2032    );
2033    assert!(b_notified.take());
2034    assert_eq!(
2035        participant_locations(&room_b, cx_b),
2036        vec![("user_a".to_string(), ParticipantLocation::UnsharedProject)]
2037    );
2038
2039    let project_a_id = active_call_a
2040        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2041        .await
2042        .unwrap();
2043    deterministic.run_until_parked();
2044    assert!(a_notified.take());
2045    assert_eq!(
2046        participant_locations(&room_a, cx_a),
2047        vec![("user_b".to_string(), ParticipantLocation::External)]
2048    );
2049    assert!(b_notified.take());
2050    assert_eq!(
2051        participant_locations(&room_b, cx_b),
2052        vec![(
2053            "user_a".to_string(),
2054            ParticipantLocation::SharedProject {
2055                project_id: project_a_id
2056            }
2057        )]
2058    );
2059
2060    let project_b_id = active_call_b
2061        .update(cx_b, |call, cx| call.share_project(project_b.clone(), cx))
2062        .await
2063        .unwrap();
2064    deterministic.run_until_parked();
2065    assert!(a_notified.take());
2066    assert_eq!(
2067        participant_locations(&room_a, cx_a),
2068        vec![("user_b".to_string(), ParticipantLocation::External)]
2069    );
2070    assert!(b_notified.take());
2071    assert_eq!(
2072        participant_locations(&room_b, cx_b),
2073        vec![(
2074            "user_a".to_string(),
2075            ParticipantLocation::SharedProject {
2076                project_id: project_a_id
2077            }
2078        )]
2079    );
2080
2081    active_call_b
2082        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
2083        .await
2084        .unwrap();
2085    deterministic.run_until_parked();
2086    assert!(a_notified.take());
2087    assert_eq!(
2088        participant_locations(&room_a, cx_a),
2089        vec![(
2090            "user_b".to_string(),
2091            ParticipantLocation::SharedProject {
2092                project_id: project_b_id
2093            }
2094        )]
2095    );
2096    assert!(b_notified.take());
2097    assert_eq!(
2098        participant_locations(&room_b, cx_b),
2099        vec![(
2100            "user_a".to_string(),
2101            ParticipantLocation::SharedProject {
2102                project_id: project_a_id
2103            }
2104        )]
2105    );
2106
2107    active_call_b
2108        .update(cx_b, |call, cx| call.set_location(None, cx))
2109        .await
2110        .unwrap();
2111    deterministic.run_until_parked();
2112    assert!(a_notified.take());
2113    assert_eq!(
2114        participant_locations(&room_a, cx_a),
2115        vec![("user_b".to_string(), ParticipantLocation::External)]
2116    );
2117    assert!(b_notified.take());
2118    assert_eq!(
2119        participant_locations(&room_b, cx_b),
2120        vec![(
2121            "user_a".to_string(),
2122            ParticipantLocation::SharedProject {
2123                project_id: project_a_id
2124            }
2125        )]
2126    );
2127
2128    fn participant_locations(
2129        room: &ModelHandle<Room>,
2130        cx: &TestAppContext,
2131    ) -> Vec<(String, ParticipantLocation)> {
2132        room.read_with(cx, |room, _| {
2133            room.remote_participants()
2134                .values()
2135                .map(|participant| {
2136                    (
2137                        participant.user.github_login.to_string(),
2138                        participant.location,
2139                    )
2140                })
2141                .collect()
2142        })
2143    }
2144}
2145
2146#[gpui::test(iterations = 10)]
2147async fn test_propagate_saves_and_fs_changes(
2148    deterministic: Arc<Deterministic>,
2149    cx_a: &mut TestAppContext,
2150    cx_b: &mut TestAppContext,
2151    cx_c: &mut TestAppContext,
2152) {
2153    deterministic.forbid_parking();
2154    let mut server = TestServer::start(&deterministic).await;
2155    let client_a = server.create_client(cx_a, "user_a").await;
2156    let client_b = server.create_client(cx_b, "user_b").await;
2157    let client_c = server.create_client(cx_c, "user_c").await;
2158
2159    server
2160        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
2161        .await;
2162    let active_call_a = cx_a.read(ActiveCall::global);
2163
2164    let rust = Arc::new(Language::new(
2165        LanguageConfig {
2166            name: "Rust".into(),
2167            path_suffixes: vec!["rs".to_string()],
2168            ..Default::default()
2169        },
2170        Some(tree_sitter_rust::language()),
2171    ));
2172    let javascript = Arc::new(Language::new(
2173        LanguageConfig {
2174            name: "JavaScript".into(),
2175            path_suffixes: vec!["js".to_string()],
2176            ..Default::default()
2177        },
2178        Some(tree_sitter_rust::language()),
2179    ));
2180    for client in [&client_a, &client_b, &client_c] {
2181        client.language_registry.add(rust.clone());
2182        client.language_registry.add(javascript.clone());
2183    }
2184
2185    client_a
2186        .fs
2187        .insert_tree(
2188            "/a",
2189            json!({
2190                "file1.rs": "",
2191                "file2": ""
2192            }),
2193        )
2194        .await;
2195    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
2196    let worktree_a = project_a.read_with(cx_a, |p, cx| p.worktrees(cx).next().unwrap());
2197    let project_id = active_call_a
2198        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2199        .await
2200        .unwrap();
2201
2202    // Join that worktree as clients B and C.
2203    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2204    let project_c = client_c.build_remote_project(project_id, cx_c).await;
2205    let worktree_b = project_b.read_with(cx_b, |p, cx| p.worktrees(cx).next().unwrap());
2206    let worktree_c = project_c.read_with(cx_c, |p, cx| p.worktrees(cx).next().unwrap());
2207
2208    // Open and edit a buffer as both guests B and C.
2209    let buffer_b = project_b
2210        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2211        .await
2212        .unwrap();
2213    let buffer_c = project_c
2214        .update(cx_c, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2215        .await
2216        .unwrap();
2217    buffer_b.read_with(cx_b, |buffer, _| {
2218        assert_eq!(&*buffer.language().unwrap().name(), "Rust");
2219    });
2220    buffer_c.read_with(cx_c, |buffer, _| {
2221        assert_eq!(&*buffer.language().unwrap().name(), "Rust");
2222    });
2223    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "i-am-b, ")], None, cx));
2224    buffer_c.update(cx_c, |buf, cx| buf.edit([(0..0, "i-am-c, ")], None, cx));
2225
2226    // Open and edit that buffer as the host.
2227    let buffer_a = project_a
2228        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "file1.rs"), cx))
2229        .await
2230        .unwrap();
2231
2232    deterministic.run_until_parked();
2233    buffer_a.read_with(cx_a, |buf, _| assert_eq!(buf.text(), "i-am-c, i-am-b, "));
2234    buffer_a.update(cx_a, |buf, cx| {
2235        buf.edit([(buf.len()..buf.len(), "i-am-a")], None, cx)
2236    });
2237
2238    deterministic.run_until_parked();
2239    buffer_a.read_with(cx_a, |buf, _| {
2240        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2241    });
2242    buffer_b.read_with(cx_b, |buf, _| {
2243        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2244    });
2245    buffer_c.read_with(cx_c, |buf, _| {
2246        assert_eq!(buf.text(), "i-am-c, i-am-b, i-am-a");
2247    });
2248
2249    // Edit the buffer as the host and concurrently save as guest B.
2250    let save_b = project_b.update(cx_b, |project, cx| {
2251        project.save_buffer(buffer_b.clone(), cx)
2252    });
2253    buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "hi-a, ")], None, cx));
2254    save_b.await.unwrap();
2255    assert_eq!(
2256        client_a.fs.load("/a/file1.rs".as_ref()).await.unwrap(),
2257        "hi-a, i-am-c, i-am-b, i-am-a"
2258    );
2259
2260    deterministic.run_until_parked();
2261    buffer_a.read_with(cx_a, |buf, _| assert!(!buf.is_dirty()));
2262    buffer_b.read_with(cx_b, |buf, _| assert!(!buf.is_dirty()));
2263    buffer_c.read_with(cx_c, |buf, _| assert!(!buf.is_dirty()));
2264
2265    // Make changes on host's file system, see those changes on guest worktrees.
2266    client_a
2267        .fs
2268        .rename(
2269            "/a/file1.rs".as_ref(),
2270            "/a/file1.js".as_ref(),
2271            Default::default(),
2272        )
2273        .await
2274        .unwrap();
2275    client_a
2276        .fs
2277        .rename("/a/file2".as_ref(), "/a/file3".as_ref(), Default::default())
2278        .await
2279        .unwrap();
2280    client_a.fs.insert_file("/a/file4", "4".into()).await;
2281    deterministic.run_until_parked();
2282
2283    worktree_a.read_with(cx_a, |tree, _| {
2284        assert_eq!(
2285            tree.paths()
2286                .map(|p| p.to_string_lossy())
2287                .collect::<Vec<_>>(),
2288            ["file1.js", "file3", "file4"]
2289        )
2290    });
2291    worktree_b.read_with(cx_b, |tree, _| {
2292        assert_eq!(
2293            tree.paths()
2294                .map(|p| p.to_string_lossy())
2295                .collect::<Vec<_>>(),
2296            ["file1.js", "file3", "file4"]
2297        )
2298    });
2299    worktree_c.read_with(cx_c, |tree, _| {
2300        assert_eq!(
2301            tree.paths()
2302                .map(|p| p.to_string_lossy())
2303                .collect::<Vec<_>>(),
2304            ["file1.js", "file3", "file4"]
2305        )
2306    });
2307
2308    // Ensure buffer files are updated as well.
2309    buffer_a.read_with(cx_a, |buffer, _| {
2310        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2311        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2312    });
2313    buffer_b.read_with(cx_b, |buffer, _| {
2314        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2315        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2316    });
2317    buffer_c.read_with(cx_c, |buffer, _| {
2318        assert_eq!(buffer.file().unwrap().path().to_str(), Some("file1.js"));
2319        assert_eq!(&*buffer.language().unwrap().name(), "JavaScript");
2320    });
2321
2322    let new_buffer_a = project_a
2323        .update(cx_a, |p, cx| p.create_buffer("", None, cx))
2324        .unwrap();
2325    let new_buffer_id = new_buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
2326    let new_buffer_b = project_b
2327        .update(cx_b, |p, cx| p.open_buffer_by_id(new_buffer_id, cx))
2328        .await
2329        .unwrap();
2330    new_buffer_b.read_with(cx_b, |buffer, _| {
2331        assert!(buffer.file().is_none());
2332    });
2333
2334    new_buffer_a.update(cx_a, |buffer, cx| {
2335        buffer.edit([(0..0, "ok")], None, cx);
2336    });
2337    project_a
2338        .update(cx_a, |project, cx| {
2339            project.save_buffer_as(new_buffer_a.clone(), "/a/file3.rs".into(), cx)
2340        })
2341        .await
2342        .unwrap();
2343
2344    deterministic.run_until_parked();
2345    new_buffer_b.read_with(cx_b, |buffer_b, _| {
2346        assert_eq!(
2347            buffer_b.file().unwrap().path().as_ref(),
2348            Path::new("file3.rs")
2349        );
2350
2351        new_buffer_a.read_with(cx_a, |buffer_a, _| {
2352            assert_eq!(buffer_b.saved_mtime(), buffer_a.saved_mtime());
2353            assert_eq!(buffer_b.saved_version(), buffer_a.saved_version());
2354        });
2355    });
2356}
2357
2358#[gpui::test(iterations = 10)]
2359async fn test_git_diff_base_change(
2360    deterministic: Arc<Deterministic>,
2361    cx_a: &mut TestAppContext,
2362    cx_b: &mut TestAppContext,
2363) {
2364    deterministic.forbid_parking();
2365    let mut server = TestServer::start(&deterministic).await;
2366    let client_a = server.create_client(cx_a, "user_a").await;
2367    let client_b = server.create_client(cx_b, "user_b").await;
2368    server
2369        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2370        .await;
2371    let active_call_a = cx_a.read(ActiveCall::global);
2372
2373    client_a
2374        .fs
2375        .insert_tree(
2376            "/dir",
2377            json!({
2378            ".git": {},
2379            "sub": {
2380                ".git": {},
2381                "b.txt": "
2382                    one
2383                    two
2384                    three
2385                ".unindent(),
2386            },
2387            "a.txt": "
2388                    one
2389                    two
2390                    three
2391                ".unindent(),
2392            }),
2393        )
2394        .await;
2395
2396    let (project_local, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2397    let project_id = active_call_a
2398        .update(cx_a, |call, cx| {
2399            call.share_project(project_local.clone(), cx)
2400        })
2401        .await
2402        .unwrap();
2403
2404    let project_remote = client_b.build_remote_project(project_id, cx_b).await;
2405
2406    let diff_base = "
2407        one
2408        three
2409    "
2410    .unindent();
2411
2412    let new_diff_base = "
2413        one
2414        two
2415    "
2416    .unindent();
2417
2418    client_a.fs.as_fake().set_index_for_repo(
2419        Path::new("/dir/.git"),
2420        &[(Path::new("a.txt"), diff_base.clone())],
2421    );
2422
2423    // Create the buffer
2424    let buffer_local_a = project_local
2425        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2426        .await
2427        .unwrap();
2428
2429    // Wait for it to catch up to the new diff
2430    deterministic.run_until_parked();
2431
2432    // Smoke test diffing
2433    buffer_local_a.read_with(cx_a, |buffer, _| {
2434        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2435        git::diff::assert_hunks(
2436            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2437            &buffer,
2438            &diff_base,
2439            &[(1..2, "", "two\n")],
2440        );
2441    });
2442
2443    // Create remote buffer
2444    let buffer_remote_a = project_remote
2445        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
2446        .await
2447        .unwrap();
2448
2449    // Wait remote buffer to catch up to the new diff
2450    deterministic.run_until_parked();
2451
2452    // Smoke test diffing
2453    buffer_remote_a.read_with(cx_b, |buffer, _| {
2454        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2455        git::diff::assert_hunks(
2456            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2457            &buffer,
2458            &diff_base,
2459            &[(1..2, "", "two\n")],
2460        );
2461    });
2462
2463    client_a.fs.as_fake().set_index_for_repo(
2464        Path::new("/dir/.git"),
2465        &[(Path::new("a.txt"), new_diff_base.clone())],
2466    );
2467
2468    // Wait for buffer_local_a to receive it
2469    deterministic.run_until_parked();
2470
2471    // Smoke test new diffing
2472    buffer_local_a.read_with(cx_a, |buffer, _| {
2473        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2474
2475        git::diff::assert_hunks(
2476            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2477            &buffer,
2478            &diff_base,
2479            &[(2..3, "", "three\n")],
2480        );
2481    });
2482
2483    // Smoke test B
2484    buffer_remote_a.read_with(cx_b, |buffer, _| {
2485        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2486        git::diff::assert_hunks(
2487            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2488            &buffer,
2489            &diff_base,
2490            &[(2..3, "", "three\n")],
2491        );
2492    });
2493
2494    //Nested git dir
2495
2496    let diff_base = "
2497        one
2498        three
2499    "
2500    .unindent();
2501
2502    let new_diff_base = "
2503        one
2504        two
2505    "
2506    .unindent();
2507
2508    client_a.fs.as_fake().set_index_for_repo(
2509        Path::new("/dir/sub/.git"),
2510        &[(Path::new("b.txt"), diff_base.clone())],
2511    );
2512
2513    // Create the buffer
2514    let buffer_local_b = project_local
2515        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
2516        .await
2517        .unwrap();
2518
2519    // Wait for it to catch up to the new diff
2520    deterministic.run_until_parked();
2521
2522    // Smoke test diffing
2523    buffer_local_b.read_with(cx_a, |buffer, _| {
2524        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2525        git::diff::assert_hunks(
2526            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2527            &buffer,
2528            &diff_base,
2529            &[(1..2, "", "two\n")],
2530        );
2531    });
2532
2533    // Create remote buffer
2534    let buffer_remote_b = project_remote
2535        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "sub/b.txt"), cx))
2536        .await
2537        .unwrap();
2538
2539    // Wait remote buffer to catch up to the new diff
2540    deterministic.run_until_parked();
2541
2542    // Smoke test diffing
2543    buffer_remote_b.read_with(cx_b, |buffer, _| {
2544        assert_eq!(buffer.diff_base(), Some(diff_base.as_ref()));
2545        git::diff::assert_hunks(
2546            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2547            &buffer,
2548            &diff_base,
2549            &[(1..2, "", "two\n")],
2550        );
2551    });
2552
2553    client_a.fs.as_fake().set_index_for_repo(
2554        Path::new("/dir/sub/.git"),
2555        &[(Path::new("b.txt"), new_diff_base.clone())],
2556    );
2557
2558    // Wait for buffer_local_b to receive it
2559    deterministic.run_until_parked();
2560
2561    // Smoke test new diffing
2562    buffer_local_b.read_with(cx_a, |buffer, _| {
2563        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2564        println!("{:?}", buffer.as_rope().to_string());
2565        println!("{:?}", buffer.diff_base());
2566        println!(
2567            "{:?}",
2568            buffer
2569                .snapshot()
2570                .git_diff_hunks_in_row_range(0..4)
2571                .collect::<Vec<_>>()
2572        );
2573
2574        git::diff::assert_hunks(
2575            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2576            &buffer,
2577            &diff_base,
2578            &[(2..3, "", "three\n")],
2579        );
2580    });
2581
2582    // Smoke test B
2583    buffer_remote_b.read_with(cx_b, |buffer, _| {
2584        assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref()));
2585        git::diff::assert_hunks(
2586            buffer.snapshot().git_diff_hunks_in_row_range(0..4),
2587            &buffer,
2588            &diff_base,
2589            &[(2..3, "", "three\n")],
2590        );
2591    });
2592}
2593
2594#[gpui::test]
2595async fn test_git_branch_name(
2596    deterministic: Arc<Deterministic>,
2597    cx_a: &mut TestAppContext,
2598    cx_b: &mut TestAppContext,
2599    cx_c: &mut TestAppContext,
2600) {
2601    deterministic.forbid_parking();
2602    let mut server = TestServer::start(&deterministic).await;
2603    let client_a = server.create_client(cx_a, "user_a").await;
2604    let client_b = server.create_client(cx_b, "user_b").await;
2605    let client_c = server.create_client(cx_c, "user_c").await;
2606    server
2607        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
2608        .await;
2609    let active_call_a = cx_a.read(ActiveCall::global);
2610
2611    client_a
2612        .fs
2613        .insert_tree(
2614            "/dir",
2615            json!({
2616            ".git": {},
2617            }),
2618        )
2619        .await;
2620
2621    let (project_local, _worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2622    let project_id = active_call_a
2623        .update(cx_a, |call, cx| {
2624            call.share_project(project_local.clone(), cx)
2625        })
2626        .await
2627        .unwrap();
2628
2629    let project_remote = client_b.build_remote_project(project_id, cx_b).await;
2630    client_a
2631        .fs
2632        .as_fake()
2633        .set_branch_name(Path::new("/dir/.git"), Some("branch-1"));
2634
2635    // Wait for it to catch up to the new branch
2636    deterministic.run_until_parked();
2637
2638    #[track_caller]
2639    fn assert_branch(branch_name: Option<impl Into<String>>, project: &Project, cx: &AppContext) {
2640        let branch_name = branch_name.map(Into::into);
2641        let worktrees = project.visible_worktrees(cx).collect::<Vec<_>>();
2642        assert_eq!(worktrees.len(), 1);
2643        let worktree = worktrees[0].clone();
2644        let root_entry = worktree.read(cx).snapshot().root_git_entry().unwrap();
2645        assert_eq!(root_entry.branch(), branch_name.map(Into::into));
2646    }
2647
2648    // Smoke test branch reading
2649    project_local.read_with(cx_a, |project, cx| {
2650        assert_branch(Some("branch-1"), project, cx)
2651    });
2652    project_remote.read_with(cx_b, |project, cx| {
2653        assert_branch(Some("branch-1"), project, cx)
2654    });
2655
2656    client_a
2657        .fs
2658        .as_fake()
2659        .set_branch_name(Path::new("/dir/.git"), Some("branch-2"));
2660
2661    // Wait for buffer_local_a to receive it
2662    deterministic.run_until_parked();
2663
2664    // Smoke test branch reading
2665    project_local.read_with(cx_a, |project, cx| {
2666        assert_branch(Some("branch-2"), project, cx)
2667    });
2668    project_remote.read_with(cx_b, |project, cx| {
2669        assert_branch(Some("branch-2"), project, cx)
2670    });
2671
2672    let project_remote_c = client_c.build_remote_project(project_id, cx_c).await;
2673    deterministic.run_until_parked();
2674    project_remote_c.read_with(cx_c, |project, cx| {
2675        assert_branch(Some("branch-2"), project, cx)
2676    });
2677}
2678
2679#[gpui::test]
2680async fn test_git_status_sync(
2681    deterministic: Arc<Deterministic>,
2682    cx_a: &mut TestAppContext,
2683    cx_b: &mut TestAppContext,
2684    cx_c: &mut TestAppContext,
2685) {
2686    deterministic.forbid_parking();
2687    let mut server = TestServer::start(&deterministic).await;
2688    let client_a = server.create_client(cx_a, "user_a").await;
2689    let client_b = server.create_client(cx_b, "user_b").await;
2690    let client_c = server.create_client(cx_c, "user_c").await;
2691    server
2692        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
2693        .await;
2694    let active_call_a = cx_a.read(ActiveCall::global);
2695
2696    client_a
2697        .fs
2698        .insert_tree(
2699            "/dir",
2700            json!({
2701            ".git": {},
2702            "a.txt": "a",
2703            "b.txt": "b",
2704            }),
2705        )
2706        .await;
2707
2708    const A_TXT: &'static str = "a.txt";
2709    const B_TXT: &'static str = "b.txt";
2710
2711    client_a.fs.as_fake().set_status_for_repo_via_git_operation(
2712        Path::new("/dir/.git"),
2713        &[
2714            (&Path::new(A_TXT), GitFileStatus::Added),
2715            (&Path::new(B_TXT), GitFileStatus::Added),
2716        ],
2717    );
2718
2719    let (project_local, _worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2720    let project_id = active_call_a
2721        .update(cx_a, |call, cx| {
2722            call.share_project(project_local.clone(), cx)
2723        })
2724        .await
2725        .unwrap();
2726
2727    let project_remote = client_b.build_remote_project(project_id, cx_b).await;
2728
2729    // Wait for it to catch up to the new status
2730    deterministic.run_until_parked();
2731
2732    #[track_caller]
2733    fn assert_status(
2734        file: &impl AsRef<Path>,
2735        status: Option<GitFileStatus>,
2736        project: &Project,
2737        cx: &AppContext,
2738    ) {
2739        let file = file.as_ref();
2740        let worktrees = project.visible_worktrees(cx).collect::<Vec<_>>();
2741        assert_eq!(worktrees.len(), 1);
2742        let worktree = worktrees[0].clone();
2743        let snapshot = worktree.read(cx).snapshot();
2744        assert_eq!(snapshot.status_for_file(file), status);
2745    }
2746
2747    // Smoke test status reading
2748    project_local.read_with(cx_a, |project, cx| {
2749        assert_status(&Path::new(A_TXT), Some(GitFileStatus::Added), project, cx);
2750        assert_status(&Path::new(B_TXT), Some(GitFileStatus::Added), project, cx);
2751    });
2752    project_remote.read_with(cx_b, |project, cx| {
2753        assert_status(&Path::new(A_TXT), Some(GitFileStatus::Added), project, cx);
2754        assert_status(&Path::new(B_TXT), Some(GitFileStatus::Added), project, cx);
2755    });
2756
2757    client_a
2758        .fs
2759        .as_fake()
2760        .set_status_for_repo_via_working_copy_change(
2761            Path::new("/dir/.git"),
2762            &[
2763                (&Path::new(A_TXT), GitFileStatus::Modified),
2764                (&Path::new(B_TXT), GitFileStatus::Modified),
2765            ],
2766        );
2767
2768    // Wait for buffer_local_a to receive it
2769    deterministic.run_until_parked();
2770
2771    // Smoke test status reading
2772    project_local.read_with(cx_a, |project, cx| {
2773        assert_status(
2774            &Path::new(A_TXT),
2775            Some(GitFileStatus::Modified),
2776            project,
2777            cx,
2778        );
2779        assert_status(
2780            &Path::new(B_TXT),
2781            Some(GitFileStatus::Modified),
2782            project,
2783            cx,
2784        );
2785    });
2786    project_remote.read_with(cx_b, |project, cx| {
2787        assert_status(
2788            &Path::new(A_TXT),
2789            Some(GitFileStatus::Modified),
2790            project,
2791            cx,
2792        );
2793        assert_status(
2794            &Path::new(B_TXT),
2795            Some(GitFileStatus::Modified),
2796            project,
2797            cx,
2798        );
2799    });
2800
2801    // And synchronization while joining
2802    let project_remote_c = client_c.build_remote_project(project_id, cx_c).await;
2803    deterministic.run_until_parked();
2804
2805    project_remote_c.read_with(cx_c, |project, cx| {
2806        assert_status(
2807            &Path::new(A_TXT),
2808            Some(GitFileStatus::Modified),
2809            project,
2810            cx,
2811        );
2812        assert_status(
2813            &Path::new(B_TXT),
2814            Some(GitFileStatus::Modified),
2815            project,
2816            cx,
2817        );
2818    });
2819}
2820
2821#[gpui::test(iterations = 10)]
2822async fn test_fs_operations(
2823    deterministic: Arc<Deterministic>,
2824    cx_a: &mut TestAppContext,
2825    cx_b: &mut TestAppContext,
2826) {
2827    deterministic.forbid_parking();
2828    let mut server = TestServer::start(&deterministic).await;
2829    let client_a = server.create_client(cx_a, "user_a").await;
2830    let client_b = server.create_client(cx_b, "user_b").await;
2831    server
2832        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
2833        .await;
2834    let active_call_a = cx_a.read(ActiveCall::global);
2835
2836    client_a
2837        .fs
2838        .insert_tree(
2839            "/dir",
2840            json!({
2841                "a.txt": "a-contents",
2842                "b.txt": "b-contents",
2843            }),
2844        )
2845        .await;
2846    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
2847    let project_id = active_call_a
2848        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
2849        .await
2850        .unwrap();
2851    let project_b = client_b.build_remote_project(project_id, cx_b).await;
2852
2853    let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
2854    let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
2855
2856    let entry = project_b
2857        .update(cx_b, |project, cx| {
2858            project
2859                .create_entry((worktree_id, "c.txt"), false, cx)
2860                .unwrap()
2861        })
2862        .await
2863        .unwrap();
2864    worktree_a.read_with(cx_a, |worktree, _| {
2865        assert_eq!(
2866            worktree
2867                .paths()
2868                .map(|p| p.to_string_lossy())
2869                .collect::<Vec<_>>(),
2870            ["a.txt", "b.txt", "c.txt"]
2871        );
2872    });
2873    worktree_b.read_with(cx_b, |worktree, _| {
2874        assert_eq!(
2875            worktree
2876                .paths()
2877                .map(|p| p.to_string_lossy())
2878                .collect::<Vec<_>>(),
2879            ["a.txt", "b.txt", "c.txt"]
2880        );
2881    });
2882
2883    project_b
2884        .update(cx_b, |project, cx| {
2885            project.rename_entry(entry.id, Path::new("d.txt"), cx)
2886        })
2887        .unwrap()
2888        .await
2889        .unwrap();
2890    worktree_a.read_with(cx_a, |worktree, _| {
2891        assert_eq!(
2892            worktree
2893                .paths()
2894                .map(|p| p.to_string_lossy())
2895                .collect::<Vec<_>>(),
2896            ["a.txt", "b.txt", "d.txt"]
2897        );
2898    });
2899    worktree_b.read_with(cx_b, |worktree, _| {
2900        assert_eq!(
2901            worktree
2902                .paths()
2903                .map(|p| p.to_string_lossy())
2904                .collect::<Vec<_>>(),
2905            ["a.txt", "b.txt", "d.txt"]
2906        );
2907    });
2908
2909    let dir_entry = project_b
2910        .update(cx_b, |project, cx| {
2911            project
2912                .create_entry((worktree_id, "DIR"), true, cx)
2913                .unwrap()
2914        })
2915        .await
2916        .unwrap();
2917    worktree_a.read_with(cx_a, |worktree, _| {
2918        assert_eq!(
2919            worktree
2920                .paths()
2921                .map(|p| p.to_string_lossy())
2922                .collect::<Vec<_>>(),
2923            ["DIR", "a.txt", "b.txt", "d.txt"]
2924        );
2925    });
2926    worktree_b.read_with(cx_b, |worktree, _| {
2927        assert_eq!(
2928            worktree
2929                .paths()
2930                .map(|p| p.to_string_lossy())
2931                .collect::<Vec<_>>(),
2932            ["DIR", "a.txt", "b.txt", "d.txt"]
2933        );
2934    });
2935
2936    project_b
2937        .update(cx_b, |project, cx| {
2938            project
2939                .create_entry((worktree_id, "DIR/e.txt"), false, cx)
2940                .unwrap()
2941        })
2942        .await
2943        .unwrap();
2944    project_b
2945        .update(cx_b, |project, cx| {
2946            project
2947                .create_entry((worktree_id, "DIR/SUBDIR"), true, cx)
2948                .unwrap()
2949        })
2950        .await
2951        .unwrap();
2952    project_b
2953        .update(cx_b, |project, cx| {
2954            project
2955                .create_entry((worktree_id, "DIR/SUBDIR/f.txt"), false, cx)
2956                .unwrap()
2957        })
2958        .await
2959        .unwrap();
2960    worktree_a.read_with(cx_a, |worktree, _| {
2961        assert_eq!(
2962            worktree
2963                .paths()
2964                .map(|p| p.to_string_lossy())
2965                .collect::<Vec<_>>(),
2966            [
2967                "DIR",
2968                "DIR/SUBDIR",
2969                "DIR/SUBDIR/f.txt",
2970                "DIR/e.txt",
2971                "a.txt",
2972                "b.txt",
2973                "d.txt"
2974            ]
2975        );
2976    });
2977    worktree_b.read_with(cx_b, |worktree, _| {
2978        assert_eq!(
2979            worktree
2980                .paths()
2981                .map(|p| p.to_string_lossy())
2982                .collect::<Vec<_>>(),
2983            [
2984                "DIR",
2985                "DIR/SUBDIR",
2986                "DIR/SUBDIR/f.txt",
2987                "DIR/e.txt",
2988                "a.txt",
2989                "b.txt",
2990                "d.txt"
2991            ]
2992        );
2993    });
2994
2995    project_b
2996        .update(cx_b, |project, cx| {
2997            project
2998                .copy_entry(entry.id, Path::new("f.txt"), cx)
2999                .unwrap()
3000        })
3001        .await
3002        .unwrap();
3003    worktree_a.read_with(cx_a, |worktree, _| {
3004        assert_eq!(
3005            worktree
3006                .paths()
3007                .map(|p| p.to_string_lossy())
3008                .collect::<Vec<_>>(),
3009            [
3010                "DIR",
3011                "DIR/SUBDIR",
3012                "DIR/SUBDIR/f.txt",
3013                "DIR/e.txt",
3014                "a.txt",
3015                "b.txt",
3016                "d.txt",
3017                "f.txt"
3018            ]
3019        );
3020    });
3021    worktree_b.read_with(cx_b, |worktree, _| {
3022        assert_eq!(
3023            worktree
3024                .paths()
3025                .map(|p| p.to_string_lossy())
3026                .collect::<Vec<_>>(),
3027            [
3028                "DIR",
3029                "DIR/SUBDIR",
3030                "DIR/SUBDIR/f.txt",
3031                "DIR/e.txt",
3032                "a.txt",
3033                "b.txt",
3034                "d.txt",
3035                "f.txt"
3036            ]
3037        );
3038    });
3039
3040    project_b
3041        .update(cx_b, |project, cx| {
3042            project.delete_entry(dir_entry.id, cx).unwrap()
3043        })
3044        .await
3045        .unwrap();
3046    deterministic.run_until_parked();
3047
3048    worktree_a.read_with(cx_a, |worktree, _| {
3049        assert_eq!(
3050            worktree
3051                .paths()
3052                .map(|p| p.to_string_lossy())
3053                .collect::<Vec<_>>(),
3054            ["a.txt", "b.txt", "d.txt", "f.txt"]
3055        );
3056    });
3057    worktree_b.read_with(cx_b, |worktree, _| {
3058        assert_eq!(
3059            worktree
3060                .paths()
3061                .map(|p| p.to_string_lossy())
3062                .collect::<Vec<_>>(),
3063            ["a.txt", "b.txt", "d.txt", "f.txt"]
3064        );
3065    });
3066
3067    project_b
3068        .update(cx_b, |project, cx| {
3069            project.delete_entry(entry.id, cx).unwrap()
3070        })
3071        .await
3072        .unwrap();
3073    worktree_a.read_with(cx_a, |worktree, _| {
3074        assert_eq!(
3075            worktree
3076                .paths()
3077                .map(|p| p.to_string_lossy())
3078                .collect::<Vec<_>>(),
3079            ["a.txt", "b.txt", "f.txt"]
3080        );
3081    });
3082    worktree_b.read_with(cx_b, |worktree, _| {
3083        assert_eq!(
3084            worktree
3085                .paths()
3086                .map(|p| p.to_string_lossy())
3087                .collect::<Vec<_>>(),
3088            ["a.txt", "b.txt", "f.txt"]
3089        );
3090    });
3091}
3092
3093#[gpui::test(iterations = 10)]
3094async fn test_buffer_conflict_after_save(
3095    deterministic: Arc<Deterministic>,
3096    cx_a: &mut TestAppContext,
3097    cx_b: &mut TestAppContext,
3098) {
3099    deterministic.forbid_parking();
3100    let mut server = TestServer::start(&deterministic).await;
3101    let client_a = server.create_client(cx_a, "user_a").await;
3102    let client_b = server.create_client(cx_b, "user_b").await;
3103    server
3104        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3105        .await;
3106    let active_call_a = cx_a.read(ActiveCall::global);
3107
3108    client_a
3109        .fs
3110        .insert_tree(
3111            "/dir",
3112            json!({
3113                "a.txt": "a-contents",
3114            }),
3115        )
3116        .await;
3117    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3118    let project_id = active_call_a
3119        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3120        .await
3121        .unwrap();
3122    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3123
3124    // Open a buffer as client B
3125    let buffer_b = project_b
3126        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3127        .await
3128        .unwrap();
3129
3130    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "world ")], None, cx));
3131    buffer_b.read_with(cx_b, |buf, _| {
3132        assert!(buf.is_dirty());
3133        assert!(!buf.has_conflict());
3134    });
3135
3136    project_b
3137        .update(cx_b, |project, cx| {
3138            project.save_buffer(buffer_b.clone(), cx)
3139        })
3140        .await
3141        .unwrap();
3142    cx_a.foreground().forbid_parking();
3143    buffer_b.read_with(cx_b, |buffer_b, _| assert!(!buffer_b.is_dirty()));
3144    buffer_b.read_with(cx_b, |buf, _| {
3145        assert!(!buf.has_conflict());
3146    });
3147
3148    buffer_b.update(cx_b, |buf, cx| buf.edit([(0..0, "hello ")], None, cx));
3149    buffer_b.read_with(cx_b, |buf, _| {
3150        assert!(buf.is_dirty());
3151        assert!(!buf.has_conflict());
3152    });
3153}
3154
3155#[gpui::test(iterations = 10)]
3156async fn test_buffer_reloading(
3157    deterministic: Arc<Deterministic>,
3158    cx_a: &mut TestAppContext,
3159    cx_b: &mut TestAppContext,
3160) {
3161    deterministic.forbid_parking();
3162    let mut server = TestServer::start(&deterministic).await;
3163    let client_a = server.create_client(cx_a, "user_a").await;
3164    let client_b = server.create_client(cx_b, "user_b").await;
3165    server
3166        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3167        .await;
3168    let active_call_a = cx_a.read(ActiveCall::global);
3169
3170    client_a
3171        .fs
3172        .insert_tree(
3173            "/dir",
3174            json!({
3175                "a.txt": "a\nb\nc",
3176            }),
3177        )
3178        .await;
3179    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3180    let project_id = active_call_a
3181        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3182        .await
3183        .unwrap();
3184    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3185
3186    // Open a buffer as client B
3187    let buffer_b = project_b
3188        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3189        .await
3190        .unwrap();
3191    buffer_b.read_with(cx_b, |buf, _| {
3192        assert!(!buf.is_dirty());
3193        assert!(!buf.has_conflict());
3194        assert_eq!(buf.line_ending(), LineEnding::Unix);
3195    });
3196
3197    let new_contents = Rope::from("d\ne\nf");
3198    client_a
3199        .fs
3200        .save("/dir/a.txt".as_ref(), &new_contents, LineEnding::Windows)
3201        .await
3202        .unwrap();
3203    cx_a.foreground().run_until_parked();
3204    buffer_b.read_with(cx_b, |buf, _| {
3205        assert_eq!(buf.text(), new_contents.to_string());
3206        assert!(!buf.is_dirty());
3207        assert!(!buf.has_conflict());
3208        assert_eq!(buf.line_ending(), LineEnding::Windows);
3209    });
3210}
3211
3212#[gpui::test(iterations = 10)]
3213async fn test_editing_while_guest_opens_buffer(
3214    deterministic: Arc<Deterministic>,
3215    cx_a: &mut TestAppContext,
3216    cx_b: &mut TestAppContext,
3217) {
3218    deterministic.forbid_parking();
3219    let mut server = TestServer::start(&deterministic).await;
3220    let client_a = server.create_client(cx_a, "user_a").await;
3221    let client_b = server.create_client(cx_b, "user_b").await;
3222    server
3223        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3224        .await;
3225    let active_call_a = cx_a.read(ActiveCall::global);
3226
3227    client_a
3228        .fs
3229        .insert_tree("/dir", json!({ "a.txt": "a-contents" }))
3230        .await;
3231    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3232    let project_id = active_call_a
3233        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3234        .await
3235        .unwrap();
3236    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3237
3238    // Open a buffer as client A
3239    let buffer_a = project_a
3240        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3241        .await
3242        .unwrap();
3243
3244    // Start opening the same buffer as client B
3245    let buffer_b = cx_b
3246        .background()
3247        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)));
3248
3249    // Edit the buffer as client A while client B is still opening it.
3250    cx_b.background().simulate_random_delay().await;
3251    buffer_a.update(cx_a, |buf, cx| buf.edit([(0..0, "X")], None, cx));
3252    cx_b.background().simulate_random_delay().await;
3253    buffer_a.update(cx_a, |buf, cx| buf.edit([(1..1, "Y")], None, cx));
3254
3255    let text = buffer_a.read_with(cx_a, |buf, _| buf.text());
3256    let buffer_b = buffer_b.await.unwrap();
3257    cx_a.foreground().run_until_parked();
3258    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), text));
3259}
3260
3261#[gpui::test]
3262async fn test_newline_above_or_below_does_not_move_guest_cursor(
3263    deterministic: Arc<Deterministic>,
3264    cx_a: &mut TestAppContext,
3265    cx_b: &mut TestAppContext,
3266) {
3267    deterministic.forbid_parking();
3268    let mut server = TestServer::start(&deterministic).await;
3269    let client_a = server.create_client(cx_a, "user_a").await;
3270    let client_b = server.create_client(cx_b, "user_b").await;
3271    server
3272        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3273        .await;
3274    let active_call_a = cx_a.read(ActiveCall::global);
3275
3276    client_a
3277        .fs
3278        .insert_tree("/dir", json!({ "a.txt": "Some text\n" }))
3279        .await;
3280    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3281    let project_id = active_call_a
3282        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3283        .await
3284        .unwrap();
3285
3286    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3287
3288    // Open a buffer as client A
3289    let buffer_a = project_a
3290        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3291        .await
3292        .unwrap();
3293    let (window_a, _) = cx_a.add_window(|_| EmptyView);
3294    let editor_a = cx_a.add_view(window_a, |cx| {
3295        Editor::for_buffer(buffer_a, Some(project_a), cx)
3296    });
3297    let mut editor_cx_a = EditorTestContext {
3298        cx: cx_a,
3299        window_id: window_a,
3300        editor: editor_a,
3301    };
3302
3303    // Open a buffer as client B
3304    let buffer_b = project_b
3305        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3306        .await
3307        .unwrap();
3308    let (window_b, _) = cx_b.add_window(|_| EmptyView);
3309    let editor_b = cx_b.add_view(window_b, |cx| {
3310        Editor::for_buffer(buffer_b, Some(project_b), cx)
3311    });
3312    let mut editor_cx_b = EditorTestContext {
3313        cx: cx_b,
3314        window_id: window_b,
3315        editor: editor_b,
3316    };
3317
3318    // Test newline above
3319    editor_cx_a.set_selections_state(indoc! {"
3320        Some textˇ
3321    "});
3322    editor_cx_b.set_selections_state(indoc! {"
3323        Some textˇ
3324    "});
3325    editor_cx_a.update_editor(|editor, cx| editor.newline_above(&editor::NewlineAbove, cx));
3326    deterministic.run_until_parked();
3327    editor_cx_a.assert_editor_state(indoc! {"
3328        ˇ
3329        Some text
3330    "});
3331    editor_cx_b.assert_editor_state(indoc! {"
3332
3333        Some textˇ
3334    "});
3335
3336    // Test newline below
3337    editor_cx_a.set_selections_state(indoc! {"
3338
3339        Some textˇ
3340    "});
3341    editor_cx_b.set_selections_state(indoc! {"
3342
3343        Some textˇ
3344    "});
3345    editor_cx_a.update_editor(|editor, cx| editor.newline_below(&editor::NewlineBelow, cx));
3346    deterministic.run_until_parked();
3347    editor_cx_a.assert_editor_state(indoc! {"
3348
3349        Some text
3350        ˇ
3351    "});
3352    editor_cx_b.assert_editor_state(indoc! {"
3353
3354        Some textˇ
3355
3356    "});
3357}
3358
3359#[gpui::test(iterations = 10)]
3360async fn test_leaving_worktree_while_opening_buffer(
3361    deterministic: Arc<Deterministic>,
3362    cx_a: &mut TestAppContext,
3363    cx_b: &mut TestAppContext,
3364) {
3365    deterministic.forbid_parking();
3366    let mut server = TestServer::start(&deterministic).await;
3367    let client_a = server.create_client(cx_a, "user_a").await;
3368    let client_b = server.create_client(cx_b, "user_b").await;
3369    server
3370        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3371        .await;
3372    let active_call_a = cx_a.read(ActiveCall::global);
3373
3374    client_a
3375        .fs
3376        .insert_tree("/dir", json!({ "a.txt": "a-contents" }))
3377        .await;
3378    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3379    let project_id = active_call_a
3380        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3381        .await
3382        .unwrap();
3383    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3384
3385    // See that a guest has joined as client A.
3386    cx_a.foreground().run_until_parked();
3387    project_a.read_with(cx_a, |p, _| assert_eq!(p.collaborators().len(), 1));
3388
3389    // Begin opening a buffer as client B, but leave the project before the open completes.
3390    let buffer_b = cx_b
3391        .background()
3392        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx)));
3393    cx_b.update(|_| drop(project_b));
3394    drop(buffer_b);
3395
3396    // See that the guest has left.
3397    cx_a.foreground().run_until_parked();
3398    project_a.read_with(cx_a, |p, _| assert!(p.collaborators().is_empty()));
3399}
3400
3401#[gpui::test(iterations = 10)]
3402async fn test_canceling_buffer_opening(
3403    deterministic: Arc<Deterministic>,
3404    cx_a: &mut TestAppContext,
3405    cx_b: &mut TestAppContext,
3406) {
3407    deterministic.forbid_parking();
3408
3409    let mut server = TestServer::start(&deterministic).await;
3410    let client_a = server.create_client(cx_a, "user_a").await;
3411    let client_b = server.create_client(cx_b, "user_b").await;
3412    server
3413        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3414        .await;
3415    let active_call_a = cx_a.read(ActiveCall::global);
3416
3417    client_a
3418        .fs
3419        .insert_tree(
3420            "/dir",
3421            json!({
3422                "a.txt": "abc",
3423            }),
3424        )
3425        .await;
3426    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
3427    let project_id = active_call_a
3428        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3429        .await
3430        .unwrap();
3431    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3432
3433    let buffer_a = project_a
3434        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
3435        .await
3436        .unwrap();
3437
3438    // Open a buffer as client B but cancel after a random amount of time.
3439    let buffer_b = project_b.update(cx_b, |p, cx| {
3440        p.open_buffer_by_id(buffer_a.read_with(cx_a, |a, _| a.remote_id()), cx)
3441    });
3442    deterministic.simulate_random_delay().await;
3443    drop(buffer_b);
3444
3445    // Try opening the same buffer again as client B, and ensure we can
3446    // still do it despite the cancellation above.
3447    let buffer_b = project_b
3448        .update(cx_b, |p, cx| {
3449            p.open_buffer_by_id(buffer_a.read_with(cx_a, |a, _| a.remote_id()), cx)
3450        })
3451        .await
3452        .unwrap();
3453    buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "abc"));
3454}
3455
3456#[gpui::test(iterations = 10)]
3457async fn test_leaving_project(
3458    deterministic: Arc<Deterministic>,
3459    cx_a: &mut TestAppContext,
3460    cx_b: &mut TestAppContext,
3461    cx_c: &mut TestAppContext,
3462) {
3463    deterministic.forbid_parking();
3464    let mut server = TestServer::start(&deterministic).await;
3465    let client_a = server.create_client(cx_a, "user_a").await;
3466    let client_b = server.create_client(cx_b, "user_b").await;
3467    let client_c = server.create_client(cx_c, "user_c").await;
3468    server
3469        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
3470        .await;
3471    let active_call_a = cx_a.read(ActiveCall::global);
3472
3473    client_a
3474        .fs
3475        .insert_tree(
3476            "/a",
3477            json!({
3478                "a.txt": "a-contents",
3479                "b.txt": "b-contents",
3480            }),
3481        )
3482        .await;
3483    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
3484    let project_id = active_call_a
3485        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3486        .await
3487        .unwrap();
3488    let project_b1 = client_b.build_remote_project(project_id, cx_b).await;
3489    let project_c = client_c.build_remote_project(project_id, cx_c).await;
3490
3491    // Client A sees that a guest has joined.
3492    deterministic.run_until_parked();
3493    project_a.read_with(cx_a, |project, _| {
3494        assert_eq!(project.collaborators().len(), 2);
3495    });
3496    project_b1.read_with(cx_b, |project, _| {
3497        assert_eq!(project.collaborators().len(), 2);
3498    });
3499    project_c.read_with(cx_c, |project, _| {
3500        assert_eq!(project.collaborators().len(), 2);
3501    });
3502
3503    // Client B opens a buffer.
3504    let buffer_b1 = project_b1
3505        .update(cx_b, |project, cx| {
3506            let worktree_id = project.worktrees(cx).next().unwrap().read(cx).id();
3507            project.open_buffer((worktree_id, "a.txt"), cx)
3508        })
3509        .await
3510        .unwrap();
3511    buffer_b1.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "a-contents"));
3512
3513    // Drop client B's project and ensure client A and client C observe client B leaving.
3514    cx_b.update(|_| drop(project_b1));
3515    deterministic.run_until_parked();
3516    project_a.read_with(cx_a, |project, _| {
3517        assert_eq!(project.collaborators().len(), 1);
3518    });
3519    project_c.read_with(cx_c, |project, _| {
3520        assert_eq!(project.collaborators().len(), 1);
3521    });
3522
3523    // Client B re-joins the project and can open buffers as before.
3524    let project_b2 = client_b.build_remote_project(project_id, cx_b).await;
3525    deterministic.run_until_parked();
3526    project_a.read_with(cx_a, |project, _| {
3527        assert_eq!(project.collaborators().len(), 2);
3528    });
3529    project_b2.read_with(cx_b, |project, _| {
3530        assert_eq!(project.collaborators().len(), 2);
3531    });
3532    project_c.read_with(cx_c, |project, _| {
3533        assert_eq!(project.collaborators().len(), 2);
3534    });
3535
3536    let buffer_b2 = project_b2
3537        .update(cx_b, |project, cx| {
3538            let worktree_id = project.worktrees(cx).next().unwrap().read(cx).id();
3539            project.open_buffer((worktree_id, "a.txt"), cx)
3540        })
3541        .await
3542        .unwrap();
3543    buffer_b2.read_with(cx_b, |buffer, _| assert_eq!(buffer.text(), "a-contents"));
3544
3545    // Drop client B's connection and ensure client A and client C observe client B leaving.
3546    client_b.disconnect(&cx_b.to_async());
3547    deterministic.advance_clock(RECONNECT_TIMEOUT);
3548    project_a.read_with(cx_a, |project, _| {
3549        assert_eq!(project.collaborators().len(), 1);
3550    });
3551    project_b2.read_with(cx_b, |project, _| {
3552        assert!(project.is_read_only());
3553    });
3554    project_c.read_with(cx_c, |project, _| {
3555        assert_eq!(project.collaborators().len(), 1);
3556    });
3557
3558    // Client B can't join the project, unless they re-join the room.
3559    cx_b.spawn(|cx| {
3560        Project::remote(
3561            project_id,
3562            client_b.client.clone(),
3563            client_b.user_store.clone(),
3564            client_b.language_registry.clone(),
3565            FakeFs::new(cx.background()),
3566            cx,
3567        )
3568    })
3569    .await
3570    .unwrap_err();
3571
3572    // Simulate connection loss for client C and ensure client A observes client C leaving the project.
3573    client_c.wait_for_current_user(cx_c).await;
3574    server.forbid_connections();
3575    server.disconnect_client(client_c.peer_id().unwrap());
3576    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
3577    deterministic.run_until_parked();
3578    project_a.read_with(cx_a, |project, _| {
3579        assert_eq!(project.collaborators().len(), 0);
3580    });
3581    project_b2.read_with(cx_b, |project, _| {
3582        assert!(project.is_read_only());
3583    });
3584    project_c.read_with(cx_c, |project, _| {
3585        assert!(project.is_read_only());
3586    });
3587}
3588
3589#[gpui::test(iterations = 10)]
3590async fn test_collaborating_with_diagnostics(
3591    deterministic: Arc<Deterministic>,
3592    cx_a: &mut TestAppContext,
3593    cx_b: &mut TestAppContext,
3594    cx_c: &mut TestAppContext,
3595) {
3596    deterministic.forbid_parking();
3597    let mut server = TestServer::start(&deterministic).await;
3598    let client_a = server.create_client(cx_a, "user_a").await;
3599    let client_b = server.create_client(cx_b, "user_b").await;
3600    let client_c = server.create_client(cx_c, "user_c").await;
3601    server
3602        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
3603        .await;
3604    let active_call_a = cx_a.read(ActiveCall::global);
3605
3606    // Set up a fake language server.
3607    let mut language = Language::new(
3608        LanguageConfig {
3609            name: "Rust".into(),
3610            path_suffixes: vec!["rs".to_string()],
3611            ..Default::default()
3612        },
3613        Some(tree_sitter_rust::language()),
3614    );
3615    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
3616    client_a.language_registry.add(Arc::new(language));
3617
3618    // Share a project as client A
3619    client_a
3620        .fs
3621        .insert_tree(
3622            "/a",
3623            json!({
3624                "a.rs": "let one = two",
3625                "other.rs": "",
3626            }),
3627        )
3628        .await;
3629    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
3630
3631    // Cause the language server to start.
3632    let _buffer = project_a
3633        .update(cx_a, |project, cx| {
3634            project.open_buffer(
3635                ProjectPath {
3636                    worktree_id,
3637                    path: Path::new("other.rs").into(),
3638                },
3639                cx,
3640            )
3641        })
3642        .await
3643        .unwrap();
3644
3645    // Simulate a language server reporting errors for a file.
3646    let mut fake_language_server = fake_language_servers.next().await.unwrap();
3647    fake_language_server
3648        .receive_notification::<lsp::notification::DidOpenTextDocument>()
3649        .await;
3650    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3651        lsp::PublishDiagnosticsParams {
3652            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3653            version: None,
3654            diagnostics: vec![lsp::Diagnostic {
3655                severity: Some(lsp::DiagnosticSeverity::WARNING),
3656                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3657                message: "message 0".to_string(),
3658                ..Default::default()
3659            }],
3660        },
3661    );
3662
3663    // Client A shares the project and, simultaneously, the language server
3664    // publishes a diagnostic. This is done to ensure that the server always
3665    // observes the latest diagnostics for a worktree.
3666    let project_id = active_call_a
3667        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3668        .await
3669        .unwrap();
3670    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3671        lsp::PublishDiagnosticsParams {
3672            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3673            version: None,
3674            diagnostics: vec![lsp::Diagnostic {
3675                severity: Some(lsp::DiagnosticSeverity::ERROR),
3676                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3677                message: "message 1".to_string(),
3678                ..Default::default()
3679            }],
3680        },
3681    );
3682
3683    // Join the worktree as client B.
3684    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3685
3686    // Wait for server to see the diagnostics update.
3687    deterministic.run_until_parked();
3688
3689    // Ensure client B observes the new diagnostics.
3690    project_b.read_with(cx_b, |project, cx| {
3691        assert_eq!(
3692            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3693            &[(
3694                ProjectPath {
3695                    worktree_id,
3696                    path: Arc::from(Path::new("a.rs")),
3697                },
3698                LanguageServerId(0),
3699                DiagnosticSummary {
3700                    error_count: 1,
3701                    warning_count: 0,
3702                    ..Default::default()
3703                },
3704            )]
3705        )
3706    });
3707
3708    // Join project as client C and observe the diagnostics.
3709    let project_c = client_c.build_remote_project(project_id, cx_c).await;
3710    let project_c_diagnostic_summaries =
3711        Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
3712            project.diagnostic_summaries(cx).collect::<Vec<_>>()
3713        })));
3714    project_c.update(cx_c, |_, cx| {
3715        let summaries = project_c_diagnostic_summaries.clone();
3716        cx.subscribe(&project_c, {
3717            move |p, _, event, cx| {
3718                if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
3719                    *summaries.borrow_mut() = p.diagnostic_summaries(cx).collect();
3720                }
3721            }
3722        })
3723        .detach();
3724    });
3725
3726    deterministic.run_until_parked();
3727    assert_eq!(
3728        project_c_diagnostic_summaries.borrow().as_slice(),
3729        &[(
3730            ProjectPath {
3731                worktree_id,
3732                path: Arc::from(Path::new("a.rs")),
3733            },
3734            LanguageServerId(0),
3735            DiagnosticSummary {
3736                error_count: 1,
3737                warning_count: 0,
3738                ..Default::default()
3739            },
3740        )]
3741    );
3742
3743    // Simulate a language server reporting more errors for a file.
3744    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3745        lsp::PublishDiagnosticsParams {
3746            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3747            version: None,
3748            diagnostics: vec![
3749                lsp::Diagnostic {
3750                    severity: Some(lsp::DiagnosticSeverity::ERROR),
3751                    range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 7)),
3752                    message: "message 1".to_string(),
3753                    ..Default::default()
3754                },
3755                lsp::Diagnostic {
3756                    severity: Some(lsp::DiagnosticSeverity::WARNING),
3757                    range: lsp::Range::new(lsp::Position::new(0, 10), lsp::Position::new(0, 13)),
3758                    message: "message 2".to_string(),
3759                    ..Default::default()
3760                },
3761            ],
3762        },
3763    );
3764
3765    // Clients B and C get the updated summaries
3766    deterministic.run_until_parked();
3767    project_b.read_with(cx_b, |project, cx| {
3768        assert_eq!(
3769            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3770            [(
3771                ProjectPath {
3772                    worktree_id,
3773                    path: Arc::from(Path::new("a.rs")),
3774                },
3775                LanguageServerId(0),
3776                DiagnosticSummary {
3777                    error_count: 1,
3778                    warning_count: 1,
3779                },
3780            )]
3781        );
3782    });
3783    project_c.read_with(cx_c, |project, cx| {
3784        assert_eq!(
3785            project.diagnostic_summaries(cx).collect::<Vec<_>>(),
3786            [(
3787                ProjectPath {
3788                    worktree_id,
3789                    path: Arc::from(Path::new("a.rs")),
3790                },
3791                LanguageServerId(0),
3792                DiagnosticSummary {
3793                    error_count: 1,
3794                    warning_count: 1,
3795                },
3796            )]
3797        );
3798    });
3799
3800    // Open the file with the errors on client B. They should be present.
3801    let buffer_b = cx_b
3802        .background()
3803        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
3804        .await
3805        .unwrap();
3806
3807    buffer_b.read_with(cx_b, |buffer, _| {
3808        assert_eq!(
3809            buffer
3810                .snapshot()
3811                .diagnostics_in_range::<_, Point>(0..buffer.len(), false)
3812                .collect::<Vec<_>>(),
3813            &[
3814                DiagnosticEntry {
3815                    range: Point::new(0, 4)..Point::new(0, 7),
3816                    diagnostic: Diagnostic {
3817                        group_id: 2,
3818                        message: "message 1".to_string(),
3819                        severity: lsp::DiagnosticSeverity::ERROR,
3820                        is_primary: true,
3821                        ..Default::default()
3822                    }
3823                },
3824                DiagnosticEntry {
3825                    range: Point::new(0, 10)..Point::new(0, 13),
3826                    diagnostic: Diagnostic {
3827                        group_id: 3,
3828                        severity: lsp::DiagnosticSeverity::WARNING,
3829                        message: "message 2".to_string(),
3830                        is_primary: true,
3831                        ..Default::default()
3832                    }
3833                }
3834            ]
3835        );
3836    });
3837
3838    // Simulate a language server reporting no errors for a file.
3839    fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3840        lsp::PublishDiagnosticsParams {
3841            uri: lsp::Url::from_file_path("/a/a.rs").unwrap(),
3842            version: None,
3843            diagnostics: vec![],
3844        },
3845    );
3846    deterministic.run_until_parked();
3847    project_a.read_with(cx_a, |project, cx| {
3848        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3849    });
3850    project_b.read_with(cx_b, |project, cx| {
3851        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3852    });
3853    project_c.read_with(cx_c, |project, cx| {
3854        assert_eq!(project.diagnostic_summaries(cx).collect::<Vec<_>>(), [])
3855    });
3856}
3857
3858#[gpui::test(iterations = 10)]
3859async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
3860    deterministic: Arc<Deterministic>,
3861    cx_a: &mut TestAppContext,
3862    cx_b: &mut TestAppContext,
3863) {
3864    deterministic.forbid_parking();
3865    let mut server = TestServer::start(&deterministic).await;
3866    let client_a = server.create_client(cx_a, "user_a").await;
3867    let client_b = server.create_client(cx_b, "user_b").await;
3868    server
3869        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
3870        .await;
3871
3872    // Set up a fake language server.
3873    let mut language = Language::new(
3874        LanguageConfig {
3875            name: "Rust".into(),
3876            path_suffixes: vec!["rs".to_string()],
3877            ..Default::default()
3878        },
3879        Some(tree_sitter_rust::language()),
3880    );
3881    let mut fake_language_servers = language
3882        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
3883            disk_based_diagnostics_progress_token: Some("the-disk-based-token".into()),
3884            disk_based_diagnostics_sources: vec!["the-disk-based-diagnostics-source".into()],
3885            ..Default::default()
3886        }))
3887        .await;
3888    client_a.language_registry.add(Arc::new(language));
3889
3890    let file_names = &["one.rs", "two.rs", "three.rs", "four.rs", "five.rs"];
3891    client_a
3892        .fs
3893        .insert_tree(
3894            "/test",
3895            json!({
3896                "one.rs": "const ONE: usize = 1;",
3897                "two.rs": "const TWO: usize = 2;",
3898                "three.rs": "const THREE: usize = 3;",
3899                "four.rs": "const FOUR: usize = 3;",
3900                "five.rs": "const FIVE: usize = 3;",
3901            }),
3902        )
3903        .await;
3904
3905    let (project_a, worktree_id) = client_a.build_local_project("/test", cx_a).await;
3906
3907    // Share a project as client A
3908    let active_call_a = cx_a.read(ActiveCall::global);
3909    let project_id = active_call_a
3910        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
3911        .await
3912        .unwrap();
3913
3914    // Join the project as client B and open all three files.
3915    let project_b = client_b.build_remote_project(project_id, cx_b).await;
3916    let guest_buffers = futures::future::try_join_all(file_names.iter().map(|file_name| {
3917        project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, file_name), cx))
3918    }))
3919    .await
3920    .unwrap();
3921
3922    // Simulate a language server reporting errors for a file.
3923    let fake_language_server = fake_language_servers.next().await.unwrap();
3924    fake_language_server
3925        .request::<lsp::request::WorkDoneProgressCreate>(lsp::WorkDoneProgressCreateParams {
3926            token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
3927        })
3928        .await
3929        .unwrap();
3930    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
3931        token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
3932        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin(
3933            lsp::WorkDoneProgressBegin {
3934                title: "Progress Began".into(),
3935                ..Default::default()
3936            },
3937        )),
3938    });
3939    for file_name in file_names {
3940        fake_language_server.notify::<lsp::notification::PublishDiagnostics>(
3941            lsp::PublishDiagnosticsParams {
3942                uri: lsp::Url::from_file_path(Path::new("/test").join(file_name)).unwrap(),
3943                version: None,
3944                diagnostics: vec![lsp::Diagnostic {
3945                    severity: Some(lsp::DiagnosticSeverity::WARNING),
3946                    source: Some("the-disk-based-diagnostics-source".into()),
3947                    range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
3948                    message: "message one".to_string(),
3949                    ..Default::default()
3950                }],
3951            },
3952        );
3953    }
3954    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
3955        token: lsp::NumberOrString::String("the-disk-based-token".to_string()),
3956        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End(
3957            lsp::WorkDoneProgressEnd { message: None },
3958        )),
3959    });
3960
3961    // When the "disk base diagnostics finished" message is received, the buffers'
3962    // diagnostics are expected to be present.
3963    let disk_based_diagnostics_finished = Arc::new(AtomicBool::new(false));
3964    project_b.update(cx_b, {
3965        let project_b = project_b.clone();
3966        let disk_based_diagnostics_finished = disk_based_diagnostics_finished.clone();
3967        move |_, cx| {
3968            cx.subscribe(&project_b, move |_, _, event, cx| {
3969                if let project::Event::DiskBasedDiagnosticsFinished { .. } = event {
3970                    disk_based_diagnostics_finished.store(true, SeqCst);
3971                    for buffer in &guest_buffers {
3972                        assert_eq!(
3973                            buffer
3974                                .read(cx)
3975                                .snapshot()
3976                                .diagnostics_in_range::<_, usize>(0..5, false)
3977                                .count(),
3978                            1,
3979                            "expected a diagnostic for buffer {:?}",
3980                            buffer.read(cx).file().unwrap().path(),
3981                        );
3982                    }
3983                }
3984            })
3985            .detach();
3986        }
3987    });
3988
3989    deterministic.run_until_parked();
3990    assert!(disk_based_diagnostics_finished.load(SeqCst));
3991}
3992
3993#[gpui::test(iterations = 10)]
3994async fn test_collaborating_with_completion(
3995    deterministic: Arc<Deterministic>,
3996    cx_a: &mut TestAppContext,
3997    cx_b: &mut TestAppContext,
3998) {
3999    deterministic.forbid_parking();
4000    let mut server = TestServer::start(&deterministic).await;
4001    let client_a = server.create_client(cx_a, "user_a").await;
4002    let client_b = server.create_client(cx_b, "user_b").await;
4003    server
4004        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4005        .await;
4006    let active_call_a = cx_a.read(ActiveCall::global);
4007
4008    // Set up a fake language server.
4009    let mut language = Language::new(
4010        LanguageConfig {
4011            name: "Rust".into(),
4012            path_suffixes: vec!["rs".to_string()],
4013            ..Default::default()
4014        },
4015        Some(tree_sitter_rust::language()),
4016    );
4017    let mut fake_language_servers = language
4018        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
4019            capabilities: lsp::ServerCapabilities {
4020                completion_provider: Some(lsp::CompletionOptions {
4021                    trigger_characters: Some(vec![".".to_string()]),
4022                    ..Default::default()
4023                }),
4024                ..Default::default()
4025            },
4026            ..Default::default()
4027        }))
4028        .await;
4029    client_a.language_registry.add(Arc::new(language));
4030
4031    client_a
4032        .fs
4033        .insert_tree(
4034            "/a",
4035            json!({
4036                "main.rs": "fn main() { a }",
4037                "other.rs": "",
4038            }),
4039        )
4040        .await;
4041    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
4042    let project_id = active_call_a
4043        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4044        .await
4045        .unwrap();
4046    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4047
4048    // Open a file in an editor as the guest.
4049    let buffer_b = project_b
4050        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
4051        .await
4052        .unwrap();
4053    let (window_b, _) = cx_b.add_window(|_| EmptyView);
4054    let editor_b = cx_b.add_view(window_b, |cx| {
4055        Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
4056    });
4057
4058    let fake_language_server = fake_language_servers.next().await.unwrap();
4059    cx_a.foreground().run_until_parked();
4060    buffer_b.read_with(cx_b, |buffer, _| {
4061        assert!(!buffer.completion_triggers().is_empty())
4062    });
4063
4064    // Type a completion trigger character as the guest.
4065    editor_b.update(cx_b, |editor, cx| {
4066        editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
4067        editor.handle_input(".", cx);
4068        cx.focus(&editor_b);
4069    });
4070
4071    // Receive a completion request as the host's language server.
4072    // Return some completions from the host's language server.
4073    cx_a.foreground().start_waiting();
4074    fake_language_server
4075        .handle_request::<lsp::request::Completion, _, _>(|params, _| async move {
4076            assert_eq!(
4077                params.text_document_position.text_document.uri,
4078                lsp::Url::from_file_path("/a/main.rs").unwrap(),
4079            );
4080            assert_eq!(
4081                params.text_document_position.position,
4082                lsp::Position::new(0, 14),
4083            );
4084
4085            Ok(Some(lsp::CompletionResponse::Array(vec![
4086                lsp::CompletionItem {
4087                    label: "first_method(…)".into(),
4088                    detail: Some("fn(&mut self, B) -> C".into()),
4089                    text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
4090                        new_text: "first_method($1)".to_string(),
4091                        range: lsp::Range::new(
4092                            lsp::Position::new(0, 14),
4093                            lsp::Position::new(0, 14),
4094                        ),
4095                    })),
4096                    insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
4097                    ..Default::default()
4098                },
4099                lsp::CompletionItem {
4100                    label: "second_method(…)".into(),
4101                    detail: Some("fn(&mut self, C) -> D<E>".into()),
4102                    text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
4103                        new_text: "second_method()".to_string(),
4104                        range: lsp::Range::new(
4105                            lsp::Position::new(0, 14),
4106                            lsp::Position::new(0, 14),
4107                        ),
4108                    })),
4109                    insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
4110                    ..Default::default()
4111                },
4112            ])))
4113        })
4114        .next()
4115        .await
4116        .unwrap();
4117    cx_a.foreground().finish_waiting();
4118
4119    // Open the buffer on the host.
4120    let buffer_a = project_a
4121        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
4122        .await
4123        .unwrap();
4124    cx_a.foreground().run_until_parked();
4125    buffer_a.read_with(cx_a, |buffer, _| {
4126        assert_eq!(buffer.text(), "fn main() { a. }")
4127    });
4128
4129    // Confirm a completion on the guest.
4130    editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
4131    editor_b.update(cx_b, |editor, cx| {
4132        editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
4133        assert_eq!(editor.text(cx), "fn main() { a.first_method() }");
4134    });
4135
4136    // Return a resolved completion from the host's language server.
4137    // The resolved completion has an additional text edit.
4138    fake_language_server.handle_request::<lsp::request::ResolveCompletionItem, _, _>(
4139        |params, _| async move {
4140            assert_eq!(params.label, "first_method(…)");
4141            Ok(lsp::CompletionItem {
4142                label: "first_method(…)".into(),
4143                detail: Some("fn(&mut self, B) -> C".into()),
4144                text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
4145                    new_text: "first_method($1)".to_string(),
4146                    range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
4147                })),
4148                additional_text_edits: Some(vec![lsp::TextEdit {
4149                    new_text: "use d::SomeTrait;\n".to_string(),
4150                    range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
4151                }]),
4152                insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
4153                ..Default::default()
4154            })
4155        },
4156    );
4157
4158    // The additional edit is applied.
4159    cx_a.foreground().run_until_parked();
4160    buffer_a.read_with(cx_a, |buffer, _| {
4161        assert_eq!(
4162            buffer.text(),
4163            "use d::SomeTrait;\nfn main() { a.first_method() }"
4164        );
4165    });
4166    buffer_b.read_with(cx_b, |buffer, _| {
4167        assert_eq!(
4168            buffer.text(),
4169            "use d::SomeTrait;\nfn main() { a.first_method() }"
4170        );
4171    });
4172}
4173
4174#[gpui::test(iterations = 10)]
4175async fn test_reloading_buffer_manually(
4176    deterministic: Arc<Deterministic>,
4177    cx_a: &mut TestAppContext,
4178    cx_b: &mut TestAppContext,
4179) {
4180    deterministic.forbid_parking();
4181    let mut server = TestServer::start(&deterministic).await;
4182    let client_a = server.create_client(cx_a, "user_a").await;
4183    let client_b = server.create_client(cx_b, "user_b").await;
4184    server
4185        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4186        .await;
4187    let active_call_a = cx_a.read(ActiveCall::global);
4188
4189    client_a
4190        .fs
4191        .insert_tree("/a", json!({ "a.rs": "let one = 1;" }))
4192        .await;
4193    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
4194    let buffer_a = project_a
4195        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx))
4196        .await
4197        .unwrap();
4198    let project_id = active_call_a
4199        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4200        .await
4201        .unwrap();
4202
4203    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4204
4205    let buffer_b = cx_b
4206        .background()
4207        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
4208        .await
4209        .unwrap();
4210    buffer_b.update(cx_b, |buffer, cx| {
4211        buffer.edit([(4..7, "six")], None, cx);
4212        buffer.edit([(10..11, "6")], None, cx);
4213        assert_eq!(buffer.text(), "let six = 6;");
4214        assert!(buffer.is_dirty());
4215        assert!(!buffer.has_conflict());
4216    });
4217    cx_a.foreground().run_until_parked();
4218    buffer_a.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "let six = 6;"));
4219
4220    client_a
4221        .fs
4222        .save(
4223            "/a/a.rs".as_ref(),
4224            &Rope::from("let seven = 7;"),
4225            LineEnding::Unix,
4226        )
4227        .await
4228        .unwrap();
4229    cx_a.foreground().run_until_parked();
4230    buffer_a.read_with(cx_a, |buffer, _| assert!(buffer.has_conflict()));
4231    buffer_b.read_with(cx_b, |buffer, _| assert!(buffer.has_conflict()));
4232
4233    project_b
4234        .update(cx_b, |project, cx| {
4235            project.reload_buffers(HashSet::from_iter([buffer_b.clone()]), true, cx)
4236        })
4237        .await
4238        .unwrap();
4239    buffer_a.read_with(cx_a, |buffer, _| {
4240        assert_eq!(buffer.text(), "let seven = 7;");
4241        assert!(!buffer.is_dirty());
4242        assert!(!buffer.has_conflict());
4243    });
4244    buffer_b.read_with(cx_b, |buffer, _| {
4245        assert_eq!(buffer.text(), "let seven = 7;");
4246        assert!(!buffer.is_dirty());
4247        assert!(!buffer.has_conflict());
4248    });
4249
4250    buffer_a.update(cx_a, |buffer, cx| {
4251        // Undoing on the host is a no-op when the reload was initiated by the guest.
4252        buffer.undo(cx);
4253        assert_eq!(buffer.text(), "let seven = 7;");
4254        assert!(!buffer.is_dirty());
4255        assert!(!buffer.has_conflict());
4256    });
4257    buffer_b.update(cx_b, |buffer, cx| {
4258        // Undoing on the guest rolls back the buffer to before it was reloaded but the conflict gets cleared.
4259        buffer.undo(cx);
4260        assert_eq!(buffer.text(), "let six = 6;");
4261        assert!(buffer.is_dirty());
4262        assert!(!buffer.has_conflict());
4263    });
4264}
4265
4266#[gpui::test(iterations = 10)]
4267async fn test_formatting_buffer(
4268    deterministic: Arc<Deterministic>,
4269    cx_a: &mut TestAppContext,
4270    cx_b: &mut TestAppContext,
4271) {
4272    use project::FormatTrigger;
4273
4274    let mut server = TestServer::start(&deterministic).await;
4275    let client_a = server.create_client(cx_a, "user_a").await;
4276    let client_b = server.create_client(cx_b, "user_b").await;
4277    server
4278        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4279        .await;
4280    let active_call_a = cx_a.read(ActiveCall::global);
4281
4282    // Set up a fake language server.
4283    let mut language = Language::new(
4284        LanguageConfig {
4285            name: "Rust".into(),
4286            path_suffixes: vec!["rs".to_string()],
4287            ..Default::default()
4288        },
4289        Some(tree_sitter_rust::language()),
4290    );
4291    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4292    client_a.language_registry.add(Arc::new(language));
4293
4294    // Here we insert a fake tree with a directory that exists on disk. This is needed
4295    // because later we'll invoke a command, which requires passing a working directory
4296    // that points to a valid location on disk.
4297    let directory = env::current_dir().unwrap();
4298    client_a
4299        .fs
4300        .insert_tree(&directory, json!({ "a.rs": "let one = \"two\"" }))
4301        .await;
4302    let (project_a, worktree_id) = client_a.build_local_project(&directory, cx_a).await;
4303    let project_id = active_call_a
4304        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4305        .await
4306        .unwrap();
4307    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4308
4309    let buffer_b = cx_b
4310        .background()
4311        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
4312        .await
4313        .unwrap();
4314
4315    let fake_language_server = fake_language_servers.next().await.unwrap();
4316    fake_language_server.handle_request::<lsp::request::Formatting, _, _>(|_, _| async move {
4317        Ok(Some(vec![
4318            lsp::TextEdit {
4319                range: lsp::Range::new(lsp::Position::new(0, 4), lsp::Position::new(0, 4)),
4320                new_text: "h".to_string(),
4321            },
4322            lsp::TextEdit {
4323                range: lsp::Range::new(lsp::Position::new(0, 7), lsp::Position::new(0, 7)),
4324                new_text: "y".to_string(),
4325            },
4326        ]))
4327    });
4328
4329    project_b
4330        .update(cx_b, |project, cx| {
4331            project.format(
4332                HashSet::from_iter([buffer_b.clone()]),
4333                true,
4334                FormatTrigger::Save,
4335                cx,
4336            )
4337        })
4338        .await
4339        .unwrap();
4340
4341    // The edits from the LSP are applied, and a final newline is added.
4342    assert_eq!(
4343        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
4344        "let honey = \"two\"\n"
4345    );
4346
4347    // Ensure buffer can be formatted using an external command. Notice how the
4348    // host's configuration is honored as opposed to using the guest's settings.
4349    cx_a.update(|cx| {
4350        cx.update_global(|store: &mut SettingsStore, cx| {
4351            store.update_user_settings::<AllLanguageSettings>(cx, |file| {
4352                file.defaults.formatter = Some(Formatter::External {
4353                    command: "awk".into(),
4354                    arguments: vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into(),
4355                });
4356            });
4357        });
4358    });
4359    project_b
4360        .update(cx_b, |project, cx| {
4361            project.format(
4362                HashSet::from_iter([buffer_b.clone()]),
4363                true,
4364                FormatTrigger::Save,
4365                cx,
4366            )
4367        })
4368        .await
4369        .unwrap();
4370    assert_eq!(
4371        buffer_b.read_with(cx_b, |buffer, _| buffer.text()),
4372        format!("let honey = \"{}/a.rs\"\n", directory.to_str().unwrap())
4373    );
4374}
4375
4376#[gpui::test(iterations = 10)]
4377async fn test_definition(
4378    deterministic: Arc<Deterministic>,
4379    cx_a: &mut TestAppContext,
4380    cx_b: &mut TestAppContext,
4381) {
4382    deterministic.forbid_parking();
4383    let mut server = TestServer::start(&deterministic).await;
4384    let client_a = server.create_client(cx_a, "user_a").await;
4385    let client_b = server.create_client(cx_b, "user_b").await;
4386    server
4387        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4388        .await;
4389    let active_call_a = cx_a.read(ActiveCall::global);
4390
4391    // Set up a fake language server.
4392    let mut language = Language::new(
4393        LanguageConfig {
4394            name: "Rust".into(),
4395            path_suffixes: vec!["rs".to_string()],
4396            ..Default::default()
4397        },
4398        Some(tree_sitter_rust::language()),
4399    );
4400    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4401    client_a.language_registry.add(Arc::new(language));
4402
4403    client_a
4404        .fs
4405        .insert_tree(
4406            "/root",
4407            json!({
4408                "dir-1": {
4409                    "a.rs": "const ONE: usize = b::TWO + b::THREE;",
4410                },
4411                "dir-2": {
4412                    "b.rs": "const TWO: c::T2 = 2;\nconst THREE: usize = 3;",
4413                    "c.rs": "type T2 = usize;",
4414                }
4415            }),
4416        )
4417        .await;
4418    let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await;
4419    let project_id = active_call_a
4420        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4421        .await
4422        .unwrap();
4423    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4424
4425    // Open the file on client B.
4426    let buffer_b = cx_b
4427        .background()
4428        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
4429        .await
4430        .unwrap();
4431
4432    // Request the definition of a symbol as the guest.
4433    let fake_language_server = fake_language_servers.next().await.unwrap();
4434    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
4435        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4436            lsp::Location::new(
4437                lsp::Url::from_file_path("/root/dir-2/b.rs").unwrap(),
4438                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
4439            ),
4440        )))
4441    });
4442
4443    let definitions_1 = project_b
4444        .update(cx_b, |p, cx| p.definition(&buffer_b, 23, cx))
4445        .await
4446        .unwrap();
4447    cx_b.read(|cx| {
4448        assert_eq!(definitions_1.len(), 1);
4449        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4450        let target_buffer = definitions_1[0].target.buffer.read(cx);
4451        assert_eq!(
4452            target_buffer.text(),
4453            "const TWO: c::T2 = 2;\nconst THREE: usize = 3;"
4454        );
4455        assert_eq!(
4456            definitions_1[0].target.range.to_point(target_buffer),
4457            Point::new(0, 6)..Point::new(0, 9)
4458        );
4459    });
4460
4461    // Try getting more definitions for the same buffer, ensuring the buffer gets reused from
4462    // the previous call to `definition`.
4463    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
4464        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4465            lsp::Location::new(
4466                lsp::Url::from_file_path("/root/dir-2/b.rs").unwrap(),
4467                lsp::Range::new(lsp::Position::new(1, 6), lsp::Position::new(1, 11)),
4468            ),
4469        )))
4470    });
4471
4472    let definitions_2 = project_b
4473        .update(cx_b, |p, cx| p.definition(&buffer_b, 33, cx))
4474        .await
4475        .unwrap();
4476    cx_b.read(|cx| {
4477        assert_eq!(definitions_2.len(), 1);
4478        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4479        let target_buffer = definitions_2[0].target.buffer.read(cx);
4480        assert_eq!(
4481            target_buffer.text(),
4482            "const TWO: c::T2 = 2;\nconst THREE: usize = 3;"
4483        );
4484        assert_eq!(
4485            definitions_2[0].target.range.to_point(target_buffer),
4486            Point::new(1, 6)..Point::new(1, 11)
4487        );
4488    });
4489    assert_eq!(
4490        definitions_1[0].target.buffer,
4491        definitions_2[0].target.buffer
4492    );
4493
4494    fake_language_server.handle_request::<lsp::request::GotoTypeDefinition, _, _>(
4495        |req, _| async move {
4496            assert_eq!(
4497                req.text_document_position_params.position,
4498                lsp::Position::new(0, 7)
4499            );
4500            Ok(Some(lsp::GotoDefinitionResponse::Scalar(
4501                lsp::Location::new(
4502                    lsp::Url::from_file_path("/root/dir-2/c.rs").unwrap(),
4503                    lsp::Range::new(lsp::Position::new(0, 5), lsp::Position::new(0, 7)),
4504                ),
4505            )))
4506        },
4507    );
4508
4509    let type_definitions = project_b
4510        .update(cx_b, |p, cx| p.type_definition(&buffer_b, 7, cx))
4511        .await
4512        .unwrap();
4513    cx_b.read(|cx| {
4514        assert_eq!(type_definitions.len(), 1);
4515        let target_buffer = type_definitions[0].target.buffer.read(cx);
4516        assert_eq!(target_buffer.text(), "type T2 = usize;");
4517        assert_eq!(
4518            type_definitions[0].target.range.to_point(target_buffer),
4519            Point::new(0, 5)..Point::new(0, 7)
4520        );
4521    });
4522}
4523
4524#[gpui::test(iterations = 10)]
4525async fn test_references(
4526    deterministic: Arc<Deterministic>,
4527    cx_a: &mut TestAppContext,
4528    cx_b: &mut TestAppContext,
4529) {
4530    deterministic.forbid_parking();
4531    let mut server = TestServer::start(&deterministic).await;
4532    let client_a = server.create_client(cx_a, "user_a").await;
4533    let client_b = server.create_client(cx_b, "user_b").await;
4534    server
4535        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4536        .await;
4537    let active_call_a = cx_a.read(ActiveCall::global);
4538
4539    // Set up a fake language server.
4540    let mut language = Language::new(
4541        LanguageConfig {
4542            name: "Rust".into(),
4543            path_suffixes: vec!["rs".to_string()],
4544            ..Default::default()
4545        },
4546        Some(tree_sitter_rust::language()),
4547    );
4548    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4549    client_a.language_registry.add(Arc::new(language));
4550
4551    client_a
4552        .fs
4553        .insert_tree(
4554            "/root",
4555            json!({
4556                "dir-1": {
4557                    "one.rs": "const ONE: usize = 1;",
4558                    "two.rs": "const TWO: usize = one::ONE + one::ONE;",
4559                },
4560                "dir-2": {
4561                    "three.rs": "const THREE: usize = two::TWO + one::ONE;",
4562                }
4563            }),
4564        )
4565        .await;
4566    let (project_a, worktree_id) = client_a.build_local_project("/root/dir-1", cx_a).await;
4567    let project_id = active_call_a
4568        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4569        .await
4570        .unwrap();
4571    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4572
4573    // Open the file on client B.
4574    let buffer_b = cx_b
4575        .background()
4576        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx)))
4577        .await
4578        .unwrap();
4579
4580    // Request references to a symbol as the guest.
4581    let fake_language_server = fake_language_servers.next().await.unwrap();
4582    fake_language_server.handle_request::<lsp::request::References, _, _>(|params, _| async move {
4583        assert_eq!(
4584            params.text_document_position.text_document.uri.as_str(),
4585            "file:///root/dir-1/one.rs"
4586        );
4587        Ok(Some(vec![
4588            lsp::Location {
4589                uri: lsp::Url::from_file_path("/root/dir-1/two.rs").unwrap(),
4590                range: lsp::Range::new(lsp::Position::new(0, 24), lsp::Position::new(0, 27)),
4591            },
4592            lsp::Location {
4593                uri: lsp::Url::from_file_path("/root/dir-1/two.rs").unwrap(),
4594                range: lsp::Range::new(lsp::Position::new(0, 35), lsp::Position::new(0, 38)),
4595            },
4596            lsp::Location {
4597                uri: lsp::Url::from_file_path("/root/dir-2/three.rs").unwrap(),
4598                range: lsp::Range::new(lsp::Position::new(0, 37), lsp::Position::new(0, 40)),
4599            },
4600        ]))
4601    });
4602
4603    let references = project_b
4604        .update(cx_b, |p, cx| p.references(&buffer_b, 7, cx))
4605        .await
4606        .unwrap();
4607    cx_b.read(|cx| {
4608        assert_eq!(references.len(), 3);
4609        assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
4610
4611        let two_buffer = references[0].buffer.read(cx);
4612        let three_buffer = references[2].buffer.read(cx);
4613        assert_eq!(
4614            two_buffer.file().unwrap().path().as_ref(),
4615            Path::new("two.rs")
4616        );
4617        assert_eq!(references[1].buffer, references[0].buffer);
4618        assert_eq!(
4619            three_buffer.file().unwrap().full_path(cx),
4620            Path::new("/root/dir-2/three.rs")
4621        );
4622
4623        assert_eq!(references[0].range.to_offset(two_buffer), 24..27);
4624        assert_eq!(references[1].range.to_offset(two_buffer), 35..38);
4625        assert_eq!(references[2].range.to_offset(three_buffer), 37..40);
4626    });
4627}
4628
4629#[gpui::test(iterations = 10)]
4630async fn test_project_search(
4631    deterministic: Arc<Deterministic>,
4632    cx_a: &mut TestAppContext,
4633    cx_b: &mut TestAppContext,
4634) {
4635    deterministic.forbid_parking();
4636    let mut server = TestServer::start(&deterministic).await;
4637    let client_a = server.create_client(cx_a, "user_a").await;
4638    let client_b = server.create_client(cx_b, "user_b").await;
4639    server
4640        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4641        .await;
4642    let active_call_a = cx_a.read(ActiveCall::global);
4643
4644    client_a
4645        .fs
4646        .insert_tree(
4647            "/root",
4648            json!({
4649                "dir-1": {
4650                    "a": "hello world",
4651                    "b": "goodnight moon",
4652                    "c": "a world of goo",
4653                    "d": "world champion of clown world",
4654                },
4655                "dir-2": {
4656                    "e": "disney world is fun",
4657                }
4658            }),
4659        )
4660        .await;
4661    let (project_a, _) = client_a.build_local_project("/root/dir-1", cx_a).await;
4662    let (worktree_2, _) = project_a
4663        .update(cx_a, |p, cx| {
4664            p.find_or_create_local_worktree("/root/dir-2", true, cx)
4665        })
4666        .await
4667        .unwrap();
4668    worktree_2
4669        .read_with(cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
4670        .await;
4671    let project_id = active_call_a
4672        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4673        .await
4674        .unwrap();
4675
4676    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4677
4678    // Perform a search as the guest.
4679    let results = project_b
4680        .update(cx_b, |project, cx| {
4681            project.search(
4682                SearchQuery::text("world", false, false, Vec::new(), Vec::new()),
4683                cx,
4684            )
4685        })
4686        .await
4687        .unwrap();
4688
4689    let mut ranges_by_path = results
4690        .into_iter()
4691        .map(|(buffer, ranges)| {
4692            buffer.read_with(cx_b, |buffer, cx| {
4693                let path = buffer.file().unwrap().full_path(cx);
4694                let offset_ranges = ranges
4695                    .into_iter()
4696                    .map(|range| range.to_offset(buffer))
4697                    .collect::<Vec<_>>();
4698                (path, offset_ranges)
4699            })
4700        })
4701        .collect::<Vec<_>>();
4702    ranges_by_path.sort_by_key(|(path, _)| path.clone());
4703
4704    assert_eq!(
4705        ranges_by_path,
4706        &[
4707            (PathBuf::from("dir-1/a"), vec![6..11]),
4708            (PathBuf::from("dir-1/c"), vec![2..7]),
4709            (PathBuf::from("dir-1/d"), vec![0..5, 24..29]),
4710            (PathBuf::from("dir-2/e"), vec![7..12]),
4711        ]
4712    );
4713}
4714
4715#[gpui::test(iterations = 10)]
4716async fn test_document_highlights(
4717    deterministic: Arc<Deterministic>,
4718    cx_a: &mut TestAppContext,
4719    cx_b: &mut TestAppContext,
4720) {
4721    deterministic.forbid_parking();
4722    let mut server = TestServer::start(&deterministic).await;
4723    let client_a = server.create_client(cx_a, "user_a").await;
4724    let client_b = server.create_client(cx_b, "user_b").await;
4725    server
4726        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4727        .await;
4728    let active_call_a = cx_a.read(ActiveCall::global);
4729
4730    client_a
4731        .fs
4732        .insert_tree(
4733            "/root-1",
4734            json!({
4735                "main.rs": "fn double(number: i32) -> i32 { number + number }",
4736            }),
4737        )
4738        .await;
4739
4740    // Set up a fake language server.
4741    let mut language = Language::new(
4742        LanguageConfig {
4743            name: "Rust".into(),
4744            path_suffixes: vec!["rs".to_string()],
4745            ..Default::default()
4746        },
4747        Some(tree_sitter_rust::language()),
4748    );
4749    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4750    client_a.language_registry.add(Arc::new(language));
4751
4752    let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
4753    let project_id = active_call_a
4754        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4755        .await
4756        .unwrap();
4757    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4758
4759    // Open the file on client B.
4760    let buffer_b = cx_b
4761        .background()
4762        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)))
4763        .await
4764        .unwrap();
4765
4766    // Request document highlights as the guest.
4767    let fake_language_server = fake_language_servers.next().await.unwrap();
4768    fake_language_server.handle_request::<lsp::request::DocumentHighlightRequest, _, _>(
4769        |params, _| async move {
4770            assert_eq!(
4771                params
4772                    .text_document_position_params
4773                    .text_document
4774                    .uri
4775                    .as_str(),
4776                "file:///root-1/main.rs"
4777            );
4778            assert_eq!(
4779                params.text_document_position_params.position,
4780                lsp::Position::new(0, 34)
4781            );
4782            Ok(Some(vec![
4783                lsp::DocumentHighlight {
4784                    kind: Some(lsp::DocumentHighlightKind::WRITE),
4785                    range: lsp::Range::new(lsp::Position::new(0, 10), lsp::Position::new(0, 16)),
4786                },
4787                lsp::DocumentHighlight {
4788                    kind: Some(lsp::DocumentHighlightKind::READ),
4789                    range: lsp::Range::new(lsp::Position::new(0, 32), lsp::Position::new(0, 38)),
4790                },
4791                lsp::DocumentHighlight {
4792                    kind: Some(lsp::DocumentHighlightKind::READ),
4793                    range: lsp::Range::new(lsp::Position::new(0, 41), lsp::Position::new(0, 47)),
4794                },
4795            ]))
4796        },
4797    );
4798
4799    let highlights = project_b
4800        .update(cx_b, |p, cx| p.document_highlights(&buffer_b, 34, cx))
4801        .await
4802        .unwrap();
4803    buffer_b.read_with(cx_b, |buffer, _| {
4804        let snapshot = buffer.snapshot();
4805
4806        let highlights = highlights
4807            .into_iter()
4808            .map(|highlight| (highlight.kind, highlight.range.to_offset(&snapshot)))
4809            .collect::<Vec<_>>();
4810        assert_eq!(
4811            highlights,
4812            &[
4813                (lsp::DocumentHighlightKind::WRITE, 10..16),
4814                (lsp::DocumentHighlightKind::READ, 32..38),
4815                (lsp::DocumentHighlightKind::READ, 41..47)
4816            ]
4817        )
4818    });
4819}
4820
4821#[gpui::test(iterations = 10)]
4822async fn test_lsp_hover(
4823    deterministic: Arc<Deterministic>,
4824    cx_a: &mut TestAppContext,
4825    cx_b: &mut TestAppContext,
4826) {
4827    deterministic.forbid_parking();
4828    let mut server = TestServer::start(&deterministic).await;
4829    let client_a = server.create_client(cx_a, "user_a").await;
4830    let client_b = server.create_client(cx_b, "user_b").await;
4831    server
4832        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4833        .await;
4834    let active_call_a = cx_a.read(ActiveCall::global);
4835
4836    client_a
4837        .fs
4838        .insert_tree(
4839            "/root-1",
4840            json!({
4841                "main.rs": "use std::collections::HashMap;",
4842            }),
4843        )
4844        .await;
4845
4846    // Set up a fake language server.
4847    let mut language = Language::new(
4848        LanguageConfig {
4849            name: "Rust".into(),
4850            path_suffixes: vec!["rs".to_string()],
4851            ..Default::default()
4852        },
4853        Some(tree_sitter_rust::language()),
4854    );
4855    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4856    client_a.language_registry.add(Arc::new(language));
4857
4858    let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
4859    let project_id = active_call_a
4860        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4861        .await
4862        .unwrap();
4863    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4864
4865    // Open the file as the guest
4866    let buffer_b = cx_b
4867        .background()
4868        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx)))
4869        .await
4870        .unwrap();
4871
4872    // Request hover information as the guest.
4873    let fake_language_server = fake_language_servers.next().await.unwrap();
4874    fake_language_server.handle_request::<lsp::request::HoverRequest, _, _>(
4875        |params, _| async move {
4876            assert_eq!(
4877                params
4878                    .text_document_position_params
4879                    .text_document
4880                    .uri
4881                    .as_str(),
4882                "file:///root-1/main.rs"
4883            );
4884            assert_eq!(
4885                params.text_document_position_params.position,
4886                lsp::Position::new(0, 22)
4887            );
4888            Ok(Some(lsp::Hover {
4889                contents: lsp::HoverContents::Array(vec![
4890                    lsp::MarkedString::String("Test hover content.".to_string()),
4891                    lsp::MarkedString::LanguageString(lsp::LanguageString {
4892                        language: "Rust".to_string(),
4893                        value: "let foo = 42;".to_string(),
4894                    }),
4895                ]),
4896                range: Some(lsp::Range::new(
4897                    lsp::Position::new(0, 22),
4898                    lsp::Position::new(0, 29),
4899                )),
4900            }))
4901        },
4902    );
4903
4904    let hover_info = project_b
4905        .update(cx_b, |p, cx| p.hover(&buffer_b, 22, cx))
4906        .await
4907        .unwrap()
4908        .unwrap();
4909    buffer_b.read_with(cx_b, |buffer, _| {
4910        let snapshot = buffer.snapshot();
4911        assert_eq!(hover_info.range.unwrap().to_offset(&snapshot), 22..29);
4912        assert_eq!(
4913            hover_info.contents,
4914            vec![
4915                project::HoverBlock {
4916                    text: "Test hover content.".to_string(),
4917                    kind: HoverBlockKind::Markdown,
4918                },
4919                project::HoverBlock {
4920                    text: "let foo = 42;".to_string(),
4921                    kind: HoverBlockKind::Code {
4922                        language: "Rust".to_string()
4923                    },
4924                }
4925            ]
4926        );
4927    });
4928}
4929
4930#[gpui::test(iterations = 10)]
4931async fn test_project_symbols(
4932    deterministic: Arc<Deterministic>,
4933    cx_a: &mut TestAppContext,
4934    cx_b: &mut TestAppContext,
4935) {
4936    deterministic.forbid_parking();
4937    let mut server = TestServer::start(&deterministic).await;
4938    let client_a = server.create_client(cx_a, "user_a").await;
4939    let client_b = server.create_client(cx_b, "user_b").await;
4940    server
4941        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
4942        .await;
4943    let active_call_a = cx_a.read(ActiveCall::global);
4944
4945    // Set up a fake language server.
4946    let mut language = Language::new(
4947        LanguageConfig {
4948            name: "Rust".into(),
4949            path_suffixes: vec!["rs".to_string()],
4950            ..Default::default()
4951        },
4952        Some(tree_sitter_rust::language()),
4953    );
4954    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
4955    client_a.language_registry.add(Arc::new(language));
4956
4957    client_a
4958        .fs
4959        .insert_tree(
4960            "/code",
4961            json!({
4962                "crate-1": {
4963                    "one.rs": "const ONE: usize = 1;",
4964                },
4965                "crate-2": {
4966                    "two.rs": "const TWO: usize = 2; const THREE: usize = 3;",
4967                },
4968                "private": {
4969                    "passwords.txt": "the-password",
4970                }
4971            }),
4972        )
4973        .await;
4974    let (project_a, worktree_id) = client_a.build_local_project("/code/crate-1", cx_a).await;
4975    let project_id = active_call_a
4976        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
4977        .await
4978        .unwrap();
4979    let project_b = client_b.build_remote_project(project_id, cx_b).await;
4980
4981    // Cause the language server to start.
4982    let _buffer = cx_b
4983        .background()
4984        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx)))
4985        .await
4986        .unwrap();
4987
4988    let fake_language_server = fake_language_servers.next().await.unwrap();
4989    fake_language_server.handle_request::<lsp::WorkspaceSymbolRequest, _, _>(|_, _| async move {
4990        Ok(Some(lsp::WorkspaceSymbolResponse::Flat(vec![
4991            #[allow(deprecated)]
4992            lsp::SymbolInformation {
4993                name: "TWO".into(),
4994                location: lsp::Location {
4995                    uri: lsp::Url::from_file_path("/code/crate-2/two.rs").unwrap(),
4996                    range: lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
4997                },
4998                kind: lsp::SymbolKind::CONSTANT,
4999                tags: None,
5000                container_name: None,
5001                deprecated: None,
5002            },
5003        ])))
5004    });
5005
5006    // Request the definition of a symbol as the guest.
5007    let symbols = project_b
5008        .update(cx_b, |p, cx| p.symbols("two", cx))
5009        .await
5010        .unwrap();
5011    assert_eq!(symbols.len(), 1);
5012    assert_eq!(symbols[0].name, "TWO");
5013
5014    // Open one of the returned symbols.
5015    let buffer_b_2 = project_b
5016        .update(cx_b, |project, cx| {
5017            project.open_buffer_for_symbol(&symbols[0], cx)
5018        })
5019        .await
5020        .unwrap();
5021    buffer_b_2.read_with(cx_b, |buffer, _| {
5022        assert_eq!(
5023            buffer.file().unwrap().path().as_ref(),
5024            Path::new("../crate-2/two.rs")
5025        );
5026    });
5027
5028    // Attempt to craft a symbol and violate host's privacy by opening an arbitrary file.
5029    let mut fake_symbol = symbols[0].clone();
5030    fake_symbol.path.path = Path::new("/code/secrets").into();
5031    let error = project_b
5032        .update(cx_b, |project, cx| {
5033            project.open_buffer_for_symbol(&fake_symbol, cx)
5034        })
5035        .await
5036        .unwrap_err();
5037    assert!(error.to_string().contains("invalid symbol signature"));
5038}
5039
5040#[gpui::test(iterations = 10)]
5041async fn test_open_buffer_while_getting_definition_pointing_to_it(
5042    deterministic: Arc<Deterministic>,
5043    cx_a: &mut TestAppContext,
5044    cx_b: &mut TestAppContext,
5045    mut rng: StdRng,
5046) {
5047    deterministic.forbid_parking();
5048    let mut server = TestServer::start(&deterministic).await;
5049    let client_a = server.create_client(cx_a, "user_a").await;
5050    let client_b = server.create_client(cx_b, "user_b").await;
5051    server
5052        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
5053        .await;
5054    let active_call_a = cx_a.read(ActiveCall::global);
5055
5056    // Set up a fake language server.
5057    let mut language = Language::new(
5058        LanguageConfig {
5059            name: "Rust".into(),
5060            path_suffixes: vec!["rs".to_string()],
5061            ..Default::default()
5062        },
5063        Some(tree_sitter_rust::language()),
5064    );
5065    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
5066    client_a.language_registry.add(Arc::new(language));
5067
5068    client_a
5069        .fs
5070        .insert_tree(
5071            "/root",
5072            json!({
5073                "a.rs": "const ONE: usize = b::TWO;",
5074                "b.rs": "const TWO: usize = 2",
5075            }),
5076        )
5077        .await;
5078    let (project_a, worktree_id) = client_a.build_local_project("/root", cx_a).await;
5079    let project_id = active_call_a
5080        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5081        .await
5082        .unwrap();
5083    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5084
5085    let buffer_b1 = cx_b
5086        .background()
5087        .spawn(project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx)))
5088        .await
5089        .unwrap();
5090
5091    let fake_language_server = fake_language_servers.next().await.unwrap();
5092    fake_language_server.handle_request::<lsp::request::GotoDefinition, _, _>(|_, _| async move {
5093        Ok(Some(lsp::GotoDefinitionResponse::Scalar(
5094            lsp::Location::new(
5095                lsp::Url::from_file_path("/root/b.rs").unwrap(),
5096                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
5097            ),
5098        )))
5099    });
5100
5101    let definitions;
5102    let buffer_b2;
5103    if rng.gen() {
5104        definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
5105        buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
5106    } else {
5107        buffer_b2 = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.rs"), cx));
5108        definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
5109    }
5110
5111    let buffer_b2 = buffer_b2.await.unwrap();
5112    let definitions = definitions.await.unwrap();
5113    assert_eq!(definitions.len(), 1);
5114    assert_eq!(definitions[0].target.buffer, buffer_b2);
5115}
5116
5117#[gpui::test(iterations = 10)]
5118async fn test_collaborating_with_code_actions(
5119    deterministic: Arc<Deterministic>,
5120    cx_a: &mut TestAppContext,
5121    cx_b: &mut TestAppContext,
5122) {
5123    deterministic.forbid_parking();
5124    let mut server = TestServer::start(&deterministic).await;
5125    let client_a = server.create_client(cx_a, "user_a").await;
5126    let client_b = server.create_client(cx_b, "user_b").await;
5127    server
5128        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
5129        .await;
5130    let active_call_a = cx_a.read(ActiveCall::global);
5131
5132    cx_b.update(editor::init);
5133
5134    // Set up a fake language server.
5135    let mut language = Language::new(
5136        LanguageConfig {
5137            name: "Rust".into(),
5138            path_suffixes: vec!["rs".to_string()],
5139            ..Default::default()
5140        },
5141        Some(tree_sitter_rust::language()),
5142    );
5143    let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
5144    client_a.language_registry.add(Arc::new(language));
5145
5146    client_a
5147        .fs
5148        .insert_tree(
5149            "/a",
5150            json!({
5151                "main.rs": "mod other;\nfn main() { let foo = other::foo(); }",
5152                "other.rs": "pub fn foo() -> usize { 4 }",
5153            }),
5154        )
5155        .await;
5156    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
5157    let project_id = active_call_a
5158        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5159        .await
5160        .unwrap();
5161
5162    // Join the project as client B.
5163    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5164    let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
5165    let editor_b = workspace_b
5166        .update(cx_b, |workspace, cx| {
5167            workspace.open_path((worktree_id, "main.rs"), None, true, cx)
5168        })
5169        .await
5170        .unwrap()
5171        .downcast::<Editor>()
5172        .unwrap();
5173
5174    let mut fake_language_server = fake_language_servers.next().await.unwrap();
5175    fake_language_server
5176        .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
5177            assert_eq!(
5178                params.text_document.uri,
5179                lsp::Url::from_file_path("/a/main.rs").unwrap(),
5180            );
5181            assert_eq!(params.range.start, lsp::Position::new(0, 0));
5182            assert_eq!(params.range.end, lsp::Position::new(0, 0));
5183            Ok(None)
5184        })
5185        .next()
5186        .await;
5187
5188    // Move cursor to a location that contains code actions.
5189    editor_b.update(cx_b, |editor, cx| {
5190        editor.change_selections(None, cx, |s| {
5191            s.select_ranges([Point::new(1, 31)..Point::new(1, 31)])
5192        });
5193        cx.focus(&editor_b);
5194    });
5195
5196    fake_language_server
5197        .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
5198            assert_eq!(
5199                params.text_document.uri,
5200                lsp::Url::from_file_path("/a/main.rs").unwrap(),
5201            );
5202            assert_eq!(params.range.start, lsp::Position::new(1, 31));
5203            assert_eq!(params.range.end, lsp::Position::new(1, 31));
5204
5205            Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
5206                lsp::CodeAction {
5207                    title: "Inline into all callers".to_string(),
5208                    edit: Some(lsp::WorkspaceEdit {
5209                        changes: Some(
5210                            [
5211                                (
5212                                    lsp::Url::from_file_path("/a/main.rs").unwrap(),
5213                                    vec![lsp::TextEdit::new(
5214                                        lsp::Range::new(
5215                                            lsp::Position::new(1, 22),
5216                                            lsp::Position::new(1, 34),
5217                                        ),
5218                                        "4".to_string(),
5219                                    )],
5220                                ),
5221                                (
5222                                    lsp::Url::from_file_path("/a/other.rs").unwrap(),
5223                                    vec![lsp::TextEdit::new(
5224                                        lsp::Range::new(
5225                                            lsp::Position::new(0, 0),
5226                                            lsp::Position::new(0, 27),
5227                                        ),
5228                                        "".to_string(),
5229                                    )],
5230                                ),
5231                            ]
5232                            .into_iter()
5233                            .collect(),
5234                        ),
5235                        ..Default::default()
5236                    }),
5237                    data: Some(json!({
5238                        "codeActionParams": {
5239                            "range": {
5240                                "start": {"line": 1, "column": 31},
5241                                "end": {"line": 1, "column": 31},
5242                            }
5243                        }
5244                    })),
5245                    ..Default::default()
5246                },
5247            )]))
5248        })
5249        .next()
5250        .await;
5251
5252    // Toggle code actions and wait for them to display.
5253    editor_b.update(cx_b, |editor, cx| {
5254        editor.toggle_code_actions(
5255            &ToggleCodeActions {
5256                deployed_from_indicator: false,
5257            },
5258            cx,
5259        );
5260    });
5261    cx_a.foreground().run_until_parked();
5262    editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
5263
5264    fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>();
5265
5266    // Confirming the code action will trigger a resolve request.
5267    let confirm_action = workspace_b
5268        .update(cx_b, |workspace, cx| {
5269            Editor::confirm_code_action(workspace, &ConfirmCodeAction { item_ix: Some(0) }, cx)
5270        })
5271        .unwrap();
5272    fake_language_server.handle_request::<lsp::request::CodeActionResolveRequest, _, _>(
5273        |_, _| async move {
5274            Ok(lsp::CodeAction {
5275                title: "Inline into all callers".to_string(),
5276                edit: Some(lsp::WorkspaceEdit {
5277                    changes: Some(
5278                        [
5279                            (
5280                                lsp::Url::from_file_path("/a/main.rs").unwrap(),
5281                                vec![lsp::TextEdit::new(
5282                                    lsp::Range::new(
5283                                        lsp::Position::new(1, 22),
5284                                        lsp::Position::new(1, 34),
5285                                    ),
5286                                    "4".to_string(),
5287                                )],
5288                            ),
5289                            (
5290                                lsp::Url::from_file_path("/a/other.rs").unwrap(),
5291                                vec![lsp::TextEdit::new(
5292                                    lsp::Range::new(
5293                                        lsp::Position::new(0, 0),
5294                                        lsp::Position::new(0, 27),
5295                                    ),
5296                                    "".to_string(),
5297                                )],
5298                            ),
5299                        ]
5300                        .into_iter()
5301                        .collect(),
5302                    ),
5303                    ..Default::default()
5304                }),
5305                ..Default::default()
5306            })
5307        },
5308    );
5309
5310    // After the action is confirmed, an editor containing both modified files is opened.
5311    confirm_action.await.unwrap();
5312    let code_action_editor = workspace_b.read_with(cx_b, |workspace, cx| {
5313        workspace
5314            .active_item(cx)
5315            .unwrap()
5316            .downcast::<Editor>()
5317            .unwrap()
5318    });
5319    code_action_editor.update(cx_b, |editor, cx| {
5320        assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
5321        editor.undo(&Undo, cx);
5322        assert_eq!(
5323            editor.text(cx),
5324            "mod other;\nfn main() { let foo = other::foo(); }\npub fn foo() -> usize { 4 }"
5325        );
5326        editor.redo(&Redo, cx);
5327        assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
5328    });
5329}
5330
5331#[gpui::test(iterations = 10)]
5332async fn test_collaborating_with_renames(
5333    deterministic: Arc<Deterministic>,
5334    cx_a: &mut TestAppContext,
5335    cx_b: &mut TestAppContext,
5336) {
5337    deterministic.forbid_parking();
5338    let mut server = TestServer::start(&deterministic).await;
5339    let client_a = server.create_client(cx_a, "user_a").await;
5340    let client_b = server.create_client(cx_b, "user_b").await;
5341    server
5342        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
5343        .await;
5344    let active_call_a = cx_a.read(ActiveCall::global);
5345
5346    cx_b.update(editor::init);
5347
5348    // Set up a fake language server.
5349    let mut language = Language::new(
5350        LanguageConfig {
5351            name: "Rust".into(),
5352            path_suffixes: vec!["rs".to_string()],
5353            ..Default::default()
5354        },
5355        Some(tree_sitter_rust::language()),
5356    );
5357    let mut fake_language_servers = language
5358        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
5359            capabilities: lsp::ServerCapabilities {
5360                rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
5361                    prepare_provider: Some(true),
5362                    work_done_progress_options: Default::default(),
5363                })),
5364                ..Default::default()
5365            },
5366            ..Default::default()
5367        }))
5368        .await;
5369    client_a.language_registry.add(Arc::new(language));
5370
5371    client_a
5372        .fs
5373        .insert_tree(
5374            "/dir",
5375            json!({
5376                "one.rs": "const ONE: usize = 1;",
5377                "two.rs": "const TWO: usize = one::ONE + one::ONE;"
5378            }),
5379        )
5380        .await;
5381    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
5382    let project_id = active_call_a
5383        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5384        .await
5385        .unwrap();
5386    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5387
5388    let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx));
5389    let editor_b = workspace_b
5390        .update(cx_b, |workspace, cx| {
5391            workspace.open_path((worktree_id, "one.rs"), None, true, cx)
5392        })
5393        .await
5394        .unwrap()
5395        .downcast::<Editor>()
5396        .unwrap();
5397    let fake_language_server = fake_language_servers.next().await.unwrap();
5398
5399    // Move cursor to a location that can be renamed.
5400    let prepare_rename = editor_b.update(cx_b, |editor, cx| {
5401        editor.change_selections(None, cx, |s| s.select_ranges([7..7]));
5402        editor.rename(&Rename, cx).unwrap()
5403    });
5404
5405    fake_language_server
5406        .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
5407            assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
5408            assert_eq!(params.position, lsp::Position::new(0, 7));
5409            Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
5410                lsp::Position::new(0, 6),
5411                lsp::Position::new(0, 9),
5412            ))))
5413        })
5414        .next()
5415        .await
5416        .unwrap();
5417    prepare_rename.await.unwrap();
5418    editor_b.update(cx_b, |editor, cx| {
5419        let rename = editor.pending_rename().unwrap();
5420        let buffer = editor.buffer().read(cx).snapshot(cx);
5421        assert_eq!(
5422            rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
5423            6..9
5424        );
5425        rename.editor.update(cx, |rename_editor, cx| {
5426            rename_editor.buffer().update(cx, |rename_buffer, cx| {
5427                rename_buffer.edit([(0..3, "THREE")], None, cx);
5428            });
5429        });
5430    });
5431
5432    let confirm_rename = workspace_b.update(cx_b, |workspace, cx| {
5433        Editor::confirm_rename(workspace, &ConfirmRename, cx).unwrap()
5434    });
5435    fake_language_server
5436        .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
5437            assert_eq!(
5438                params.text_document_position.text_document.uri.as_str(),
5439                "file:///dir/one.rs"
5440            );
5441            assert_eq!(
5442                params.text_document_position.position,
5443                lsp::Position::new(0, 6)
5444            );
5445            assert_eq!(params.new_name, "THREE");
5446            Ok(Some(lsp::WorkspaceEdit {
5447                changes: Some(
5448                    [
5449                        (
5450                            lsp::Url::from_file_path("/dir/one.rs").unwrap(),
5451                            vec![lsp::TextEdit::new(
5452                                lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
5453                                "THREE".to_string(),
5454                            )],
5455                        ),
5456                        (
5457                            lsp::Url::from_file_path("/dir/two.rs").unwrap(),
5458                            vec![
5459                                lsp::TextEdit::new(
5460                                    lsp::Range::new(
5461                                        lsp::Position::new(0, 24),
5462                                        lsp::Position::new(0, 27),
5463                                    ),
5464                                    "THREE".to_string(),
5465                                ),
5466                                lsp::TextEdit::new(
5467                                    lsp::Range::new(
5468                                        lsp::Position::new(0, 35),
5469                                        lsp::Position::new(0, 38),
5470                                    ),
5471                                    "THREE".to_string(),
5472                                ),
5473                            ],
5474                        ),
5475                    ]
5476                    .into_iter()
5477                    .collect(),
5478                ),
5479                ..Default::default()
5480            }))
5481        })
5482        .next()
5483        .await
5484        .unwrap();
5485    confirm_rename.await.unwrap();
5486
5487    let rename_editor = workspace_b.read_with(cx_b, |workspace, cx| {
5488        workspace
5489            .active_item(cx)
5490            .unwrap()
5491            .downcast::<Editor>()
5492            .unwrap()
5493    });
5494    rename_editor.update(cx_b, |editor, cx| {
5495        assert_eq!(
5496            editor.text(cx),
5497            "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
5498        );
5499        editor.undo(&Undo, cx);
5500        assert_eq!(
5501            editor.text(cx),
5502            "const ONE: usize = 1;\nconst TWO: usize = one::ONE + one::ONE;"
5503        );
5504        editor.redo(&Redo, cx);
5505        assert_eq!(
5506            editor.text(cx),
5507            "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
5508        );
5509    });
5510
5511    // Ensure temporary rename edits cannot be undone/redone.
5512    editor_b.update(cx_b, |editor, cx| {
5513        editor.undo(&Undo, cx);
5514        assert_eq!(editor.text(cx), "const ONE: usize = 1;");
5515        editor.undo(&Undo, cx);
5516        assert_eq!(editor.text(cx), "const ONE: usize = 1;");
5517        editor.redo(&Redo, cx);
5518        assert_eq!(editor.text(cx), "const THREE: usize = 1;");
5519    })
5520}
5521
5522#[gpui::test(iterations = 10)]
5523async fn test_language_server_statuses(
5524    deterministic: Arc<Deterministic>,
5525    cx_a: &mut TestAppContext,
5526    cx_b: &mut TestAppContext,
5527) {
5528    deterministic.forbid_parking();
5529    let mut server = TestServer::start(&deterministic).await;
5530    let client_a = server.create_client(cx_a, "user_a").await;
5531    let client_b = server.create_client(cx_b, "user_b").await;
5532    server
5533        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
5534        .await;
5535    let active_call_a = cx_a.read(ActiveCall::global);
5536
5537    cx_b.update(editor::init);
5538
5539    // Set up a fake language server.
5540    let mut language = Language::new(
5541        LanguageConfig {
5542            name: "Rust".into(),
5543            path_suffixes: vec!["rs".to_string()],
5544            ..Default::default()
5545        },
5546        Some(tree_sitter_rust::language()),
5547    );
5548    let mut fake_language_servers = language
5549        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
5550            name: "the-language-server",
5551            ..Default::default()
5552        }))
5553        .await;
5554    client_a.language_registry.add(Arc::new(language));
5555
5556    client_a
5557        .fs
5558        .insert_tree(
5559            "/dir",
5560            json!({
5561                "main.rs": "const ONE: usize = 1;",
5562            }),
5563        )
5564        .await;
5565    let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
5566
5567    let _buffer_a = project_a
5568        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
5569        .await
5570        .unwrap();
5571
5572    let fake_language_server = fake_language_servers.next().await.unwrap();
5573    fake_language_server.start_progress("the-token").await;
5574    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
5575        token: lsp::NumberOrString::String("the-token".to_string()),
5576        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
5577            lsp::WorkDoneProgressReport {
5578                message: Some("the-message".to_string()),
5579                ..Default::default()
5580            },
5581        )),
5582    });
5583    deterministic.run_until_parked();
5584    project_a.read_with(cx_a, |project, _| {
5585        let status = project.language_server_statuses().next().unwrap();
5586        assert_eq!(status.name, "the-language-server");
5587        assert_eq!(status.pending_work.len(), 1);
5588        assert_eq!(
5589            status.pending_work["the-token"].message.as_ref().unwrap(),
5590            "the-message"
5591        );
5592    });
5593
5594    let project_id = active_call_a
5595        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
5596        .await
5597        .unwrap();
5598    deterministic.run_until_parked();
5599    let project_b = client_b.build_remote_project(project_id, cx_b).await;
5600    project_b.read_with(cx_b, |project, _| {
5601        let status = project.language_server_statuses().next().unwrap();
5602        assert_eq!(status.name, "the-language-server");
5603    });
5604
5605    fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
5606        token: lsp::NumberOrString::String("the-token".to_string()),
5607        value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
5608            lsp::WorkDoneProgressReport {
5609                message: Some("the-message-2".to_string()),
5610                ..Default::default()
5611            },
5612        )),
5613    });
5614    deterministic.run_until_parked();
5615    project_a.read_with(cx_a, |project, _| {
5616        let status = project.language_server_statuses().next().unwrap();
5617        assert_eq!(status.name, "the-language-server");
5618        assert_eq!(status.pending_work.len(), 1);
5619        assert_eq!(
5620            status.pending_work["the-token"].message.as_ref().unwrap(),
5621            "the-message-2"
5622        );
5623    });
5624    project_b.read_with(cx_b, |project, _| {
5625        let status = project.language_server_statuses().next().unwrap();
5626        assert_eq!(status.name, "the-language-server");
5627        assert_eq!(status.pending_work.len(), 1);
5628        assert_eq!(
5629            status.pending_work["the-token"].message.as_ref().unwrap(),
5630            "the-message-2"
5631        );
5632    });
5633}
5634
5635#[gpui::test(iterations = 10)]
5636async fn test_contacts(
5637    deterministic: Arc<Deterministic>,
5638    cx_a: &mut TestAppContext,
5639    cx_b: &mut TestAppContext,
5640    cx_c: &mut TestAppContext,
5641    cx_d: &mut TestAppContext,
5642) {
5643    deterministic.forbid_parking();
5644    let mut server = TestServer::start(&deterministic).await;
5645    let client_a = server.create_client(cx_a, "user_a").await;
5646    let client_b = server.create_client(cx_b, "user_b").await;
5647    let client_c = server.create_client(cx_c, "user_c").await;
5648    let client_d = server.create_client(cx_d, "user_d").await;
5649    server
5650        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
5651        .await;
5652    let active_call_a = cx_a.read(ActiveCall::global);
5653    let active_call_b = cx_b.read(ActiveCall::global);
5654    let active_call_c = cx_c.read(ActiveCall::global);
5655    let _active_call_d = cx_d.read(ActiveCall::global);
5656
5657    deterministic.run_until_parked();
5658    assert_eq!(
5659        contacts(&client_a, cx_a),
5660        [
5661            ("user_b".to_string(), "online", "free"),
5662            ("user_c".to_string(), "online", "free")
5663        ]
5664    );
5665    assert_eq!(
5666        contacts(&client_b, cx_b),
5667        [
5668            ("user_a".to_string(), "online", "free"),
5669            ("user_c".to_string(), "online", "free")
5670        ]
5671    );
5672    assert_eq!(
5673        contacts(&client_c, cx_c),
5674        [
5675            ("user_a".to_string(), "online", "free"),
5676            ("user_b".to_string(), "online", "free")
5677        ]
5678    );
5679    assert_eq!(contacts(&client_d, cx_d), []);
5680
5681    server.disconnect_client(client_c.peer_id().unwrap());
5682    server.forbid_connections();
5683    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
5684    assert_eq!(
5685        contacts(&client_a, cx_a),
5686        [
5687            ("user_b".to_string(), "online", "free"),
5688            ("user_c".to_string(), "offline", "free")
5689        ]
5690    );
5691    assert_eq!(
5692        contacts(&client_b, cx_b),
5693        [
5694            ("user_a".to_string(), "online", "free"),
5695            ("user_c".to_string(), "offline", "free")
5696        ]
5697    );
5698    assert_eq!(contacts(&client_c, cx_c), []);
5699    assert_eq!(contacts(&client_d, cx_d), []);
5700
5701    server.allow_connections();
5702    client_c
5703        .authenticate_and_connect(false, &cx_c.to_async())
5704        .await
5705        .unwrap();
5706
5707    deterministic.run_until_parked();
5708    assert_eq!(
5709        contacts(&client_a, cx_a),
5710        [
5711            ("user_b".to_string(), "online", "free"),
5712            ("user_c".to_string(), "online", "free")
5713        ]
5714    );
5715    assert_eq!(
5716        contacts(&client_b, cx_b),
5717        [
5718            ("user_a".to_string(), "online", "free"),
5719            ("user_c".to_string(), "online", "free")
5720        ]
5721    );
5722    assert_eq!(
5723        contacts(&client_c, cx_c),
5724        [
5725            ("user_a".to_string(), "online", "free"),
5726            ("user_b".to_string(), "online", "free")
5727        ]
5728    );
5729    assert_eq!(contacts(&client_d, cx_d), []);
5730
5731    active_call_a
5732        .update(cx_a, |call, cx| {
5733            call.invite(client_b.user_id().unwrap(), None, cx)
5734        })
5735        .await
5736        .unwrap();
5737    deterministic.run_until_parked();
5738    assert_eq!(
5739        contacts(&client_a, cx_a),
5740        [
5741            ("user_b".to_string(), "online", "busy"),
5742            ("user_c".to_string(), "online", "free")
5743        ]
5744    );
5745    assert_eq!(
5746        contacts(&client_b, cx_b),
5747        [
5748            ("user_a".to_string(), "online", "busy"),
5749            ("user_c".to_string(), "online", "free")
5750        ]
5751    );
5752    assert_eq!(
5753        contacts(&client_c, cx_c),
5754        [
5755            ("user_a".to_string(), "online", "busy"),
5756            ("user_b".to_string(), "online", "busy")
5757        ]
5758    );
5759    assert_eq!(contacts(&client_d, cx_d), []);
5760
5761    // Client B and client D become contacts while client B is being called.
5762    server
5763        .make_contacts(&mut [(&client_b, cx_b), (&client_d, cx_d)])
5764        .await;
5765    deterministic.run_until_parked();
5766    assert_eq!(
5767        contacts(&client_a, cx_a),
5768        [
5769            ("user_b".to_string(), "online", "busy"),
5770            ("user_c".to_string(), "online", "free")
5771        ]
5772    );
5773    assert_eq!(
5774        contacts(&client_b, cx_b),
5775        [
5776            ("user_a".to_string(), "online", "busy"),
5777            ("user_c".to_string(), "online", "free"),
5778            ("user_d".to_string(), "online", "free"),
5779        ]
5780    );
5781    assert_eq!(
5782        contacts(&client_c, cx_c),
5783        [
5784            ("user_a".to_string(), "online", "busy"),
5785            ("user_b".to_string(), "online", "busy")
5786        ]
5787    );
5788    assert_eq!(
5789        contacts(&client_d, cx_d),
5790        [("user_b".to_string(), "online", "busy")]
5791    );
5792
5793    active_call_b.update(cx_b, |call, _| call.decline_incoming().unwrap());
5794    deterministic.run_until_parked();
5795    assert_eq!(
5796        contacts(&client_a, cx_a),
5797        [
5798            ("user_b".to_string(), "online", "free"),
5799            ("user_c".to_string(), "online", "free")
5800        ]
5801    );
5802    assert_eq!(
5803        contacts(&client_b, cx_b),
5804        [
5805            ("user_a".to_string(), "online", "free"),
5806            ("user_c".to_string(), "online", "free"),
5807            ("user_d".to_string(), "online", "free")
5808        ]
5809    );
5810    assert_eq!(
5811        contacts(&client_c, cx_c),
5812        [
5813            ("user_a".to_string(), "online", "free"),
5814            ("user_b".to_string(), "online", "free")
5815        ]
5816    );
5817    assert_eq!(
5818        contacts(&client_d, cx_d),
5819        [("user_b".to_string(), "online", "free")]
5820    );
5821
5822    active_call_c
5823        .update(cx_c, |call, cx| {
5824            call.invite(client_a.user_id().unwrap(), None, cx)
5825        })
5826        .await
5827        .unwrap();
5828    deterministic.run_until_parked();
5829    assert_eq!(
5830        contacts(&client_a, cx_a),
5831        [
5832            ("user_b".to_string(), "online", "free"),
5833            ("user_c".to_string(), "online", "busy")
5834        ]
5835    );
5836    assert_eq!(
5837        contacts(&client_b, cx_b),
5838        [
5839            ("user_a".to_string(), "online", "busy"),
5840            ("user_c".to_string(), "online", "busy"),
5841            ("user_d".to_string(), "online", "free")
5842        ]
5843    );
5844    assert_eq!(
5845        contacts(&client_c, cx_c),
5846        [
5847            ("user_a".to_string(), "online", "busy"),
5848            ("user_b".to_string(), "online", "free")
5849        ]
5850    );
5851    assert_eq!(
5852        contacts(&client_d, cx_d),
5853        [("user_b".to_string(), "online", "free")]
5854    );
5855
5856    active_call_a
5857        .update(cx_a, |call, cx| call.accept_incoming(cx))
5858        .await
5859        .unwrap();
5860    deterministic.run_until_parked();
5861    assert_eq!(
5862        contacts(&client_a, cx_a),
5863        [
5864            ("user_b".to_string(), "online", "free"),
5865            ("user_c".to_string(), "online", "busy")
5866        ]
5867    );
5868    assert_eq!(
5869        contacts(&client_b, cx_b),
5870        [
5871            ("user_a".to_string(), "online", "busy"),
5872            ("user_c".to_string(), "online", "busy"),
5873            ("user_d".to_string(), "online", "free")
5874        ]
5875    );
5876    assert_eq!(
5877        contacts(&client_c, cx_c),
5878        [
5879            ("user_a".to_string(), "online", "busy"),
5880            ("user_b".to_string(), "online", "free")
5881        ]
5882    );
5883    assert_eq!(
5884        contacts(&client_d, cx_d),
5885        [("user_b".to_string(), "online", "free")]
5886    );
5887
5888    active_call_a
5889        .update(cx_a, |call, cx| {
5890            call.invite(client_b.user_id().unwrap(), None, cx)
5891        })
5892        .await
5893        .unwrap();
5894    deterministic.run_until_parked();
5895    assert_eq!(
5896        contacts(&client_a, cx_a),
5897        [
5898            ("user_b".to_string(), "online", "busy"),
5899            ("user_c".to_string(), "online", "busy")
5900        ]
5901    );
5902    assert_eq!(
5903        contacts(&client_b, cx_b),
5904        [
5905            ("user_a".to_string(), "online", "busy"),
5906            ("user_c".to_string(), "online", "busy"),
5907            ("user_d".to_string(), "online", "free")
5908        ]
5909    );
5910    assert_eq!(
5911        contacts(&client_c, cx_c),
5912        [
5913            ("user_a".to_string(), "online", "busy"),
5914            ("user_b".to_string(), "online", "busy")
5915        ]
5916    );
5917    assert_eq!(
5918        contacts(&client_d, cx_d),
5919        [("user_b".to_string(), "online", "busy")]
5920    );
5921
5922    active_call_a
5923        .update(cx_a, |call, cx| call.hang_up(cx))
5924        .await
5925        .unwrap();
5926    deterministic.run_until_parked();
5927    assert_eq!(
5928        contacts(&client_a, cx_a),
5929        [
5930            ("user_b".to_string(), "online", "free"),
5931            ("user_c".to_string(), "online", "free")
5932        ]
5933    );
5934    assert_eq!(
5935        contacts(&client_b, cx_b),
5936        [
5937            ("user_a".to_string(), "online", "free"),
5938            ("user_c".to_string(), "online", "free"),
5939            ("user_d".to_string(), "online", "free")
5940        ]
5941    );
5942    assert_eq!(
5943        contacts(&client_c, cx_c),
5944        [
5945            ("user_a".to_string(), "online", "free"),
5946            ("user_b".to_string(), "online", "free")
5947        ]
5948    );
5949    assert_eq!(
5950        contacts(&client_d, cx_d),
5951        [("user_b".to_string(), "online", "free")]
5952    );
5953
5954    active_call_a
5955        .update(cx_a, |call, cx| {
5956            call.invite(client_b.user_id().unwrap(), None, cx)
5957        })
5958        .await
5959        .unwrap();
5960    deterministic.run_until_parked();
5961    assert_eq!(
5962        contacts(&client_a, cx_a),
5963        [
5964            ("user_b".to_string(), "online", "busy"),
5965            ("user_c".to_string(), "online", "free")
5966        ]
5967    );
5968    assert_eq!(
5969        contacts(&client_b, cx_b),
5970        [
5971            ("user_a".to_string(), "online", "busy"),
5972            ("user_c".to_string(), "online", "free"),
5973            ("user_d".to_string(), "online", "free")
5974        ]
5975    );
5976    assert_eq!(
5977        contacts(&client_c, cx_c),
5978        [
5979            ("user_a".to_string(), "online", "busy"),
5980            ("user_b".to_string(), "online", "busy")
5981        ]
5982    );
5983    assert_eq!(
5984        contacts(&client_d, cx_d),
5985        [("user_b".to_string(), "online", "busy")]
5986    );
5987
5988    server.forbid_connections();
5989    server.disconnect_client(client_a.peer_id().unwrap());
5990    deterministic.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
5991    assert_eq!(contacts(&client_a, cx_a), []);
5992    assert_eq!(
5993        contacts(&client_b, cx_b),
5994        [
5995            ("user_a".to_string(), "offline", "free"),
5996            ("user_c".to_string(), "online", "free"),
5997            ("user_d".to_string(), "online", "free")
5998        ]
5999    );
6000    assert_eq!(
6001        contacts(&client_c, cx_c),
6002        [
6003            ("user_a".to_string(), "offline", "free"),
6004            ("user_b".to_string(), "online", "free")
6005        ]
6006    );
6007    assert_eq!(
6008        contacts(&client_d, cx_d),
6009        [("user_b".to_string(), "online", "free")]
6010    );
6011
6012    // Test removing a contact
6013    client_b
6014        .user_store
6015        .update(cx_b, |store, cx| {
6016            store.remove_contact(client_c.user_id().unwrap(), cx)
6017        })
6018        .await
6019        .unwrap();
6020    deterministic.run_until_parked();
6021    assert_eq!(
6022        contacts(&client_b, cx_b),
6023        [
6024            ("user_a".to_string(), "offline", "free"),
6025            ("user_d".to_string(), "online", "free")
6026        ]
6027    );
6028    assert_eq!(
6029        contacts(&client_c, cx_c),
6030        [("user_a".to_string(), "offline", "free"),]
6031    );
6032
6033    fn contacts(
6034        client: &TestClient,
6035        cx: &TestAppContext,
6036    ) -> Vec<(String, &'static str, &'static str)> {
6037        client.user_store.read_with(cx, |store, _| {
6038            store
6039                .contacts()
6040                .iter()
6041                .map(|contact| {
6042                    (
6043                        contact.user.github_login.clone(),
6044                        if contact.online { "online" } else { "offline" },
6045                        if contact.busy { "busy" } else { "free" },
6046                    )
6047                })
6048                .collect()
6049        })
6050    }
6051}
6052
6053#[gpui::test(iterations = 10)]
6054async fn test_contact_requests(
6055    deterministic: Arc<Deterministic>,
6056    cx_a: &mut TestAppContext,
6057    cx_a2: &mut TestAppContext,
6058    cx_b: &mut TestAppContext,
6059    cx_b2: &mut TestAppContext,
6060    cx_c: &mut TestAppContext,
6061    cx_c2: &mut TestAppContext,
6062) {
6063    deterministic.forbid_parking();
6064
6065    // Connect to a server as 3 clients.
6066    let mut server = TestServer::start(&deterministic).await;
6067    let client_a = server.create_client(cx_a, "user_a").await;
6068    let client_a2 = server.create_client(cx_a2, "user_a").await;
6069    let client_b = server.create_client(cx_b, "user_b").await;
6070    let client_b2 = server.create_client(cx_b2, "user_b").await;
6071    let client_c = server.create_client(cx_c, "user_c").await;
6072    let client_c2 = server.create_client(cx_c2, "user_c").await;
6073
6074    assert_eq!(client_a.user_id().unwrap(), client_a2.user_id().unwrap());
6075    assert_eq!(client_b.user_id().unwrap(), client_b2.user_id().unwrap());
6076    assert_eq!(client_c.user_id().unwrap(), client_c2.user_id().unwrap());
6077
6078    // User A and User C request that user B become their contact.
6079    client_a
6080        .user_store
6081        .update(cx_a, |store, cx| {
6082            store.request_contact(client_b.user_id().unwrap(), cx)
6083        })
6084        .await
6085        .unwrap();
6086    client_c
6087        .user_store
6088        .update(cx_c, |store, cx| {
6089            store.request_contact(client_b.user_id().unwrap(), cx)
6090        })
6091        .await
6092        .unwrap();
6093    deterministic.run_until_parked();
6094
6095    // All users see the pending request appear in all their clients.
6096    assert_eq!(
6097        client_a.summarize_contacts(cx_a).outgoing_requests,
6098        &["user_b"]
6099    );
6100    assert_eq!(
6101        client_a2.summarize_contacts(cx_a2).outgoing_requests,
6102        &["user_b"]
6103    );
6104    assert_eq!(
6105        client_b.summarize_contacts(cx_b).incoming_requests,
6106        &["user_a", "user_c"]
6107    );
6108    assert_eq!(
6109        client_b2.summarize_contacts(cx_b2).incoming_requests,
6110        &["user_a", "user_c"]
6111    );
6112    assert_eq!(
6113        client_c.summarize_contacts(cx_c).outgoing_requests,
6114        &["user_b"]
6115    );
6116    assert_eq!(
6117        client_c2.summarize_contacts(cx_c2).outgoing_requests,
6118        &["user_b"]
6119    );
6120
6121    // Contact requests are present upon connecting (tested here via disconnect/reconnect)
6122    disconnect_and_reconnect(&client_a, cx_a).await;
6123    disconnect_and_reconnect(&client_b, cx_b).await;
6124    disconnect_and_reconnect(&client_c, cx_c).await;
6125    deterministic.run_until_parked();
6126    assert_eq!(
6127        client_a.summarize_contacts(cx_a).outgoing_requests,
6128        &["user_b"]
6129    );
6130    assert_eq!(
6131        client_b.summarize_contacts(cx_b).incoming_requests,
6132        &["user_a", "user_c"]
6133    );
6134    assert_eq!(
6135        client_c.summarize_contacts(cx_c).outgoing_requests,
6136        &["user_b"]
6137    );
6138
6139    // User B accepts the request from user A.
6140    client_b
6141        .user_store
6142        .update(cx_b, |store, cx| {
6143            store.respond_to_contact_request(client_a.user_id().unwrap(), true, cx)
6144        })
6145        .await
6146        .unwrap();
6147
6148    deterministic.run_until_parked();
6149
6150    // User B sees user A as their contact now in all client, and the incoming request from them is removed.
6151    let contacts_b = client_b.summarize_contacts(cx_b);
6152    assert_eq!(contacts_b.current, &["user_a"]);
6153    assert_eq!(contacts_b.incoming_requests, &["user_c"]);
6154    let contacts_b2 = client_b2.summarize_contacts(cx_b2);
6155    assert_eq!(contacts_b2.current, &["user_a"]);
6156    assert_eq!(contacts_b2.incoming_requests, &["user_c"]);
6157
6158    // User A sees user B as their contact now in all clients, and the outgoing request to them is removed.
6159    let contacts_a = client_a.summarize_contacts(cx_a);
6160    assert_eq!(contacts_a.current, &["user_b"]);
6161    assert!(contacts_a.outgoing_requests.is_empty());
6162    let contacts_a2 = client_a2.summarize_contacts(cx_a2);
6163    assert_eq!(contacts_a2.current, &["user_b"]);
6164    assert!(contacts_a2.outgoing_requests.is_empty());
6165
6166    // Contacts are present upon connecting (tested here via disconnect/reconnect)
6167    disconnect_and_reconnect(&client_a, cx_a).await;
6168    disconnect_and_reconnect(&client_b, cx_b).await;
6169    disconnect_and_reconnect(&client_c, cx_c).await;
6170    deterministic.run_until_parked();
6171    assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
6172    assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
6173    assert_eq!(
6174        client_b.summarize_contacts(cx_b).incoming_requests,
6175        &["user_c"]
6176    );
6177    assert!(client_c.summarize_contacts(cx_c).current.is_empty());
6178    assert_eq!(
6179        client_c.summarize_contacts(cx_c).outgoing_requests,
6180        &["user_b"]
6181    );
6182
6183    // User B rejects the request from user C.
6184    client_b
6185        .user_store
6186        .update(cx_b, |store, cx| {
6187            store.respond_to_contact_request(client_c.user_id().unwrap(), false, cx)
6188        })
6189        .await
6190        .unwrap();
6191
6192    deterministic.run_until_parked();
6193
6194    // User B doesn't see user C as their contact, and the incoming request from them is removed.
6195    let contacts_b = client_b.summarize_contacts(cx_b);
6196    assert_eq!(contacts_b.current, &["user_a"]);
6197    assert!(contacts_b.incoming_requests.is_empty());
6198    let contacts_b2 = client_b2.summarize_contacts(cx_b2);
6199    assert_eq!(contacts_b2.current, &["user_a"]);
6200    assert!(contacts_b2.incoming_requests.is_empty());
6201
6202    // User C doesn't see user B as their contact, and the outgoing request to them is removed.
6203    let contacts_c = client_c.summarize_contacts(cx_c);
6204    assert!(contacts_c.current.is_empty());
6205    assert!(contacts_c.outgoing_requests.is_empty());
6206    let contacts_c2 = client_c2.summarize_contacts(cx_c2);
6207    assert!(contacts_c2.current.is_empty());
6208    assert!(contacts_c2.outgoing_requests.is_empty());
6209
6210    // Incoming/outgoing requests are not present upon connecting (tested here via disconnect/reconnect)
6211    disconnect_and_reconnect(&client_a, cx_a).await;
6212    disconnect_and_reconnect(&client_b, cx_b).await;
6213    disconnect_and_reconnect(&client_c, cx_c).await;
6214    deterministic.run_until_parked();
6215    assert_eq!(client_a.summarize_contacts(cx_a).current, &["user_b"]);
6216    assert_eq!(client_b.summarize_contacts(cx_b).current, &["user_a"]);
6217    assert!(client_b
6218        .summarize_contacts(cx_b)
6219        .incoming_requests
6220        .is_empty());
6221    assert!(client_c.summarize_contacts(cx_c).current.is_empty());
6222    assert!(client_c
6223        .summarize_contacts(cx_c)
6224        .outgoing_requests
6225        .is_empty());
6226
6227    async fn disconnect_and_reconnect(client: &TestClient, cx: &mut TestAppContext) {
6228        client.disconnect(&cx.to_async());
6229        client.clear_contacts(cx).await;
6230        client
6231            .authenticate_and_connect(false, &cx.to_async())
6232            .await
6233            .unwrap();
6234    }
6235}
6236
6237#[gpui::test(iterations = 10)]
6238async fn test_basic_following(
6239    deterministic: Arc<Deterministic>,
6240    cx_a: &mut TestAppContext,
6241    cx_b: &mut TestAppContext,
6242    cx_c: &mut TestAppContext,
6243    cx_d: &mut TestAppContext,
6244) {
6245    deterministic.forbid_parking();
6246
6247    let mut server = TestServer::start(&deterministic).await;
6248    let client_a = server.create_client(cx_a, "user_a").await;
6249    let client_b = server.create_client(cx_b, "user_b").await;
6250    let client_c = server.create_client(cx_c, "user_c").await;
6251    let client_d = server.create_client(cx_d, "user_d").await;
6252    server
6253        .create_room(&mut [
6254            (&client_a, cx_a),
6255            (&client_b, cx_b),
6256            (&client_c, cx_c),
6257            (&client_d, cx_d),
6258        ])
6259        .await;
6260    let active_call_a = cx_a.read(ActiveCall::global);
6261    let active_call_b = cx_b.read(ActiveCall::global);
6262
6263    cx_a.update(editor::init);
6264    cx_b.update(editor::init);
6265
6266    client_a
6267        .fs
6268        .insert_tree(
6269            "/a",
6270            json!({
6271                "1.txt": "one\none\none",
6272                "2.txt": "two\ntwo\ntwo",
6273                "3.txt": "three\nthree\nthree",
6274            }),
6275        )
6276        .await;
6277    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6278    active_call_a
6279        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6280        .await
6281        .unwrap();
6282
6283    let project_id = active_call_a
6284        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6285        .await
6286        .unwrap();
6287    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6288    active_call_b
6289        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6290        .await
6291        .unwrap();
6292
6293    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6294    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6295
6296    // Client A opens some editors.
6297    let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
6298    let editor_a1 = workspace_a
6299        .update(cx_a, |workspace, cx| {
6300            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6301        })
6302        .await
6303        .unwrap()
6304        .downcast::<Editor>()
6305        .unwrap();
6306    let editor_a2 = workspace_a
6307        .update(cx_a, |workspace, cx| {
6308            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
6309        })
6310        .await
6311        .unwrap()
6312        .downcast::<Editor>()
6313        .unwrap();
6314
6315    // Client B opens an editor.
6316    let editor_b1 = workspace_b
6317        .update(cx_b, |workspace, cx| {
6318            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6319        })
6320        .await
6321        .unwrap()
6322        .downcast::<Editor>()
6323        .unwrap();
6324
6325    let peer_id_a = client_a.peer_id().unwrap();
6326    let peer_id_b = client_b.peer_id().unwrap();
6327    let peer_id_c = client_c.peer_id().unwrap();
6328    let peer_id_d = client_d.peer_id().unwrap();
6329
6330    // Client A updates their selections in those editors
6331    editor_a1.update(cx_a, |editor, cx| {
6332        editor.handle_input("a", cx);
6333        editor.handle_input("b", cx);
6334        editor.handle_input("c", cx);
6335        editor.select_left(&Default::default(), cx);
6336        assert_eq!(editor.selections.ranges(cx), vec![3..2]);
6337    });
6338    editor_a2.update(cx_a, |editor, cx| {
6339        editor.handle_input("d", cx);
6340        editor.handle_input("e", cx);
6341        editor.select_left(&Default::default(), cx);
6342        assert_eq!(editor.selections.ranges(cx), vec![2..1]);
6343    });
6344
6345    // When client B starts following client A, all visible view states are replicated to client B.
6346    workspace_b
6347        .update(cx_b, |workspace, cx| {
6348            workspace.toggle_follow(peer_id_a, cx).unwrap()
6349        })
6350        .await
6351        .unwrap();
6352
6353    cx_c.foreground().run_until_parked();
6354    let editor_b2 = workspace_b.read_with(cx_b, |workspace, cx| {
6355        workspace
6356            .active_item(cx)
6357            .unwrap()
6358            .downcast::<Editor>()
6359            .unwrap()
6360    });
6361    assert_eq!(
6362        cx_b.read(|cx| editor_b2.project_path(cx)),
6363        Some((worktree_id, "2.txt").into())
6364    );
6365    assert_eq!(
6366        editor_b2.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
6367        vec![2..1]
6368    );
6369    assert_eq!(
6370        editor_b1.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
6371        vec![3..2]
6372    );
6373
6374    cx_c.foreground().run_until_parked();
6375    let active_call_c = cx_c.read(ActiveCall::global);
6376    let project_c = client_c.build_remote_project(project_id, cx_c).await;
6377    let workspace_c = client_c.build_workspace(&project_c, cx_c);
6378    active_call_c
6379        .update(cx_c, |call, cx| call.set_location(Some(&project_c), cx))
6380        .await
6381        .unwrap();
6382    drop(project_c);
6383
6384    // Client C also follows client A.
6385    workspace_c
6386        .update(cx_c, |workspace, cx| {
6387            workspace.toggle_follow(peer_id_a, cx).unwrap()
6388        })
6389        .await
6390        .unwrap();
6391
6392    cx_d.foreground().run_until_parked();
6393    let active_call_d = cx_d.read(ActiveCall::global);
6394    let project_d = client_d.build_remote_project(project_id, cx_d).await;
6395    let workspace_d = client_d.build_workspace(&project_d, cx_d);
6396    active_call_d
6397        .update(cx_d, |call, cx| call.set_location(Some(&project_d), cx))
6398        .await
6399        .unwrap();
6400    drop(project_d);
6401
6402    // All clients see that clients B and C are following client A.
6403    cx_c.foreground().run_until_parked();
6404    for (name, active_call, cx) in [
6405        ("A", &active_call_a, &cx_a),
6406        ("B", &active_call_b, &cx_b),
6407        ("C", &active_call_c, &cx_c),
6408        ("D", &active_call_d, &cx_d),
6409    ] {
6410        active_call.read_with(*cx, |call, cx| {
6411            let room = call.room().unwrap().read(cx);
6412            assert_eq!(
6413                room.followers_for(peer_id_a, project_id),
6414                &[peer_id_b, peer_id_c],
6415                "checking followers for A as {name}"
6416            );
6417        });
6418    }
6419
6420    // Client C unfollows client A.
6421    workspace_c.update(cx_c, |workspace, cx| {
6422        workspace.toggle_follow(peer_id_a, cx);
6423    });
6424
6425    // All clients see that clients B is following client A.
6426    cx_c.foreground().run_until_parked();
6427    for (name, active_call, cx) in [
6428        ("A", &active_call_a, &cx_a),
6429        ("B", &active_call_b, &cx_b),
6430        ("C", &active_call_c, &cx_c),
6431        ("D", &active_call_d, &cx_d),
6432    ] {
6433        active_call.read_with(*cx, |call, cx| {
6434            let room = call.room().unwrap().read(cx);
6435            assert_eq!(
6436                room.followers_for(peer_id_a, project_id),
6437                &[peer_id_b],
6438                "checking followers for A as {name}"
6439            );
6440        });
6441    }
6442
6443    // Client C re-follows client A.
6444    workspace_c.update(cx_c, |workspace, cx| {
6445        workspace.toggle_follow(peer_id_a, cx);
6446    });
6447
6448    // All clients see that clients B and C are following client A.
6449    cx_c.foreground().run_until_parked();
6450    for (name, active_call, cx) in [
6451        ("A", &active_call_a, &cx_a),
6452        ("B", &active_call_b, &cx_b),
6453        ("C", &active_call_c, &cx_c),
6454        ("D", &active_call_d, &cx_d),
6455    ] {
6456        active_call.read_with(*cx, |call, cx| {
6457            let room = call.room().unwrap().read(cx);
6458            assert_eq!(
6459                room.followers_for(peer_id_a, project_id),
6460                &[peer_id_b, peer_id_c],
6461                "checking followers for A as {name}"
6462            );
6463        });
6464    }
6465
6466    // Client D follows client C.
6467    workspace_d
6468        .update(cx_d, |workspace, cx| {
6469            workspace.toggle_follow(peer_id_c, cx).unwrap()
6470        })
6471        .await
6472        .unwrap();
6473
6474    // All clients see that D is following C
6475    cx_d.foreground().run_until_parked();
6476    for (name, active_call, cx) in [
6477        ("A", &active_call_a, &cx_a),
6478        ("B", &active_call_b, &cx_b),
6479        ("C", &active_call_c, &cx_c),
6480        ("D", &active_call_d, &cx_d),
6481    ] {
6482        active_call.read_with(*cx, |call, cx| {
6483            let room = call.room().unwrap().read(cx);
6484            assert_eq!(
6485                room.followers_for(peer_id_c, project_id),
6486                &[peer_id_d],
6487                "checking followers for C as {name}"
6488            );
6489        });
6490    }
6491
6492    // Client C closes the project.
6493    cx_c.drop_last(workspace_c);
6494
6495    // Clients A and B see that client B is following A, and client C is not present in the followers.
6496    cx_c.foreground().run_until_parked();
6497    for (name, active_call, cx) in [("A", &active_call_a, &cx_a), ("B", &active_call_b, &cx_b)] {
6498        active_call.read_with(*cx, |call, cx| {
6499            let room = call.room().unwrap().read(cx);
6500            assert_eq!(
6501                room.followers_for(peer_id_a, project_id),
6502                &[peer_id_b],
6503                "checking followers for A as {name}"
6504            );
6505        });
6506    }
6507
6508    // All clients see that no-one is following C
6509    for (name, active_call, cx) in [
6510        ("A", &active_call_a, &cx_a),
6511        ("B", &active_call_b, &cx_b),
6512        ("C", &active_call_c, &cx_c),
6513        ("D", &active_call_d, &cx_d),
6514    ] {
6515        active_call.read_with(*cx, |call, cx| {
6516            let room = call.room().unwrap().read(cx);
6517            assert_eq!(
6518                room.followers_for(peer_id_c, project_id),
6519                &[],
6520                "checking followers for C as {name}"
6521            );
6522        });
6523    }
6524
6525    // When client A activates a different editor, client B does so as well.
6526    workspace_a.update(cx_a, |workspace, cx| {
6527        workspace.activate_item(&editor_a1, cx)
6528    });
6529    deterministic.run_until_parked();
6530    workspace_b.read_with(cx_b, |workspace, cx| {
6531        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6532    });
6533
6534    // When client A opens a multibuffer, client B does so as well.
6535    let multibuffer_a = cx_a.add_model(|cx| {
6536        let buffer_a1 = project_a.update(cx, |project, cx| {
6537            project
6538                .get_open_buffer(&(worktree_id, "1.txt").into(), cx)
6539                .unwrap()
6540        });
6541        let buffer_a2 = project_a.update(cx, |project, cx| {
6542            project
6543                .get_open_buffer(&(worktree_id, "2.txt").into(), cx)
6544                .unwrap()
6545        });
6546        let mut result = MultiBuffer::new(0);
6547        result.push_excerpts(
6548            buffer_a1,
6549            [ExcerptRange {
6550                context: 0..3,
6551                primary: None,
6552            }],
6553            cx,
6554        );
6555        result.push_excerpts(
6556            buffer_a2,
6557            [ExcerptRange {
6558                context: 4..7,
6559                primary: None,
6560            }],
6561            cx,
6562        );
6563        result
6564    });
6565    let multibuffer_editor_a = workspace_a.update(cx_a, |workspace, cx| {
6566        let editor =
6567            cx.add_view(|cx| Editor::for_multibuffer(multibuffer_a, Some(project_a.clone()), cx));
6568        workspace.add_item(Box::new(editor.clone()), cx);
6569        editor
6570    });
6571    deterministic.run_until_parked();
6572    let multibuffer_editor_b = workspace_b.read_with(cx_b, |workspace, cx| {
6573        workspace
6574            .active_item(cx)
6575            .unwrap()
6576            .downcast::<Editor>()
6577            .unwrap()
6578    });
6579    assert_eq!(
6580        multibuffer_editor_a.read_with(cx_a, |editor, cx| editor.text(cx)),
6581        multibuffer_editor_b.read_with(cx_b, |editor, cx| editor.text(cx)),
6582    );
6583
6584    // When client A navigates back and forth, client B does so as well.
6585    workspace_a
6586        .update(cx_a, |workspace, cx| {
6587            workspace.go_back(workspace.active_pane().downgrade(), cx)
6588        })
6589        .await
6590        .unwrap();
6591    deterministic.run_until_parked();
6592    workspace_b.read_with(cx_b, |workspace, cx| {
6593        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6594    });
6595
6596    workspace_a
6597        .update(cx_a, |workspace, cx| {
6598            workspace.go_back(workspace.active_pane().downgrade(), cx)
6599        })
6600        .await
6601        .unwrap();
6602    deterministic.run_until_parked();
6603    workspace_b.read_with(cx_b, |workspace, cx| {
6604        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b2.id());
6605    });
6606
6607    workspace_a
6608        .update(cx_a, |workspace, cx| {
6609            workspace.go_forward(workspace.active_pane().downgrade(), cx)
6610        })
6611        .await
6612        .unwrap();
6613    deterministic.run_until_parked();
6614    workspace_b.read_with(cx_b, |workspace, cx| {
6615        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id());
6616    });
6617
6618    // Changes to client A's editor are reflected on client B.
6619    editor_a1.update(cx_a, |editor, cx| {
6620        editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2]));
6621    });
6622    deterministic.run_until_parked();
6623    editor_b1.read_with(cx_b, |editor, cx| {
6624        assert_eq!(editor.selections.ranges(cx), &[1..1, 2..2]);
6625    });
6626
6627    editor_a1.update(cx_a, |editor, cx| editor.set_text("TWO", cx));
6628    deterministic.run_until_parked();
6629    editor_b1.read_with(cx_b, |editor, cx| assert_eq!(editor.text(cx), "TWO"));
6630
6631    editor_a1.update(cx_a, |editor, cx| {
6632        editor.change_selections(None, cx, |s| s.select_ranges([3..3]));
6633        editor.set_scroll_position(vec2f(0., 100.), cx);
6634    });
6635    deterministic.run_until_parked();
6636    editor_b1.read_with(cx_b, |editor, cx| {
6637        assert_eq!(editor.selections.ranges(cx), &[3..3]);
6638    });
6639
6640    // After unfollowing, client B stops receiving updates from client A.
6641    workspace_b.update(cx_b, |workspace, cx| {
6642        workspace.unfollow(&workspace.active_pane().clone(), cx)
6643    });
6644    workspace_a.update(cx_a, |workspace, cx| {
6645        workspace.activate_item(&editor_a2, cx)
6646    });
6647    deterministic.run_until_parked();
6648    assert_eq!(
6649        workspace_b.read_with(cx_b, |workspace, cx| workspace
6650            .active_item(cx)
6651            .unwrap()
6652            .id()),
6653        editor_b1.id()
6654    );
6655
6656    // Client A starts following client B.
6657    workspace_a
6658        .update(cx_a, |workspace, cx| {
6659            workspace.toggle_follow(peer_id_b, cx).unwrap()
6660        })
6661        .await
6662        .unwrap();
6663    assert_eq!(
6664        workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)),
6665        Some(peer_id_b)
6666    );
6667    assert_eq!(
6668        workspace_a.read_with(cx_a, |workspace, cx| workspace
6669            .active_item(cx)
6670            .unwrap()
6671            .id()),
6672        editor_a1.id()
6673    );
6674
6675    // Client B activates an external window, which causes a new screen-sharing item to be added to the pane.
6676    let display = MacOSDisplay::new();
6677    active_call_b
6678        .update(cx_b, |call, cx| call.set_location(None, cx))
6679        .await
6680        .unwrap();
6681    active_call_b
6682        .update(cx_b, |call, cx| {
6683            call.room().unwrap().update(cx, |room, cx| {
6684                room.set_display_sources(vec![display.clone()]);
6685                room.share_screen(cx)
6686            })
6687        })
6688        .await
6689        .unwrap();
6690    deterministic.run_until_parked();
6691    let shared_screen = workspace_a.read_with(cx_a, |workspace, cx| {
6692        workspace
6693            .active_item(cx)
6694            .unwrap()
6695            .downcast::<SharedScreen>()
6696            .unwrap()
6697    });
6698
6699    // Client B activates Zed again, which causes the previous editor to become focused again.
6700    active_call_b
6701        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6702        .await
6703        .unwrap();
6704    deterministic.run_until_parked();
6705    workspace_a.read_with(cx_a, |workspace, cx| {
6706        assert_eq!(workspace.active_item(cx).unwrap().id(), editor_a1.id())
6707    });
6708
6709    // Client B activates a multibuffer that was created by following client A. Client A returns to that multibuffer.
6710    workspace_b.update(cx_b, |workspace, cx| {
6711        workspace.activate_item(&multibuffer_editor_b, cx)
6712    });
6713    deterministic.run_until_parked();
6714    workspace_a.read_with(cx_a, |workspace, cx| {
6715        assert_eq!(
6716            workspace.active_item(cx).unwrap().id(),
6717            multibuffer_editor_a.id()
6718        )
6719    });
6720
6721    // Client B activates an external window again, and the previously-opened screen-sharing item
6722    // gets activated.
6723    active_call_b
6724        .update(cx_b, |call, cx| call.set_location(None, cx))
6725        .await
6726        .unwrap();
6727    deterministic.run_until_parked();
6728    assert_eq!(
6729        workspace_a.read_with(cx_a, |workspace, cx| workspace
6730            .active_item(cx)
6731            .unwrap()
6732            .id()),
6733        shared_screen.id()
6734    );
6735
6736    // Following interrupts when client B disconnects.
6737    client_b.disconnect(&cx_b.to_async());
6738    deterministic.advance_clock(RECONNECT_TIMEOUT);
6739    assert_eq!(
6740        workspace_a.read_with(cx_a, |workspace, _| workspace.leader_for_pane(&pane_a)),
6741        None
6742    );
6743}
6744
6745#[gpui::test(iterations = 10)]
6746async fn test_join_call_after_screen_was_shared(
6747    deterministic: Arc<Deterministic>,
6748    cx_a: &mut TestAppContext,
6749    cx_b: &mut TestAppContext,
6750) {
6751    deterministic.forbid_parking();
6752    let mut server = TestServer::start(&deterministic).await;
6753
6754    let client_a = server.create_client(cx_a, "user_a").await;
6755    let client_b = server.create_client(cx_b, "user_b").await;
6756    server
6757        .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6758        .await;
6759
6760    let active_call_a = cx_a.read(ActiveCall::global);
6761    let active_call_b = cx_b.read(ActiveCall::global);
6762
6763    // Call users B and C from client A.
6764    active_call_a
6765        .update(cx_a, |call, cx| {
6766            call.invite(client_b.user_id().unwrap(), None, cx)
6767        })
6768        .await
6769        .unwrap();
6770    let room_a = active_call_a.read_with(cx_a, |call, _| call.room().unwrap().clone());
6771    deterministic.run_until_parked();
6772    assert_eq!(
6773        room_participants(&room_a, cx_a),
6774        RoomParticipants {
6775            remote: Default::default(),
6776            pending: vec!["user_b".to_string()]
6777        }
6778    );
6779
6780    // User B receives the call.
6781    let mut incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
6782    let call_b = incoming_call_b.next().await.unwrap().unwrap();
6783    assert_eq!(call_b.calling_user.github_login, "user_a");
6784
6785    // User A shares their screen
6786    let display = MacOSDisplay::new();
6787    active_call_a
6788        .update(cx_a, |call, cx| {
6789            call.room().unwrap().update(cx, |room, cx| {
6790                room.set_display_sources(vec![display.clone()]);
6791                room.share_screen(cx)
6792            })
6793        })
6794        .await
6795        .unwrap();
6796
6797    client_b.user_store.update(cx_b, |user_store, _| {
6798        user_store.clear_cache();
6799    });
6800
6801    // User B joins the room
6802    active_call_b
6803        .update(cx_b, |call, cx| call.accept_incoming(cx))
6804        .await
6805        .unwrap();
6806    let room_b = active_call_b.read_with(cx_b, |call, _| call.room().unwrap().clone());
6807    assert!(incoming_call_b.next().await.unwrap().is_none());
6808
6809    deterministic.run_until_parked();
6810    assert_eq!(
6811        room_participants(&room_a, cx_a),
6812        RoomParticipants {
6813            remote: vec!["user_b".to_string()],
6814            pending: vec![],
6815        }
6816    );
6817    assert_eq!(
6818        room_participants(&room_b, cx_b),
6819        RoomParticipants {
6820            remote: vec!["user_a".to_string()],
6821            pending: vec![],
6822        }
6823    );
6824
6825    // Ensure User B sees User A's screenshare.
6826    room_b.read_with(cx_b, |room, _| {
6827        assert_eq!(
6828            room.remote_participants()
6829                .get(&client_a.user_id().unwrap())
6830                .unwrap()
6831                .tracks
6832                .len(),
6833            1
6834        );
6835    });
6836}
6837
6838#[gpui::test]
6839async fn test_following_tab_order(
6840    deterministic: Arc<Deterministic>,
6841    cx_a: &mut TestAppContext,
6842    cx_b: &mut TestAppContext,
6843) {
6844    let mut server = TestServer::start(&deterministic).await;
6845    let client_a = server.create_client(cx_a, "user_a").await;
6846    let client_b = server.create_client(cx_b, "user_b").await;
6847    server
6848        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6849        .await;
6850    let active_call_a = cx_a.read(ActiveCall::global);
6851    let active_call_b = cx_b.read(ActiveCall::global);
6852
6853    cx_a.update(editor::init);
6854    cx_b.update(editor::init);
6855
6856    client_a
6857        .fs
6858        .insert_tree(
6859            "/a",
6860            json!({
6861                "1.txt": "one",
6862                "2.txt": "two",
6863                "3.txt": "three",
6864            }),
6865        )
6866        .await;
6867    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6868    active_call_a
6869        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6870        .await
6871        .unwrap();
6872
6873    let project_id = active_call_a
6874        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6875        .await
6876        .unwrap();
6877    let project_b = client_b.build_remote_project(project_id, cx_b).await;
6878    active_call_b
6879        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
6880        .await
6881        .unwrap();
6882
6883    let workspace_a = client_a.build_workspace(&project_a, cx_a);
6884    let pane_a = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
6885
6886    let workspace_b = client_b.build_workspace(&project_b, cx_b);
6887    let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
6888
6889    let client_b_id = project_a.read_with(cx_a, |project, _| {
6890        project.collaborators().values().next().unwrap().peer_id
6891    });
6892
6893    //Open 1, 3 in that order on client A
6894    workspace_a
6895        .update(cx_a, |workspace, cx| {
6896            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6897        })
6898        .await
6899        .unwrap();
6900    workspace_a
6901        .update(cx_a, |workspace, cx| {
6902            workspace.open_path((worktree_id, "3.txt"), None, true, cx)
6903        })
6904        .await
6905        .unwrap();
6906
6907    let pane_paths = |pane: &ViewHandle<workspace::Pane>, cx: &mut TestAppContext| {
6908        pane.update(cx, |pane, cx| {
6909            pane.items()
6910                .map(|item| {
6911                    item.project_path(cx)
6912                        .unwrap()
6913                        .path
6914                        .to_str()
6915                        .unwrap()
6916                        .to_owned()
6917                })
6918                .collect::<Vec<_>>()
6919        })
6920    };
6921
6922    //Verify that the tabs opened in the order we expect
6923    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt"]);
6924
6925    //Follow client B as client A
6926    workspace_a
6927        .update(cx_a, |workspace, cx| {
6928            workspace.toggle_follow(client_b_id, cx).unwrap()
6929        })
6930        .await
6931        .unwrap();
6932
6933    //Open just 2 on client B
6934    workspace_b
6935        .update(cx_b, |workspace, cx| {
6936            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
6937        })
6938        .await
6939        .unwrap();
6940    deterministic.run_until_parked();
6941
6942    // Verify that newly opened followed file is at the end
6943    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]);
6944
6945    //Open just 1 on client B
6946    workspace_b
6947        .update(cx_b, |workspace, cx| {
6948            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
6949        })
6950        .await
6951        .unwrap();
6952    assert_eq!(&pane_paths(&pane_b, cx_b), &["2.txt", "1.txt"]);
6953    deterministic.run_until_parked();
6954
6955    // Verify that following into 1 did not reorder
6956    assert_eq!(&pane_paths(&pane_a, cx_a), &["1.txt", "3.txt", "2.txt"]);
6957}
6958
6959#[gpui::test(iterations = 10)]
6960async fn test_peers_following_each_other(
6961    deterministic: Arc<Deterministic>,
6962    cx_a: &mut TestAppContext,
6963    cx_b: &mut TestAppContext,
6964) {
6965    deterministic.forbid_parking();
6966    let mut server = TestServer::start(&deterministic).await;
6967    let client_a = server.create_client(cx_a, "user_a").await;
6968    let client_b = server.create_client(cx_b, "user_b").await;
6969    server
6970        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
6971        .await;
6972    let active_call_a = cx_a.read(ActiveCall::global);
6973    let active_call_b = cx_b.read(ActiveCall::global);
6974
6975    cx_a.update(editor::init);
6976    cx_b.update(editor::init);
6977
6978    // Client A shares a project.
6979    client_a
6980        .fs
6981        .insert_tree(
6982            "/a",
6983            json!({
6984                "1.txt": "one",
6985                "2.txt": "two",
6986                "3.txt": "three",
6987                "4.txt": "four",
6988            }),
6989        )
6990        .await;
6991    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
6992    active_call_a
6993        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
6994        .await
6995        .unwrap();
6996    let project_id = active_call_a
6997        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
6998        .await
6999        .unwrap();
7000
7001    // Client B joins the project.
7002    let project_b = client_b.build_remote_project(project_id, cx_b).await;
7003    active_call_b
7004        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
7005        .await
7006        .unwrap();
7007
7008    // Client A opens some editors.
7009    let workspace_a = client_a.build_workspace(&project_a, cx_a);
7010    let pane_a1 = workspace_a.read_with(cx_a, |workspace, _| workspace.active_pane().clone());
7011    let _editor_a1 = workspace_a
7012        .update(cx_a, |workspace, cx| {
7013            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
7014        })
7015        .await
7016        .unwrap()
7017        .downcast::<Editor>()
7018        .unwrap();
7019
7020    // Client B opens an editor.
7021    let workspace_b = client_b.build_workspace(&project_b, cx_b);
7022    let pane_b1 = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
7023    let _editor_b1 = workspace_b
7024        .update(cx_b, |workspace, cx| {
7025            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
7026        })
7027        .await
7028        .unwrap()
7029        .downcast::<Editor>()
7030        .unwrap();
7031
7032    // Clients A and B follow each other in split panes
7033    workspace_a.update(cx_a, |workspace, cx| {
7034        workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
7035    });
7036    workspace_a
7037        .update(cx_a, |workspace, cx| {
7038            assert_ne!(*workspace.active_pane(), pane_a1);
7039            let leader_id = *project_a.read(cx).collaborators().keys().next().unwrap();
7040            workspace.toggle_follow(leader_id, cx).unwrap()
7041        })
7042        .await
7043        .unwrap();
7044    workspace_b.update(cx_b, |workspace, cx| {
7045        workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
7046    });
7047    workspace_b
7048        .update(cx_b, |workspace, cx| {
7049            assert_ne!(*workspace.active_pane(), pane_b1);
7050            let leader_id = *project_b.read(cx).collaborators().keys().next().unwrap();
7051            workspace.toggle_follow(leader_id, cx).unwrap()
7052        })
7053        .await
7054        .unwrap();
7055
7056    workspace_a.update(cx_a, |workspace, cx| {
7057        workspace.activate_next_pane(cx);
7058    });
7059    // Wait for focus effects to be fully flushed
7060    workspace_a.update(cx_a, |workspace, _| {
7061        assert_eq!(*workspace.active_pane(), pane_a1);
7062    });
7063
7064    workspace_a
7065        .update(cx_a, |workspace, cx| {
7066            workspace.open_path((worktree_id, "3.txt"), None, true, cx)
7067        })
7068        .await
7069        .unwrap();
7070    workspace_b.update(cx_b, |workspace, cx| {
7071        workspace.activate_next_pane(cx);
7072    });
7073
7074    workspace_b
7075        .update(cx_b, |workspace, cx| {
7076            assert_eq!(*workspace.active_pane(), pane_b1);
7077            workspace.open_path((worktree_id, "4.txt"), None, true, cx)
7078        })
7079        .await
7080        .unwrap();
7081    cx_a.foreground().run_until_parked();
7082
7083    // Ensure leader updates don't change the active pane of followers
7084    workspace_a.read_with(cx_a, |workspace, _| {
7085        assert_eq!(*workspace.active_pane(), pane_a1);
7086    });
7087    workspace_b.read_with(cx_b, |workspace, _| {
7088        assert_eq!(*workspace.active_pane(), pane_b1);
7089    });
7090
7091    // Ensure peers following each other doesn't cause an infinite loop.
7092    assert_eq!(
7093        workspace_a.read_with(cx_a, |workspace, cx| workspace
7094            .active_item(cx)
7095            .unwrap()
7096            .project_path(cx)),
7097        Some((worktree_id, "3.txt").into())
7098    );
7099    workspace_a.update(cx_a, |workspace, cx| {
7100        assert_eq!(
7101            workspace.active_item(cx).unwrap().project_path(cx),
7102            Some((worktree_id, "3.txt").into())
7103        );
7104        workspace.activate_next_pane(cx);
7105    });
7106
7107    workspace_a.update(cx_a, |workspace, cx| {
7108        assert_eq!(
7109            workspace.active_item(cx).unwrap().project_path(cx),
7110            Some((worktree_id, "4.txt").into())
7111        );
7112    });
7113
7114    workspace_b.update(cx_b, |workspace, cx| {
7115        assert_eq!(
7116            workspace.active_item(cx).unwrap().project_path(cx),
7117            Some((worktree_id, "4.txt").into())
7118        );
7119        workspace.activate_next_pane(cx);
7120    });
7121
7122    workspace_b.update(cx_b, |workspace, cx| {
7123        assert_eq!(
7124            workspace.active_item(cx).unwrap().project_path(cx),
7125            Some((worktree_id, "3.txt").into())
7126        );
7127    });
7128}
7129
7130#[gpui::test(iterations = 10)]
7131async fn test_auto_unfollowing(
7132    deterministic: Arc<Deterministic>,
7133    cx_a: &mut TestAppContext,
7134    cx_b: &mut TestAppContext,
7135) {
7136    deterministic.forbid_parking();
7137
7138    // 2 clients connect to a server.
7139    let mut server = TestServer::start(&deterministic).await;
7140    let client_a = server.create_client(cx_a, "user_a").await;
7141    let client_b = server.create_client(cx_b, "user_b").await;
7142    server
7143        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
7144        .await;
7145    let active_call_a = cx_a.read(ActiveCall::global);
7146    let active_call_b = cx_b.read(ActiveCall::global);
7147
7148    cx_a.update(editor::init);
7149    cx_b.update(editor::init);
7150
7151    // Client A shares a project.
7152    client_a
7153        .fs
7154        .insert_tree(
7155            "/a",
7156            json!({
7157                "1.txt": "one",
7158                "2.txt": "two",
7159                "3.txt": "three",
7160            }),
7161        )
7162        .await;
7163    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
7164    active_call_a
7165        .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
7166        .await
7167        .unwrap();
7168
7169    let project_id = active_call_a
7170        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
7171        .await
7172        .unwrap();
7173    let project_b = client_b.build_remote_project(project_id, cx_b).await;
7174    active_call_b
7175        .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
7176        .await
7177        .unwrap();
7178
7179    // Client A opens some editors.
7180    let workspace_a = client_a.build_workspace(&project_a, cx_a);
7181    let _editor_a1 = workspace_a
7182        .update(cx_a, |workspace, cx| {
7183            workspace.open_path((worktree_id, "1.txt"), None, true, cx)
7184        })
7185        .await
7186        .unwrap()
7187        .downcast::<Editor>()
7188        .unwrap();
7189
7190    // Client B starts following client A.
7191    let workspace_b = client_b.build_workspace(&project_b, cx_b);
7192    let pane_b = workspace_b.read_with(cx_b, |workspace, _| workspace.active_pane().clone());
7193    let leader_id = project_b.read_with(cx_b, |project, _| {
7194        project.collaborators().values().next().unwrap().peer_id
7195    });
7196    workspace_b
7197        .update(cx_b, |workspace, cx| {
7198            workspace.toggle_follow(leader_id, cx).unwrap()
7199        })
7200        .await
7201        .unwrap();
7202    assert_eq!(
7203        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7204        Some(leader_id)
7205    );
7206    let editor_b2 = workspace_b.read_with(cx_b, |workspace, cx| {
7207        workspace
7208            .active_item(cx)
7209            .unwrap()
7210            .downcast::<Editor>()
7211            .unwrap()
7212    });
7213
7214    // When client B moves, it automatically stops following client A.
7215    editor_b2.update(cx_b, |editor, cx| editor.move_right(&editor::MoveRight, cx));
7216    assert_eq!(
7217        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7218        None
7219    );
7220
7221    workspace_b
7222        .update(cx_b, |workspace, cx| {
7223            workspace.toggle_follow(leader_id, cx).unwrap()
7224        })
7225        .await
7226        .unwrap();
7227    assert_eq!(
7228        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7229        Some(leader_id)
7230    );
7231
7232    // When client B edits, it automatically stops following client A.
7233    editor_b2.update(cx_b, |editor, cx| editor.insert("X", cx));
7234    assert_eq!(
7235        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7236        None
7237    );
7238
7239    workspace_b
7240        .update(cx_b, |workspace, cx| {
7241            workspace.toggle_follow(leader_id, cx).unwrap()
7242        })
7243        .await
7244        .unwrap();
7245    assert_eq!(
7246        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7247        Some(leader_id)
7248    );
7249
7250    // When client B scrolls, it automatically stops following client A.
7251    editor_b2.update(cx_b, |editor, cx| {
7252        editor.set_scroll_position(vec2f(0., 3.), cx)
7253    });
7254    assert_eq!(
7255        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7256        None
7257    );
7258
7259    workspace_b
7260        .update(cx_b, |workspace, cx| {
7261            workspace.toggle_follow(leader_id, cx).unwrap()
7262        })
7263        .await
7264        .unwrap();
7265    assert_eq!(
7266        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7267        Some(leader_id)
7268    );
7269
7270    // When client B activates a different pane, it continues following client A in the original pane.
7271    workspace_b.update(cx_b, |workspace, cx| {
7272        workspace.split_pane(pane_b.clone(), SplitDirection::Right, cx)
7273    });
7274    assert_eq!(
7275        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7276        Some(leader_id)
7277    );
7278
7279    workspace_b.update(cx_b, |workspace, cx| workspace.activate_next_pane(cx));
7280    assert_eq!(
7281        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7282        Some(leader_id)
7283    );
7284
7285    // When client B activates a different item in the original pane, it automatically stops following client A.
7286    workspace_b
7287        .update(cx_b, |workspace, cx| {
7288            workspace.open_path((worktree_id, "2.txt"), None, true, cx)
7289        })
7290        .await
7291        .unwrap();
7292    assert_eq!(
7293        workspace_b.read_with(cx_b, |workspace, _| workspace.leader_for_pane(&pane_b)),
7294        None
7295    );
7296}
7297
7298#[gpui::test(iterations = 10)]
7299async fn test_peers_simultaneously_following_each_other(
7300    deterministic: Arc<Deterministic>,
7301    cx_a: &mut TestAppContext,
7302    cx_b: &mut TestAppContext,
7303) {
7304    deterministic.forbid_parking();
7305
7306    let mut server = TestServer::start(&deterministic).await;
7307    let client_a = server.create_client(cx_a, "user_a").await;
7308    let client_b = server.create_client(cx_b, "user_b").await;
7309    server
7310        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
7311        .await;
7312    let active_call_a = cx_a.read(ActiveCall::global);
7313
7314    cx_a.update(editor::init);
7315    cx_b.update(editor::init);
7316
7317    client_a.fs.insert_tree("/a", json!({})).await;
7318    let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
7319    let workspace_a = client_a.build_workspace(&project_a, cx_a);
7320    let project_id = active_call_a
7321        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
7322        .await
7323        .unwrap();
7324
7325    let project_b = client_b.build_remote_project(project_id, cx_b).await;
7326    let workspace_b = client_b.build_workspace(&project_b, cx_b);
7327
7328    deterministic.run_until_parked();
7329    let client_a_id = project_b.read_with(cx_b, |project, _| {
7330        project.collaborators().values().next().unwrap().peer_id
7331    });
7332    let client_b_id = project_a.read_with(cx_a, |project, _| {
7333        project.collaborators().values().next().unwrap().peer_id
7334    });
7335
7336    let a_follow_b = workspace_a.update(cx_a, |workspace, cx| {
7337        workspace.toggle_follow(client_b_id, cx).unwrap()
7338    });
7339    let b_follow_a = workspace_b.update(cx_b, |workspace, cx| {
7340        workspace.toggle_follow(client_a_id, cx).unwrap()
7341    });
7342
7343    futures::try_join!(a_follow_b, b_follow_a).unwrap();
7344    workspace_a.read_with(cx_a, |workspace, _| {
7345        assert_eq!(
7346            workspace.leader_for_pane(workspace.active_pane()),
7347            Some(client_b_id)
7348        );
7349    });
7350    workspace_b.read_with(cx_b, |workspace, _| {
7351        assert_eq!(
7352            workspace.leader_for_pane(workspace.active_pane()),
7353            Some(client_a_id)
7354        );
7355    });
7356}
7357
7358#[gpui::test(iterations = 10)]
7359async fn test_on_input_format_from_host_to_guest(
7360    deterministic: Arc<Deterministic>,
7361    cx_a: &mut TestAppContext,
7362    cx_b: &mut TestAppContext,
7363) {
7364    deterministic.forbid_parking();
7365    let mut server = TestServer::start(&deterministic).await;
7366    let client_a = server.create_client(cx_a, "user_a").await;
7367    let client_b = server.create_client(cx_b, "user_b").await;
7368    server
7369        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
7370        .await;
7371    let active_call_a = cx_a.read(ActiveCall::global);
7372
7373    // Set up a fake language server.
7374    let mut language = Language::new(
7375        LanguageConfig {
7376            name: "Rust".into(),
7377            path_suffixes: vec!["rs".to_string()],
7378            ..Default::default()
7379        },
7380        Some(tree_sitter_rust::language()),
7381    );
7382    let mut fake_language_servers = language
7383        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
7384            capabilities: lsp::ServerCapabilities {
7385                document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
7386                    first_trigger_character: ":".to_string(),
7387                    more_trigger_character: Some(vec![">".to_string()]),
7388                }),
7389                ..Default::default()
7390            },
7391            ..Default::default()
7392        }))
7393        .await;
7394    client_a.language_registry.add(Arc::new(language));
7395
7396    client_a
7397        .fs
7398        .insert_tree(
7399            "/a",
7400            json!({
7401                "main.rs": "fn main() { a }",
7402                "other.rs": "// Test file",
7403            }),
7404        )
7405        .await;
7406    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
7407    let project_id = active_call_a
7408        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
7409        .await
7410        .unwrap();
7411    let project_b = client_b.build_remote_project(project_id, cx_b).await;
7412
7413    // Open a file in an editor as the host.
7414    let buffer_a = project_a
7415        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
7416        .await
7417        .unwrap();
7418    let (window_a, _) = cx_a.add_window(|_| EmptyView);
7419    let editor_a = cx_a.add_view(window_a, |cx| {
7420        Editor::for_buffer(buffer_a, Some(project_a.clone()), cx)
7421    });
7422
7423    let fake_language_server = fake_language_servers.next().await.unwrap();
7424    cx_b.foreground().run_until_parked();
7425
7426    // Receive an OnTypeFormatting request as the host's language server.
7427    // Return some formattings from the host's language server.
7428    fake_language_server.handle_request::<lsp::request::OnTypeFormatting, _, _>(
7429        |params, _| async move {
7430            assert_eq!(
7431                params.text_document_position.text_document.uri,
7432                lsp::Url::from_file_path("/a/main.rs").unwrap(),
7433            );
7434            assert_eq!(
7435                params.text_document_position.position,
7436                lsp::Position::new(0, 14),
7437            );
7438
7439            Ok(Some(vec![lsp::TextEdit {
7440                new_text: "~<".to_string(),
7441                range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
7442            }]))
7443        },
7444    );
7445
7446    // Open the buffer on the guest and see that the formattings worked
7447    let buffer_b = project_b
7448        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
7449        .await
7450        .unwrap();
7451
7452    // Type a on type formatting trigger character as the guest.
7453    editor_a.update(cx_a, |editor, cx| {
7454        cx.focus(&editor_a);
7455        editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
7456        editor.handle_input(">", cx);
7457    });
7458
7459    cx_b.foreground().run_until_parked();
7460
7461    buffer_b.read_with(cx_b, |buffer, _| {
7462        assert_eq!(buffer.text(), "fn main() { a>~< }")
7463    });
7464
7465    // Undo should remove LSP edits first
7466    editor_a.update(cx_a, |editor, cx| {
7467        assert_eq!(editor.text(cx), "fn main() { a>~< }");
7468        editor.undo(&Undo, cx);
7469        assert_eq!(editor.text(cx), "fn main() { a> }");
7470    });
7471    cx_b.foreground().run_until_parked();
7472    buffer_b.read_with(cx_b, |buffer, _| {
7473        assert_eq!(buffer.text(), "fn main() { a> }")
7474    });
7475
7476    editor_a.update(cx_a, |editor, cx| {
7477        assert_eq!(editor.text(cx), "fn main() { a> }");
7478        editor.undo(&Undo, cx);
7479        assert_eq!(editor.text(cx), "fn main() { a }");
7480    });
7481    cx_b.foreground().run_until_parked();
7482    buffer_b.read_with(cx_b, |buffer, _| {
7483        assert_eq!(buffer.text(), "fn main() { a }")
7484    });
7485}
7486
7487#[gpui::test(iterations = 10)]
7488async fn test_on_input_format_from_guest_to_host(
7489    deterministic: Arc<Deterministic>,
7490    cx_a: &mut TestAppContext,
7491    cx_b: &mut TestAppContext,
7492) {
7493    deterministic.forbid_parking();
7494    let mut server = TestServer::start(&deterministic).await;
7495    let client_a = server.create_client(cx_a, "user_a").await;
7496    let client_b = server.create_client(cx_b, "user_b").await;
7497    server
7498        .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
7499        .await;
7500    let active_call_a = cx_a.read(ActiveCall::global);
7501
7502    // Set up a fake language server.
7503    let mut language = Language::new(
7504        LanguageConfig {
7505            name: "Rust".into(),
7506            path_suffixes: vec!["rs".to_string()],
7507            ..Default::default()
7508        },
7509        Some(tree_sitter_rust::language()),
7510    );
7511    let mut fake_language_servers = language
7512        .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
7513            capabilities: lsp::ServerCapabilities {
7514                document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
7515                    first_trigger_character: ":".to_string(),
7516                    more_trigger_character: Some(vec![">".to_string()]),
7517                }),
7518                ..Default::default()
7519            },
7520            ..Default::default()
7521        }))
7522        .await;
7523    client_a.language_registry.add(Arc::new(language));
7524
7525    client_a
7526        .fs
7527        .insert_tree(
7528            "/a",
7529            json!({
7530                "main.rs": "fn main() { a }",
7531                "other.rs": "// Test file",
7532            }),
7533        )
7534        .await;
7535    let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
7536    let project_id = active_call_a
7537        .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
7538        .await
7539        .unwrap();
7540    let project_b = client_b.build_remote_project(project_id, cx_b).await;
7541
7542    // Open a file in an editor as the guest.
7543    let buffer_b = project_b
7544        .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
7545        .await
7546        .unwrap();
7547    let (window_b, _) = cx_b.add_window(|_| EmptyView);
7548    let editor_b = cx_b.add_view(window_b, |cx| {
7549        Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
7550    });
7551
7552    let fake_language_server = fake_language_servers.next().await.unwrap();
7553    cx_a.foreground().run_until_parked();
7554    // Type a on type formatting trigger character as the guest.
7555    editor_b.update(cx_b, |editor, cx| {
7556        editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
7557        editor.handle_input(":", cx);
7558        cx.focus(&editor_b);
7559    });
7560
7561    // Receive an OnTypeFormatting request as the host's language server.
7562    // Return some formattings from the host's language server.
7563    cx_a.foreground().start_waiting();
7564    fake_language_server
7565        .handle_request::<lsp::request::OnTypeFormatting, _, _>(|params, _| async move {
7566            assert_eq!(
7567                params.text_document_position.text_document.uri,
7568                lsp::Url::from_file_path("/a/main.rs").unwrap(),
7569            );
7570            assert_eq!(
7571                params.text_document_position.position,
7572                lsp::Position::new(0, 14),
7573            );
7574
7575            Ok(Some(vec![lsp::TextEdit {
7576                new_text: "~:".to_string(),
7577                range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
7578            }]))
7579        })
7580        .next()
7581        .await
7582        .unwrap();
7583    cx_a.foreground().finish_waiting();
7584
7585    // Open the buffer on the host and see that the formattings worked
7586    let buffer_a = project_a
7587        .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
7588        .await
7589        .unwrap();
7590    cx_a.foreground().run_until_parked();
7591    buffer_a.read_with(cx_a, |buffer, _| {
7592        assert_eq!(buffer.text(), "fn main() { a:~: }")
7593    });
7594
7595    // Undo should remove LSP edits first
7596    editor_b.update(cx_b, |editor, cx| {
7597        assert_eq!(editor.text(cx), "fn main() { a:~: }");
7598        editor.undo(&Undo, cx);
7599        assert_eq!(editor.text(cx), "fn main() { a: }");
7600    });
7601    cx_a.foreground().run_until_parked();
7602    buffer_a.read_with(cx_a, |buffer, _| {
7603        assert_eq!(buffer.text(), "fn main() { a: }")
7604    });
7605
7606    editor_b.update(cx_b, |editor, cx| {
7607        assert_eq!(editor.text(cx), "fn main() { a: }");
7608        editor.undo(&Undo, cx);
7609        assert_eq!(editor.text(cx), "fn main() { a }");
7610    });
7611    cx_a.foreground().run_until_parked();
7612    buffer_a.read_with(cx_a, |buffer, _| {
7613        assert_eq!(buffer.text(), "fn main() { a }")
7614    });
7615}
7616
7617#[derive(Debug, Eq, PartialEq)]
7618struct RoomParticipants {
7619    remote: Vec<String>,
7620    pending: Vec<String>,
7621}
7622
7623fn room_participants(room: &ModelHandle<Room>, cx: &mut TestAppContext) -> RoomParticipants {
7624    room.read_with(cx, |room, _| {
7625        let mut remote = room
7626            .remote_participants()
7627            .iter()
7628            .map(|(_, participant)| participant.user.github_login.clone())
7629            .collect::<Vec<_>>();
7630        let mut pending = room
7631            .pending_participants()
7632            .iter()
7633            .map(|user| user.github_login.clone())
7634            .collect::<Vec<_>>();
7635        remote.sort();
7636        pending.sort();
7637        RoomParticipants { remote, pending }
7638    })
7639}