integration_tests.rs

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