tests.rs

   1use super::*;
   2use clock::ReplicaId;
   3use collections::BTreeMap;
   4use gpui::{ModelHandle, MutableAppContext};
   5use rand::prelude::*;
   6use std::{
   7    cell::RefCell,
   8    env,
   9    ops::Range,
  10    rc::Rc,
  11    time::{Duration, Instant},
  12};
  13use text::network::Network;
  14use unindent::Unindent as _;
  15use util::post_inc;
  16
  17#[cfg(test)]
  18#[ctor::ctor]
  19fn init_logger() {
  20    if std::env::var("RUST_LOG").is_ok() {
  21        env_logger::init();
  22    }
  23}
  24
  25#[gpui::test]
  26fn test_select_language() {
  27    let registry = LanguageRegistry::test();
  28    registry.add(Arc::new(Language::new(
  29        LanguageConfig {
  30            name: "Rust".into(),
  31            path_suffixes: vec!["rs".to_string()],
  32            ..Default::default()
  33        },
  34        Some(tree_sitter_rust::language()),
  35    )));
  36    registry.add(Arc::new(Language::new(
  37        LanguageConfig {
  38            name: "Make".into(),
  39            path_suffixes: vec!["Makefile".to_string(), "mk".to_string()],
  40            ..Default::default()
  41        },
  42        Some(tree_sitter_rust::language()),
  43    )));
  44
  45    // matching file extension
  46    assert_eq!(
  47        registry.select_language("zed/lib.rs").map(|l| l.name()),
  48        Some("Rust".into())
  49    );
  50    assert_eq!(
  51        registry.select_language("zed/lib.mk").map(|l| l.name()),
  52        Some("Make".into())
  53    );
  54
  55    // matching filename
  56    assert_eq!(
  57        registry.select_language("zed/Makefile").map(|l| l.name()),
  58        Some("Make".into())
  59    );
  60
  61    // matching suffix that is not the full file extension or filename
  62    assert_eq!(registry.select_language("zed/cars").map(|l| l.name()), None);
  63    assert_eq!(
  64        registry.select_language("zed/a.cars").map(|l| l.name()),
  65        None
  66    );
  67    assert_eq!(registry.select_language("zed/sumk").map(|l| l.name()), None);
  68}
  69
  70#[gpui::test]
  71fn test_edit_events(cx: &mut gpui::MutableAppContext) {
  72    let mut now = Instant::now();
  73    let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
  74    let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
  75
  76    let buffer1 = cx.add_model(|cx| Buffer::new(0, "abcdef", cx));
  77    let buffer2 = cx.add_model(|cx| Buffer::new(1, "abcdef", cx));
  78    let buffer1_ops = Rc::new(RefCell::new(Vec::new()));
  79    buffer1.update(cx, {
  80        let buffer1_ops = buffer1_ops.clone();
  81        |buffer, cx| {
  82            let buffer_1_events = buffer_1_events.clone();
  83            cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
  84                Event::Operation(op) => buffer1_ops.borrow_mut().push(op),
  85                event @ _ => buffer_1_events.borrow_mut().push(event),
  86            })
  87            .detach();
  88            let buffer_2_events = buffer_2_events.clone();
  89            cx.subscribe(&buffer2, move |_, _, event, _| {
  90                buffer_2_events.borrow_mut().push(event.clone())
  91            })
  92            .detach();
  93
  94            // An edit emits an edited event, followed by a dirtied event,
  95            // since the buffer was previously in a clean state.
  96            buffer.edit([(2..4, "XYZ")], cx);
  97
  98            // An empty transaction does not emit any events.
  99            buffer.start_transaction();
 100            buffer.end_transaction(cx);
 101
 102            // A transaction containing two edits emits one edited event.
 103            now += Duration::from_secs(1);
 104            buffer.start_transaction_at(now);
 105            buffer.edit([(5..5, "u")], cx);
 106            buffer.edit([(6..6, "w")], cx);
 107            buffer.end_transaction_at(now, cx);
 108
 109            // Undoing a transaction emits one edited event.
 110            buffer.undo(cx);
 111        }
 112    });
 113
 114    // Incorporating a set of remote ops emits a single edited event,
 115    // followed by a dirtied event.
 116    buffer2.update(cx, |buffer, cx| {
 117        buffer
 118            .apply_ops(buffer1_ops.borrow_mut().drain(..), cx)
 119            .unwrap();
 120    });
 121
 122    let buffer_1_events = buffer_1_events.borrow();
 123    assert_eq!(
 124        *buffer_1_events,
 125        vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
 126    );
 127
 128    let buffer_2_events = buffer_2_events.borrow();
 129    assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
 130}
 131
 132#[gpui::test]
 133async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
 134    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
 135    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
 136
 137    let text = "a\nccc\ndddd\nffffff\n";
 138    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 139    buffer.update(cx, |buffer, cx| {
 140        buffer.apply_diff(diff, cx).unwrap();
 141    });
 142    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
 143
 144    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
 145    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
 146    buffer.update(cx, |buffer, cx| {
 147        buffer.apply_diff(diff, cx).unwrap();
 148    });
 149    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
 150}
 151
 152#[gpui::test]
 153async fn test_reparse(cx: &mut gpui::TestAppContext) {
 154    let text = "fn a() {}";
 155    let buffer =
 156        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 157
 158    // Wait for the initial text to parse
 159    buffer
 160        .condition(&cx, |buffer, _| !buffer.is_parsing())
 161        .await;
 162    assert_eq!(
 163        get_tree_sexp(&buffer, &cx),
 164        concat!(
 165            "(source_file (function_item name: (identifier) ",
 166            "parameters: (parameters) ",
 167            "body: (block)))"
 168        )
 169    );
 170
 171    buffer.update(cx, |buffer, _| {
 172        buffer.set_sync_parse_timeout(Duration::ZERO)
 173    });
 174
 175    // Perform some edits (add parameter and variable reference)
 176    // Parsing doesn't begin until the transaction is complete
 177    buffer.update(cx, |buf, cx| {
 178        buf.start_transaction();
 179
 180        let offset = buf.text().find(")").unwrap();
 181        buf.edit([(offset..offset, "b: C")], cx);
 182        assert!(!buf.is_parsing());
 183
 184        let offset = buf.text().find("}").unwrap();
 185        buf.edit([(offset..offset, " d; ")], cx);
 186        assert!(!buf.is_parsing());
 187
 188        buf.end_transaction(cx);
 189        assert_eq!(buf.text(), "fn a(b: C) { d; }");
 190        assert!(buf.is_parsing());
 191    });
 192    buffer
 193        .condition(&cx, |buffer, _| !buffer.is_parsing())
 194        .await;
 195    assert_eq!(
 196        get_tree_sexp(&buffer, &cx),
 197        concat!(
 198            "(source_file (function_item name: (identifier) ",
 199            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 200            "body: (block (expression_statement (identifier)))))"
 201        )
 202    );
 203
 204    // Perform a series of edits without waiting for the current parse to complete:
 205    // * turn identifier into a field expression
 206    // * turn field expression into a method call
 207    // * add a turbofish to the method call
 208    buffer.update(cx, |buf, cx| {
 209        let offset = buf.text().find(";").unwrap();
 210        buf.edit([(offset..offset, ".e")], cx);
 211        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
 212        assert!(buf.is_parsing());
 213    });
 214    buffer.update(cx, |buf, cx| {
 215        let offset = buf.text().find(";").unwrap();
 216        buf.edit([(offset..offset, "(f)")], cx);
 217        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
 218        assert!(buf.is_parsing());
 219    });
 220    buffer.update(cx, |buf, cx| {
 221        let offset = buf.text().find("(f)").unwrap();
 222        buf.edit([(offset..offset, "::<G>")], cx);
 223        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 224        assert!(buf.is_parsing());
 225    });
 226    buffer
 227        .condition(&cx, |buffer, _| !buffer.is_parsing())
 228        .await;
 229    assert_eq!(
 230        get_tree_sexp(&buffer, &cx),
 231        concat!(
 232            "(source_file (function_item name: (identifier) ",
 233            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 234            "body: (block (expression_statement (call_expression ",
 235            "function: (generic_function ",
 236            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 237            "type_arguments: (type_arguments (type_identifier))) ",
 238            "arguments: (arguments (identifier)))))))",
 239        )
 240    );
 241
 242    buffer.update(cx, |buf, cx| {
 243        buf.undo(cx);
 244        assert_eq!(buf.text(), "fn a() {}");
 245        assert!(buf.is_parsing());
 246    });
 247    buffer
 248        .condition(&cx, |buffer, _| !buffer.is_parsing())
 249        .await;
 250    assert_eq!(
 251        get_tree_sexp(&buffer, &cx),
 252        concat!(
 253            "(source_file (function_item name: (identifier) ",
 254            "parameters: (parameters) ",
 255            "body: (block)))"
 256        )
 257    );
 258
 259    buffer.update(cx, |buf, cx| {
 260        buf.redo(cx);
 261        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
 262        assert!(buf.is_parsing());
 263    });
 264    buffer
 265        .condition(&cx, |buffer, _| !buffer.is_parsing())
 266        .await;
 267    assert_eq!(
 268        get_tree_sexp(&buffer, &cx),
 269        concat!(
 270            "(source_file (function_item name: (identifier) ",
 271            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
 272            "body: (block (expression_statement (call_expression ",
 273            "function: (generic_function ",
 274            "function: (field_expression value: (identifier) field: (field_identifier)) ",
 275            "type_arguments: (type_arguments (type_identifier))) ",
 276            "arguments: (arguments (identifier)))))))",
 277        )
 278    );
 279}
 280
 281#[gpui::test]
 282async fn test_resetting_language(cx: &mut gpui::TestAppContext) {
 283    let buffer = cx.add_model(|cx| {
 284        let mut buffer = Buffer::new(0, "{}", cx).with_language(Arc::new(rust_lang()), cx);
 285        buffer.set_sync_parse_timeout(Duration::ZERO);
 286        buffer
 287    });
 288
 289    // Wait for the initial text to parse
 290    buffer
 291        .condition(&cx, |buffer, _| !buffer.is_parsing())
 292        .await;
 293    assert_eq!(
 294        get_tree_sexp(&buffer, &cx),
 295        "(source_file (expression_statement (block)))"
 296    );
 297
 298    buffer.update(cx, |buffer, cx| {
 299        buffer.set_language(Some(Arc::new(json_lang())), cx)
 300    });
 301    buffer
 302        .condition(&cx, |buffer, _| !buffer.is_parsing())
 303        .await;
 304    assert_eq!(get_tree_sexp(&buffer, &cx), "(document (object))");
 305}
 306
 307#[gpui::test]
 308async fn test_outline(cx: &mut gpui::TestAppContext) {
 309    let text = r#"
 310        struct Person {
 311            name: String,
 312            age: usize,
 313        }
 314
 315        mod module {
 316            enum LoginState {
 317                LoggedOut,
 318                LoggingOn,
 319                LoggedIn {
 320                    person: Person,
 321                    time: Instant,
 322                }
 323            }
 324        }
 325
 326        impl Eq for Person {}
 327
 328        impl Drop for Person {
 329            fn drop(&mut self) {
 330                println!("bye");
 331            }
 332        }
 333    "#
 334    .unindent();
 335
 336    let buffer =
 337        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 338    let outline = buffer
 339        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
 340        .unwrap();
 341
 342    assert_eq!(
 343        outline
 344            .items
 345            .iter()
 346            .map(|item| (item.text.as_str(), item.depth))
 347            .collect::<Vec<_>>(),
 348        &[
 349            ("struct Person", 0),
 350            ("name", 1),
 351            ("age", 1),
 352            ("mod module", 0),
 353            ("enum LoginState", 1),
 354            ("LoggedOut", 2),
 355            ("LoggingOn", 2),
 356            ("LoggedIn", 2),
 357            ("person", 3),
 358            ("time", 3),
 359            ("impl Eq for Person", 0),
 360            ("impl Drop for Person", 0),
 361            ("fn drop", 1),
 362        ]
 363    );
 364
 365    // Without space, we only match on names
 366    assert_eq!(
 367        search(&outline, "oon", &cx).await,
 368        &[
 369            ("mod module", vec![]),                    // included as the parent of a match
 370            ("enum LoginState", vec![]),               // included as the parent of a match
 371            ("LoggingOn", vec![1, 7, 8]),              // matches
 372            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
 373        ]
 374    );
 375
 376    assert_eq!(
 377        search(&outline, "dp p", &cx).await,
 378        &[
 379            ("impl Drop for Person", vec![5, 8, 9, 14]),
 380            ("fn drop", vec![]),
 381        ]
 382    );
 383    assert_eq!(
 384        search(&outline, "dpn", &cx).await,
 385        &[("impl Drop for Person", vec![5, 14, 19])]
 386    );
 387    assert_eq!(
 388        search(&outline, "impl ", &cx).await,
 389        &[
 390            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
 391            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
 392            ("fn drop", vec![]),
 393        ]
 394    );
 395
 396    async fn search<'a>(
 397        outline: &'a Outline<Anchor>,
 398        query: &str,
 399        cx: &gpui::TestAppContext,
 400    ) -> Vec<(&'a str, Vec<usize>)> {
 401        let matches = cx
 402            .read(|cx| outline.search(query, cx.background().clone()))
 403            .await;
 404        matches
 405            .into_iter()
 406            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
 407            .collect::<Vec<_>>()
 408    }
 409}
 410
 411#[gpui::test]
 412async fn test_symbols_containing(cx: &mut gpui::TestAppContext) {
 413    let text = r#"
 414        impl Person {
 415            fn one() {
 416                1
 417            }
 418
 419            fn two() {
 420                2
 421            }fn three() {
 422                3
 423            }
 424        }
 425    "#
 426    .unindent();
 427
 428    let buffer =
 429        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
 430    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
 431
 432    // point is at the start of an item
 433    assert_eq!(
 434        symbols_containing(Point::new(1, 4), &snapshot),
 435        vec![
 436            (
 437                "impl Person".to_string(),
 438                Point::new(0, 0)..Point::new(10, 1)
 439            ),
 440            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 441        ]
 442    );
 443
 444    // point is in the middle of an item
 445    assert_eq!(
 446        symbols_containing(Point::new(2, 8), &snapshot),
 447        vec![
 448            (
 449                "impl Person".to_string(),
 450                Point::new(0, 0)..Point::new(10, 1)
 451            ),
 452            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 453        ]
 454    );
 455
 456    // point is at the end of an item
 457    assert_eq!(
 458        symbols_containing(Point::new(3, 5), &snapshot),
 459        vec![
 460            (
 461                "impl Person".to_string(),
 462                Point::new(0, 0)..Point::new(10, 1)
 463            ),
 464            ("fn one".to_string(), Point::new(1, 4)..Point::new(3, 5))
 465        ]
 466    );
 467
 468    // point is in between two adjacent items
 469    assert_eq!(
 470        symbols_containing(Point::new(7, 5), &snapshot),
 471        vec![
 472            (
 473                "impl Person".to_string(),
 474                Point::new(0, 0)..Point::new(10, 1)
 475            ),
 476            ("fn two".to_string(), Point::new(5, 4)..Point::new(7, 5))
 477        ]
 478    );
 479
 480    fn symbols_containing<'a>(
 481        position: Point,
 482        snapshot: &'a BufferSnapshot,
 483    ) -> Vec<(String, Range<Point>)> {
 484        snapshot
 485            .symbols_containing(position, None)
 486            .unwrap()
 487            .into_iter()
 488            .map(|item| {
 489                (
 490                    item.text,
 491                    item.range.start.to_point(snapshot)..item.range.end.to_point(snapshot),
 492                )
 493            })
 494            .collect()
 495    }
 496}
 497
 498#[gpui::test]
 499fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
 500    let buffer = cx.add_model(|cx| {
 501        let text = "
 502            mod x {
 503                mod y {
 504
 505                }
 506            }
 507        "
 508        .unindent();
 509        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
 510    });
 511    let buffer = buffer.read(cx);
 512    assert_eq!(
 513        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
 514        Some((
 515            Point::new(0, 6)..Point::new(0, 7),
 516            Point::new(4, 0)..Point::new(4, 1)
 517        ))
 518    );
 519    assert_eq!(
 520        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
 521        Some((
 522            Point::new(1, 10)..Point::new(1, 11),
 523            Point::new(3, 4)..Point::new(3, 5)
 524        ))
 525    );
 526    assert_eq!(
 527        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
 528        Some((
 529            Point::new(1, 10)..Point::new(1, 11),
 530            Point::new(3, 4)..Point::new(3, 5)
 531        ))
 532    );
 533}
 534
 535#[gpui::test]
 536fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
 537    cx.add_model(|cx| {
 538        let text = "fn a() { b(|c| {}) }";
 539        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 540        let snapshot = buffer.snapshot();
 541
 542        assert_eq!(
 543            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
 544            Some(range_of(text, "|"))
 545        );
 546        assert_eq!(
 547            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
 548            Some(range_of(text, "|c|"))
 549        );
 550        assert_eq!(
 551            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
 552            Some(range_of(text, "|c| {}"))
 553        );
 554        assert_eq!(
 555            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
 556            Some(range_of(text, "(|c| {})"))
 557        );
 558
 559        buffer
 560    });
 561
 562    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
 563        let start = text.find(part).unwrap();
 564        start..start
 565    }
 566
 567    fn range_of(text: &str, part: &str) -> Range<usize> {
 568        let start = text.find(part).unwrap();
 569        start..start + part.len()
 570    }
 571}
 572
 573#[gpui::test]
 574fn test_edit_with_autoindent(cx: &mut MutableAppContext) {
 575    cx.add_model(|cx| {
 576        let text = "fn a() {}";
 577        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 578
 579        buffer.edit_with_autoindent([(8..8, "\n\n")], 4, cx);
 580        assert_eq!(buffer.text(), "fn a() {\n    \n}");
 581
 582        buffer.edit_with_autoindent([(Point::new(1, 4)..Point::new(1, 4), "b()\n")], 4, cx);
 583        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
 584
 585        buffer.edit_with_autoindent([(Point::new(2, 4)..Point::new(2, 4), ".c")], 4, cx);
 586        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
 587
 588        buffer
 589    });
 590}
 591
 592#[gpui::test]
 593fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
 594    cx.add_model(|cx| {
 595        let text = "
 596            fn a() {
 597            c;
 598            d;
 599            }
 600        "
 601        .unindent();
 602
 603        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 604
 605        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
 606        // their indentation is not adjusted.
 607        buffer.edit_with_autoindent(
 608            [
 609                (empty(Point::new(1, 1)), "()"),
 610                (empty(Point::new(2, 1)), "()"),
 611            ],
 612            4,
 613            cx,
 614        );
 615        assert_eq!(
 616            buffer.text(),
 617            "
 618            fn a() {
 619            c();
 620            d();
 621            }
 622            "
 623            .unindent()
 624        );
 625
 626        // When appending new content after these lines, the indentation is based on the
 627        // preceding lines' actual indentation.
 628        buffer.edit_with_autoindent(
 629            [
 630                (empty(Point::new(1, 1)), "\n.f\n.g"),
 631                (empty(Point::new(2, 1)), "\n.f\n.g"),
 632            ],
 633            4,
 634            cx,
 635        );
 636        assert_eq!(
 637            buffer.text(),
 638            "
 639            fn a() {
 640            c
 641                .f
 642                .g();
 643            d
 644                .f
 645                .g();
 646            }
 647            "
 648            .unindent()
 649        );
 650        buffer
 651    });
 652
 653    cx.add_model(|cx| {
 654        let text = "fn a() {\n    {\n        b()?\n    }\n\n    Ok(())\n}";
 655        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 656        buffer.edit_with_autoindent([(Point::new(3, 4)..Point::new(3, 5), "")], 4, cx);
 657        assert_eq!(
 658            buffer.text(),
 659            "fn a() {\n    {\n        b()?\n            \n\n    Ok(())\n}"
 660        );
 661
 662        buffer.edit_with_autoindent([(Point::new(3, 0)..Point::new(3, 12), "")], 4, cx);
 663        assert_eq!(
 664            buffer.text(),
 665            "fn a() {\n    {\n        b()?\n\n\n    Ok(())\n}"
 666        );
 667        buffer
 668    });
 669}
 670
 671#[gpui::test]
 672fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
 673    cx.add_model(|cx| {
 674        let text = "
 675            fn a() {}
 676        "
 677        .unindent();
 678
 679        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 680
 681        buffer.edit_with_autoindent([(5..5, "\nb")], 4, cx);
 682        assert_eq!(
 683            buffer.text(),
 684            "
 685                fn a(
 686                    b) {}
 687            "
 688            .unindent()
 689        );
 690
 691        // The indentation suggestion changed because `@end` node (a close paren)
 692        // is now at the beginning of the line.
 693        buffer.edit_with_autoindent([(Point::new(1, 4)..Point::new(1, 5), "")], 4, cx);
 694        assert_eq!(
 695            buffer.text(),
 696            "
 697                fn a(
 698                ) {}
 699            "
 700            .unindent()
 701        );
 702
 703        buffer
 704    });
 705}
 706
 707#[gpui::test]
 708fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut MutableAppContext) {
 709    cx.add_model(|cx| {
 710        let text = "a\nb";
 711        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
 712        buffer.edit_with_autoindent([(0..1, "\n"), (2..3, "\n")], 4, cx);
 713        assert_eq!(buffer.text(), "\n\n\n");
 714        buffer
 715    });
 716}
 717
 718#[gpui::test]
 719fn test_serialization(cx: &mut gpui::MutableAppContext) {
 720    let mut now = Instant::now();
 721
 722    let buffer1 = cx.add_model(|cx| {
 723        let mut buffer = Buffer::new(0, "abc", cx);
 724        buffer.edit([(3..3, "D")], cx);
 725
 726        now += Duration::from_secs(1);
 727        buffer.start_transaction_at(now);
 728        buffer.edit([(4..4, "E")], cx);
 729        buffer.end_transaction_at(now, cx);
 730        assert_eq!(buffer.text(), "abcDE");
 731
 732        buffer.undo(cx);
 733        assert_eq!(buffer.text(), "abcD");
 734
 735        buffer.edit([(4..4, "F")], cx);
 736        assert_eq!(buffer.text(), "abcDF");
 737        buffer
 738    });
 739    assert_eq!(buffer1.read(cx).text(), "abcDF");
 740
 741    let message = buffer1.read(cx).to_proto();
 742    let buffer2 = cx.add_model(|cx| Buffer::from_proto(1, message, None, cx).unwrap());
 743    assert_eq!(buffer2.read(cx).text(), "abcDF");
 744}
 745
 746#[gpui::test(iterations = 100)]
 747fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
 748    let min_peers = env::var("MIN_PEERS")
 749        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
 750        .unwrap_or(1);
 751    let max_peers = env::var("MAX_PEERS")
 752        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
 753        .unwrap_or(5);
 754    let operations = env::var("OPERATIONS")
 755        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
 756        .unwrap_or(10);
 757
 758    let base_text_len = rng.gen_range(0..10);
 759    let base_text = RandomCharIter::new(&mut rng)
 760        .take(base_text_len)
 761        .collect::<String>();
 762    let mut replica_ids = Vec::new();
 763    let mut buffers = Vec::new();
 764    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
 765    let base_buffer = cx.add_model(|cx| Buffer::new(0, base_text.as_str(), cx));
 766
 767    for i in 0..rng.gen_range(min_peers..=max_peers) {
 768        let buffer = cx.add_model(|cx| {
 769            let mut buffer =
 770                Buffer::from_proto(i as ReplicaId, base_buffer.read(cx).to_proto(), None, cx)
 771                    .unwrap();
 772            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
 773            let network = network.clone();
 774            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
 775                if let Event::Operation(op) = event {
 776                    network
 777                        .borrow_mut()
 778                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(&op)]);
 779                }
 780            })
 781            .detach();
 782            buffer
 783        });
 784        buffers.push(buffer);
 785        replica_ids.push(i as ReplicaId);
 786        network.borrow_mut().add_peer(i as ReplicaId);
 787        log::info!("Adding initial peer with replica id {}", i);
 788    }
 789
 790    log::info!("initial text: {:?}", base_text);
 791
 792    let mut now = Instant::now();
 793    let mut mutation_count = operations;
 794    let mut next_diagnostic_id = 0;
 795    let mut active_selections = BTreeMap::default();
 796    loop {
 797        let replica_index = rng.gen_range(0..replica_ids.len());
 798        let replica_id = replica_ids[replica_index];
 799        let buffer = &mut buffers[replica_index];
 800        let mut new_buffer = None;
 801        match rng.gen_range(0..100) {
 802            0..=29 if mutation_count != 0 => {
 803                buffer.update(cx, |buffer, cx| {
 804                    buffer.start_transaction_at(now);
 805                    buffer.randomly_edit(&mut rng, 5, cx);
 806                    buffer.end_transaction_at(now, cx);
 807                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
 808                });
 809                mutation_count -= 1;
 810            }
 811            30..=39 if mutation_count != 0 => {
 812                buffer.update(cx, |buffer, cx| {
 813                    let mut selections = Vec::new();
 814                    for id in 0..rng.gen_range(1..=5) {
 815                        let range = buffer.random_byte_range(0, &mut rng);
 816                        selections.push(Selection {
 817                            id,
 818                            start: buffer.anchor_before(range.start),
 819                            end: buffer.anchor_before(range.end),
 820                            reversed: false,
 821                            goal: SelectionGoal::None,
 822                        });
 823                    }
 824                    let selections: Arc<[Selection<Anchor>]> = selections.into();
 825                    log::info!(
 826                        "peer {} setting active selections: {:?}",
 827                        replica_id,
 828                        selections
 829                    );
 830                    active_selections.insert(replica_id, selections.clone());
 831                    buffer.set_active_selections(selections, false, cx);
 832                });
 833                mutation_count -= 1;
 834            }
 835            40..=49 if mutation_count != 0 && replica_id == 0 => {
 836                let entry_count = rng.gen_range(1..=5);
 837                buffer.update(cx, |buffer, cx| {
 838                    let diagnostics = DiagnosticSet::new(
 839                        (0..entry_count).map(|_| {
 840                            let range = buffer.random_byte_range(0, &mut rng);
 841                            let range = range.to_point_utf16(buffer);
 842                            DiagnosticEntry {
 843                                range,
 844                                diagnostic: Diagnostic {
 845                                    message: post_inc(&mut next_diagnostic_id).to_string(),
 846                                    ..Default::default()
 847                                },
 848                            }
 849                        }),
 850                        buffer,
 851                    );
 852                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
 853                    buffer.update_diagnostics(diagnostics, cx);
 854                });
 855                mutation_count -= 1;
 856            }
 857            50..=59 if replica_ids.len() < max_peers => {
 858                let old_buffer = buffer.read(cx).to_proto();
 859                let new_replica_id = (0..=replica_ids.len() as ReplicaId)
 860                    .filter(|replica_id| *replica_id != buffer.read(cx).replica_id())
 861                    .choose(&mut rng)
 862                    .unwrap();
 863                log::info!(
 864                    "Adding new replica {} (replicating from {})",
 865                    new_replica_id,
 866                    replica_id
 867                );
 868                new_buffer = Some(cx.add_model(|cx| {
 869                    let mut new_buffer =
 870                        Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap();
 871                    log::info!(
 872                        "New replica {} text: {:?}",
 873                        new_buffer.replica_id(),
 874                        new_buffer.text()
 875                    );
 876                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
 877                    let network = network.clone();
 878                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
 879                        if let Event::Operation(op) = event {
 880                            network.borrow_mut().broadcast(
 881                                buffer.replica_id(),
 882                                vec![proto::serialize_operation(&op)],
 883                            );
 884                        }
 885                    })
 886                    .detach();
 887                    new_buffer
 888                }));
 889                network.borrow_mut().replicate(replica_id, new_replica_id);
 890
 891                if new_replica_id as usize == replica_ids.len() {
 892                    replica_ids.push(new_replica_id);
 893                } else {
 894                    let new_buffer = new_buffer.take().unwrap();
 895                    while network.borrow().has_unreceived(new_replica_id) {
 896                        let ops = network
 897                            .borrow_mut()
 898                            .receive(new_replica_id)
 899                            .into_iter()
 900                            .map(|op| proto::deserialize_operation(op).unwrap());
 901                        if ops.len() > 0 {
 902                            log::info!(
 903                                "peer {} (version: {:?}) applying {} ops from the network. {:?}",
 904                                new_replica_id,
 905                                buffer.read(cx).version(),
 906                                ops.len(),
 907                                ops
 908                            );
 909                            new_buffer.update(cx, |new_buffer, cx| {
 910                                new_buffer.apply_ops(ops, cx).unwrap();
 911                            });
 912                        }
 913                    }
 914                    buffers[new_replica_id as usize] = new_buffer;
 915                }
 916            }
 917            60..=69 if mutation_count != 0 => {
 918                buffer.update(cx, |buffer, cx| {
 919                    buffer.randomly_undo_redo(&mut rng, cx);
 920                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
 921                });
 922                mutation_count -= 1;
 923            }
 924            _ if network.borrow().has_unreceived(replica_id) => {
 925                let ops = network
 926                    .borrow_mut()
 927                    .receive(replica_id)
 928                    .into_iter()
 929                    .map(|op| proto::deserialize_operation(op).unwrap());
 930                if ops.len() > 0 {
 931                    log::info!(
 932                        "peer {} (version: {:?}) applying {} ops from the network. {:?}",
 933                        replica_id,
 934                        buffer.read(cx).version(),
 935                        ops.len(),
 936                        ops
 937                    );
 938                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
 939                }
 940            }
 941            _ => {}
 942        }
 943
 944        now += Duration::from_millis(rng.gen_range(0..=200));
 945        buffers.extend(new_buffer);
 946
 947        for buffer in &buffers {
 948            buffer.read(cx).check_invariants();
 949        }
 950
 951        if mutation_count == 0 && network.borrow().is_idle() {
 952            break;
 953        }
 954    }
 955
 956    let first_buffer = buffers[0].read(cx).snapshot();
 957    for buffer in &buffers[1..] {
 958        let buffer = buffer.read(cx).snapshot();
 959        assert_eq!(
 960            buffer.version(),
 961            first_buffer.version(),
 962            "Replica {} version != Replica 0 version",
 963            buffer.replica_id()
 964        );
 965        assert_eq!(
 966            buffer.text(),
 967            first_buffer.text(),
 968            "Replica {} text != Replica 0 text",
 969            buffer.replica_id()
 970        );
 971        assert_eq!(
 972            buffer
 973                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
 974                .collect::<Vec<_>>(),
 975            first_buffer
 976                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
 977                .collect::<Vec<_>>(),
 978            "Replica {} diagnostics != Replica 0 diagnostics",
 979            buffer.replica_id()
 980        );
 981    }
 982
 983    for buffer in &buffers {
 984        let buffer = buffer.read(cx).snapshot();
 985        let actual_remote_selections = buffer
 986            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
 987            .map(|(replica_id, _, selections)| (replica_id, selections.collect::<Vec<_>>()))
 988            .collect::<Vec<_>>();
 989        let expected_remote_selections = active_selections
 990            .iter()
 991            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
 992            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
 993            .collect::<Vec<_>>();
 994        assert_eq!(
 995            actual_remote_selections,
 996            expected_remote_selections,
 997            "Replica {} remote selections != expected selections",
 998            buffer.replica_id()
 999        );
1000    }
1001}
1002
1003#[test]
1004fn test_contiguous_ranges() {
1005    assert_eq!(
1006        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
1007        &[1..4, 5..7, 9..13]
1008    );
1009
1010    // Respects the `max_len` parameter
1011    assert_eq!(
1012        contiguous_ranges(
1013            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
1014            3
1015        )
1016        .collect::<Vec<_>>(),
1017        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
1018    );
1019}
1020
1021impl Buffer {
1022    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
1023        &self,
1024        range: Range<T>,
1025    ) -> Option<(Range<Point>, Range<Point>)> {
1026        self.snapshot()
1027            .enclosing_bracket_ranges(range)
1028            .map(|(start, end)| {
1029                let point_start = start.start.to_point(self)..start.end.to_point(self);
1030                let point_end = end.start.to_point(self)..end.end.to_point(self);
1031                (point_start, point_end)
1032            })
1033    }
1034}
1035
1036fn rust_lang() -> Language {
1037    Language::new(
1038        LanguageConfig {
1039            name: "Rust".into(),
1040            path_suffixes: vec!["rs".to_string()],
1041            ..Default::default()
1042        },
1043        Some(tree_sitter_rust::language()),
1044    )
1045    .with_indents_query(
1046        r#"
1047        (call_expression) @indent
1048        (field_expression) @indent
1049        (_ "(" ")" @end) @indent
1050        (_ "{" "}" @end) @indent
1051        "#,
1052    )
1053    .unwrap()
1054    .with_brackets_query(
1055        r#"
1056        ("{" @open "}" @close)
1057        "#,
1058    )
1059    .unwrap()
1060    .with_outline_query(
1061        r#"
1062        (struct_item
1063            "struct" @context
1064            name: (_) @name) @item
1065        (enum_item
1066            "enum" @context
1067            name: (_) @name) @item
1068        (enum_variant
1069            name: (_) @name) @item
1070        (field_declaration
1071            name: (_) @name) @item
1072        (impl_item
1073            "impl" @context
1074            trait: (_)? @name
1075            "for"? @context
1076            type: (_) @name) @item
1077        (function_item
1078            "fn" @context
1079            name: (_) @name) @item
1080        (mod_item
1081            "mod" @context
1082            name: (_) @name) @item
1083        "#,
1084    )
1085    .unwrap()
1086}
1087
1088fn json_lang() -> Language {
1089    Language::new(
1090        LanguageConfig {
1091            name: "Json".into(),
1092            path_suffixes: vec!["js".to_string()],
1093            ..Default::default()
1094        },
1095        Some(tree_sitter_json::language()),
1096    )
1097}
1098
1099fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
1100    buffer.read_with(cx, |buffer, _| {
1101        buffer.syntax_tree().unwrap().root_node().to_sexp()
1102    })
1103}
1104
1105fn empty(point: Point) -> Range<Point> {
1106    point..point
1107}