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(Some(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(Some(5..5), "u", cx);
106            buffer.edit(Some(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![
126            Event::Edited { local: true },
127            Event::Dirtied,
128            Event::Edited { local: true },
129            Event::Edited { local: true }
130        ]
131    );
132
133    let buffer_2_events = buffer_2_events.borrow();
134    assert_eq!(
135        *buffer_2_events,
136        vec![Event::Edited { local: false }, Event::Dirtied]
137    );
138}
139
140#[gpui::test]
141async fn test_apply_diff(cx: &mut gpui::TestAppContext) {
142    let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n";
143    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx));
144
145    let text = "a\nccc\ndddd\nffffff\n";
146    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
147    buffer.update(cx, |b, cx| b.apply_diff(diff, cx));
148    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
149
150    let text = "a\n1\n\nccc\ndd2dd\nffffff\n";
151    let diff = buffer.read_with(cx, |b, cx| b.diff(text.into(), cx)).await;
152    buffer.update(cx, |b, cx| b.apply_diff(diff, cx));
153    cx.read(|cx| assert_eq!(buffer.read(cx).text(), text));
154}
155
156#[gpui::test]
157async fn test_reparse(cx: &mut gpui::TestAppContext) {
158    let text = "fn a() {}";
159    let buffer =
160        cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx));
161
162    // Wait for the initial text to parse
163    buffer
164        .condition(&cx, |buffer, _| !buffer.is_parsing())
165        .await;
166    assert_eq!(
167        get_tree_sexp(&buffer, &cx),
168        concat!(
169            "(source_file (function_item name: (identifier) ",
170            "parameters: (parameters) ",
171            "body: (block)))"
172        )
173    );
174
175    buffer.update(cx, |buffer, _| {
176        buffer.set_sync_parse_timeout(Duration::ZERO)
177    });
178
179    // Perform some edits (add parameter and variable reference)
180    // Parsing doesn't begin until the transaction is complete
181    buffer.update(cx, |buf, cx| {
182        buf.start_transaction();
183
184        let offset = buf.text().find(")").unwrap();
185        buf.edit(vec![offset..offset], "b: C", cx);
186        assert!(!buf.is_parsing());
187
188        let offset = buf.text().find("}").unwrap();
189        buf.edit(vec![offset..offset], " d; ", cx);
190        assert!(!buf.is_parsing());
191
192        buf.end_transaction(cx);
193        assert_eq!(buf.text(), "fn a(b: C) { d; }");
194        assert!(buf.is_parsing());
195    });
196    buffer
197        .condition(&cx, |buffer, _| !buffer.is_parsing())
198        .await;
199    assert_eq!(
200        get_tree_sexp(&buffer, &cx),
201        concat!(
202            "(source_file (function_item name: (identifier) ",
203            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
204            "body: (block (expression_statement (identifier)))))"
205        )
206    );
207
208    // Perform a series of edits without waiting for the current parse to complete:
209    // * turn identifier into a field expression
210    // * turn field expression into a method call
211    // * add a turbofish to the method call
212    buffer.update(cx, |buf, cx| {
213        let offset = buf.text().find(";").unwrap();
214        buf.edit(vec![offset..offset], ".e", cx);
215        assert_eq!(buf.text(), "fn a(b: C) { d.e; }");
216        assert!(buf.is_parsing());
217    });
218    buffer.update(cx, |buf, cx| {
219        let offset = buf.text().find(";").unwrap();
220        buf.edit(vec![offset..offset], "(f)", cx);
221        assert_eq!(buf.text(), "fn a(b: C) { d.e(f); }");
222        assert!(buf.is_parsing());
223    });
224    buffer.update(cx, |buf, cx| {
225        let offset = buf.text().find("(f)").unwrap();
226        buf.edit(vec![offset..offset], "::<G>", cx);
227        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
228        assert!(buf.is_parsing());
229    });
230    buffer
231        .condition(&cx, |buffer, _| !buffer.is_parsing())
232        .await;
233    assert_eq!(
234        get_tree_sexp(&buffer, &cx),
235        concat!(
236            "(source_file (function_item name: (identifier) ",
237            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
238            "body: (block (expression_statement (call_expression ",
239            "function: (generic_function ",
240            "function: (field_expression value: (identifier) field: (field_identifier)) ",
241            "type_arguments: (type_arguments (type_identifier))) ",
242            "arguments: (arguments (identifier)))))))",
243        )
244    );
245
246    buffer.update(cx, |buf, cx| {
247        buf.undo(cx);
248        assert_eq!(buf.text(), "fn a() {}");
249        assert!(buf.is_parsing());
250    });
251    buffer
252        .condition(&cx, |buffer, _| !buffer.is_parsing())
253        .await;
254    assert_eq!(
255        get_tree_sexp(&buffer, &cx),
256        concat!(
257            "(source_file (function_item name: (identifier) ",
258            "parameters: (parameters) ",
259            "body: (block)))"
260        )
261    );
262
263    buffer.update(cx, |buf, cx| {
264        buf.redo(cx);
265        assert_eq!(buf.text(), "fn a(b: C) { d.e::<G>(f); }");
266        assert!(buf.is_parsing());
267    });
268    buffer
269        .condition(&cx, |buffer, _| !buffer.is_parsing())
270        .await;
271    assert_eq!(
272        get_tree_sexp(&buffer, &cx),
273        concat!(
274            "(source_file (function_item name: (identifier) ",
275            "parameters: (parameters (parameter pattern: (identifier) type: (type_identifier))) ",
276            "body: (block (expression_statement (call_expression ",
277            "function: (generic_function ",
278            "function: (field_expression value: (identifier) field: (field_identifier)) ",
279            "type_arguments: (type_arguments (type_identifier))) ",
280            "arguments: (arguments (identifier)))))))",
281        )
282    );
283
284    fn get_tree_sexp(buffer: &ModelHandle<Buffer>, cx: &gpui::TestAppContext) -> String {
285        buffer.read_with(cx, |buffer, _| {
286            buffer.syntax_tree().unwrap().root_node().to_sexp()
287        })
288    }
289}
290
291#[gpui::test]
292async fn test_outline(cx: &mut gpui::TestAppContext) {
293    let language = Arc::new(
294        rust_lang()
295            .with_outline_query(
296                r#"
297                (struct_item
298                    "struct" @context
299                    name: (_) @name) @item
300                (enum_item
301                    "enum" @context
302                    name: (_) @name) @item
303                (enum_variant
304                    name: (_) @name) @item
305                (field_declaration
306                    name: (_) @name) @item
307                (impl_item
308                    "impl" @context
309                    trait: (_) @name
310                    "for" @context
311                    type: (_) @name) @item
312                (function_item
313                    "fn" @context
314                    name: (_) @name) @item
315                (mod_item
316                    "mod" @context
317                    name: (_) @name) @item
318                "#,
319            )
320            .unwrap(),
321    );
322
323    let text = r#"
324        struct Person {
325            name: String,
326            age: usize,
327        }
328
329        mod module {
330            enum LoginState {
331                LoggedOut,
332                LoggingOn,
333                LoggedIn {
334                    person: Person,
335                    time: Instant,
336                }
337            }
338        }
339
340        impl Eq for Person {}
341
342        impl Drop for Person {
343            fn drop(&mut self) {
344                println!("bye");
345            }
346        }
347    "#
348    .unindent();
349
350    let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, cx));
351    let outline = buffer
352        .read_with(cx, |buffer, _| buffer.snapshot().outline(None))
353        .unwrap();
354
355    assert_eq!(
356        outline
357            .items
358            .iter()
359            .map(|item| (item.text.as_str(), item.depth))
360            .collect::<Vec<_>>(),
361        &[
362            ("struct Person", 0),
363            ("name", 1),
364            ("age", 1),
365            ("mod module", 0),
366            ("enum LoginState", 1),
367            ("LoggedOut", 2),
368            ("LoggingOn", 2),
369            ("LoggedIn", 2),
370            ("person", 3),
371            ("time", 3),
372            ("impl Eq for Person", 0),
373            ("impl Drop for Person", 0),
374            ("fn drop", 1),
375        ]
376    );
377
378    // Without space, we only match on names
379    assert_eq!(
380        search(&outline, "oon", &cx).await,
381        &[
382            ("mod module", vec![]),                    // included as the parent of a match
383            ("enum LoginState", vec![]),               // included as the parent of a match
384            ("LoggingOn", vec![1, 7, 8]),              // matches
385            ("impl Drop for Person", vec![7, 18, 19]), // matches in two disjoint names
386        ]
387    );
388
389    assert_eq!(
390        search(&outline, "dp p", &cx).await,
391        &[
392            ("impl Drop for Person", vec![5, 8, 9, 14]),
393            ("fn drop", vec![]),
394        ]
395    );
396    assert_eq!(
397        search(&outline, "dpn", &cx).await,
398        &[("impl Drop for Person", vec![5, 14, 19])]
399    );
400    assert_eq!(
401        search(&outline, "impl ", &cx).await,
402        &[
403            ("impl Eq for Person", vec![0, 1, 2, 3, 4]),
404            ("impl Drop for Person", vec![0, 1, 2, 3, 4]),
405            ("fn drop", vec![]),
406        ]
407    );
408
409    async fn search<'a>(
410        outline: &'a Outline<Anchor>,
411        query: &str,
412        cx: &gpui::TestAppContext,
413    ) -> Vec<(&'a str, Vec<usize>)> {
414        let matches = cx
415            .read(|cx| outline.search(query, cx.background().clone()))
416            .await;
417        matches
418            .into_iter()
419            .map(|mat| (outline.items[mat.candidate_id].text.as_str(), mat.positions))
420            .collect::<Vec<_>>()
421    }
422}
423
424#[gpui::test]
425fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) {
426    let buffer = cx.add_model(|cx| {
427        let text = "
428            mod x {
429                mod y {
430
431                }
432            }
433        "
434        .unindent();
435        Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx)
436    });
437    let buffer = buffer.read(cx);
438    assert_eq!(
439        buffer.enclosing_bracket_point_ranges(Point::new(1, 6)..Point::new(1, 6)),
440        Some((
441            Point::new(0, 6)..Point::new(0, 7),
442            Point::new(4, 0)..Point::new(4, 1)
443        ))
444    );
445    assert_eq!(
446        buffer.enclosing_bracket_point_ranges(Point::new(1, 10)..Point::new(1, 10)),
447        Some((
448            Point::new(1, 10)..Point::new(1, 11),
449            Point::new(3, 4)..Point::new(3, 5)
450        ))
451    );
452    assert_eq!(
453        buffer.enclosing_bracket_point_ranges(Point::new(3, 5)..Point::new(3, 5)),
454        Some((
455            Point::new(1, 10)..Point::new(1, 11),
456            Point::new(3, 4)..Point::new(3, 5)
457        ))
458    );
459}
460
461#[gpui::test]
462fn test_range_for_syntax_ancestor(cx: &mut MutableAppContext) {
463    cx.add_model(|cx| {
464        let text = "fn a() { b(|c| {}) }";
465        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
466        let snapshot = buffer.snapshot();
467
468        assert_eq!(
469            snapshot.range_for_syntax_ancestor(empty_range_at(text, "|")),
470            Some(range_of(text, "|"))
471        );
472        assert_eq!(
473            snapshot.range_for_syntax_ancestor(range_of(text, "|")),
474            Some(range_of(text, "|c|"))
475        );
476        assert_eq!(
477            snapshot.range_for_syntax_ancestor(range_of(text, "|c|")),
478            Some(range_of(text, "|c| {}"))
479        );
480        assert_eq!(
481            snapshot.range_for_syntax_ancestor(range_of(text, "|c| {}")),
482            Some(range_of(text, "(|c| {})"))
483        );
484
485        buffer
486    });
487
488    fn empty_range_at(text: &str, part: &str) -> Range<usize> {
489        let start = text.find(part).unwrap();
490        start..start
491    }
492
493    fn range_of(text: &str, part: &str) -> Range<usize> {
494        let start = text.find(part).unwrap();
495        start..start + part.len()
496    }
497}
498
499#[gpui::test]
500fn test_edit_with_autoindent(cx: &mut MutableAppContext) {
501    cx.add_model(|cx| {
502        let text = "fn a() {}";
503        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
504
505        buffer.edit_with_autoindent([8..8], "\n\n", cx);
506        assert_eq!(buffer.text(), "fn a() {\n    \n}");
507
508        buffer.edit_with_autoindent([Point::new(1, 4)..Point::new(1, 4)], "b()\n", cx);
509        assert_eq!(buffer.text(), "fn a() {\n    b()\n    \n}");
510
511        buffer.edit_with_autoindent([Point::new(2, 4)..Point::new(2, 4)], ".c", cx);
512        assert_eq!(buffer.text(), "fn a() {\n    b()\n        .c\n}");
513
514        buffer
515    });
516}
517
518#[gpui::test]
519fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) {
520    cx.add_model(|cx| {
521        let text = "
522            fn a() {
523            c;
524            d;
525            }
526        "
527        .unindent();
528
529        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
530
531        // Lines 2 and 3 don't match the indentation suggestion. When editing these lines,
532        // their indentation is not adjusted.
533        buffer.edit_with_autoindent([empty(Point::new(1, 1)), empty(Point::new(2, 1))], "()", cx);
534        assert_eq!(
535            buffer.text(),
536            "
537            fn a() {
538            c();
539            d();
540            }
541            "
542            .unindent()
543        );
544
545        // When appending new content after these lines, the indentation is based on the
546        // preceding lines' actual indentation.
547        buffer.edit_with_autoindent(
548            [empty(Point::new(1, 1)), empty(Point::new(2, 1))],
549            "\n.f\n.g",
550            cx,
551        );
552        assert_eq!(
553            buffer.text(),
554            "
555            fn a() {
556            c
557                .f
558                .g();
559            d
560                .f
561                .g();
562            }
563            "
564            .unindent()
565        );
566        buffer
567    });
568}
569
570#[gpui::test]
571fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut MutableAppContext) {
572    cx.add_model(|cx| {
573        let text = "
574            fn a() {}
575        "
576        .unindent();
577
578        let mut buffer = Buffer::new(0, text, cx).with_language(Arc::new(rust_lang()), cx);
579
580        buffer.edit_with_autoindent([5..5], "\nb", cx);
581        assert_eq!(
582            buffer.text(),
583            "
584                fn a(
585                    b) {}
586            "
587            .unindent()
588        );
589
590        // The indentation suggestion changed because `@end` node (a close paren)
591        // is now at the beginning of the line.
592        buffer.edit_with_autoindent([Point::new(1, 4)..Point::new(1, 5)], "", cx);
593        assert_eq!(
594            buffer.text(),
595            "
596                fn a(
597                ) {}
598            "
599            .unindent()
600        );
601
602        buffer
603    });
604}
605
606#[gpui::test]
607fn test_serialization(cx: &mut gpui::MutableAppContext) {
608    let mut now = Instant::now();
609
610    let buffer1 = cx.add_model(|cx| {
611        let mut buffer = Buffer::new(0, "abc", cx);
612        buffer.edit([3..3], "D", cx);
613
614        now += Duration::from_secs(1);
615        buffer.start_transaction_at(now);
616        buffer.edit([4..4], "E", cx);
617        buffer.end_transaction_at(now, cx);
618        assert_eq!(buffer.text(), "abcDE");
619
620        buffer.undo(cx);
621        assert_eq!(buffer.text(), "abcD");
622
623        buffer.edit([4..4], "F", cx);
624        assert_eq!(buffer.text(), "abcDF");
625        buffer
626    });
627    assert_eq!(buffer1.read(cx).text(), "abcDF");
628
629    let message = buffer1.read(cx).to_proto();
630    let buffer2 = cx.add_model(|cx| Buffer::from_proto(1, message, None, cx).unwrap());
631    assert_eq!(buffer2.read(cx).text(), "abcDF");
632}
633
634#[gpui::test(iterations = 100)]
635fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
636    let min_peers = env::var("MIN_PEERS")
637        .map(|i| i.parse().expect("invalid `MIN_PEERS` variable"))
638        .unwrap_or(1);
639    let max_peers = env::var("MAX_PEERS")
640        .map(|i| i.parse().expect("invalid `MAX_PEERS` variable"))
641        .unwrap_or(5);
642    let operations = env::var("OPERATIONS")
643        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
644        .unwrap_or(10);
645
646    let base_text_len = rng.gen_range(0..10);
647    let base_text = RandomCharIter::new(&mut rng)
648        .take(base_text_len)
649        .collect::<String>();
650    let mut replica_ids = Vec::new();
651    let mut buffers = Vec::new();
652    let network = Rc::new(RefCell::new(Network::new(rng.clone())));
653
654    for i in 0..rng.gen_range(min_peers..=max_peers) {
655        let buffer = cx.add_model(|cx| {
656            let mut buffer = Buffer::new(i as ReplicaId, base_text.as_str(), cx);
657            buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
658            let network = network.clone();
659            cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
660                if let Event::Operation(op) = event {
661                    network
662                        .borrow_mut()
663                        .broadcast(buffer.replica_id(), vec![proto::serialize_operation(&op)]);
664                }
665            })
666            .detach();
667            buffer
668        });
669        buffers.push(buffer);
670        replica_ids.push(i as ReplicaId);
671        network.borrow_mut().add_peer(i as ReplicaId);
672        log::info!("Adding initial peer with replica id {}", i);
673    }
674
675    log::info!("initial text: {:?}", base_text);
676
677    let mut now = Instant::now();
678    let mut mutation_count = operations;
679    let mut next_diagnostic_id = 0;
680    let mut active_selections = BTreeMap::default();
681    loop {
682        let replica_index = rng.gen_range(0..replica_ids.len());
683        let replica_id = replica_ids[replica_index];
684        let buffer = &mut buffers[replica_index];
685        let mut new_buffer = None;
686        match rng.gen_range(0..100) {
687            0..=29 if mutation_count != 0 => {
688                buffer.update(cx, |buffer, cx| {
689                    buffer.start_transaction_at(now);
690                    buffer.randomly_edit(&mut rng, 5, cx);
691                    buffer.end_transaction_at(now, cx);
692                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
693                });
694                mutation_count -= 1;
695            }
696            30..=39 if mutation_count != 0 => {
697                buffer.update(cx, |buffer, cx| {
698                    let mut selections = Vec::new();
699                    for id in 0..rng.gen_range(1..=5) {
700                        let range = buffer.random_byte_range(0, &mut rng);
701                        selections.push(Selection {
702                            id,
703                            start: buffer.anchor_before(range.start),
704                            end: buffer.anchor_before(range.end),
705                            reversed: false,
706                            goal: SelectionGoal::None,
707                        });
708                    }
709                    let selections: Arc<[Selection<Anchor>]> = selections.into();
710                    log::info!(
711                        "peer {} setting active selections: {:?}",
712                        replica_id,
713                        selections
714                    );
715                    active_selections.insert(replica_id, selections.clone());
716                    buffer.set_active_selections(selections, cx);
717                });
718                mutation_count -= 1;
719            }
720            40..=49 if mutation_count != 0 && replica_id == 0 => {
721                let entry_count = rng.gen_range(1..=5);
722                buffer.update(cx, |buffer, cx| {
723                    let diagnostics = DiagnosticSet::new(
724                        (0..entry_count).map(|_| {
725                            let range = buffer.random_byte_range(0, &mut rng);
726                            let range = range.to_point_utf16(buffer);
727                            DiagnosticEntry {
728                                range,
729                                diagnostic: Diagnostic {
730                                    message: post_inc(&mut next_diagnostic_id).to_string(),
731                                    ..Default::default()
732                                },
733                            }
734                        }),
735                        buffer,
736                    );
737                    log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
738                    buffer.update_diagnostics(diagnostics, cx);
739                });
740                mutation_count -= 1;
741            }
742            50..=59 if replica_ids.len() < max_peers => {
743                let old_buffer = buffer.read(cx).to_proto();
744                let new_replica_id = replica_ids.len() as ReplicaId;
745                log::info!(
746                    "Adding new replica {} (replicating from {})",
747                    new_replica_id,
748                    replica_id
749                );
750                new_buffer = Some(cx.add_model(|cx| {
751                    let mut new_buffer =
752                        Buffer::from_proto(new_replica_id, old_buffer, None, cx).unwrap();
753                    new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
754                    let network = network.clone();
755                    cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
756                        if let Event::Operation(op) = event {
757                            network.borrow_mut().broadcast(
758                                buffer.replica_id(),
759                                vec![proto::serialize_operation(&op)],
760                            );
761                        }
762                    })
763                    .detach();
764                    new_buffer
765                }));
766                replica_ids.push(new_replica_id);
767                network.borrow_mut().replicate(replica_id, new_replica_id);
768            }
769            60..=69 if mutation_count != 0 => {
770                buffer.update(cx, |buffer, cx| {
771                    buffer.randomly_undo_redo(&mut rng, cx);
772                    log::info!("buffer {} text: {:?}", buffer.replica_id(), buffer.text());
773                });
774                mutation_count -= 1;
775            }
776            _ if network.borrow().has_unreceived(replica_id) => {
777                let ops = network
778                    .borrow_mut()
779                    .receive(replica_id)
780                    .into_iter()
781                    .map(|op| proto::deserialize_operation(op).unwrap());
782                if ops.len() > 0 {
783                    log::info!(
784                        "peer {} applying {} ops from the network.",
785                        replica_id,
786                        ops.len()
787                    );
788                    buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx).unwrap());
789                }
790            }
791            _ => {}
792        }
793
794        now += Duration::from_millis(rng.gen_range(0..=200));
795        buffers.extend(new_buffer);
796
797        for buffer in &buffers {
798            buffer.read(cx).check_invariants();
799        }
800
801        if mutation_count == 0 && network.borrow().is_idle() {
802            break;
803        }
804    }
805
806    let first_buffer = buffers[0].read(cx).snapshot();
807    for buffer in &buffers[1..] {
808        let buffer = buffer.read(cx).snapshot();
809        assert_eq!(
810            buffer.text(),
811            first_buffer.text(),
812            "Replica {} text != Replica 0 text",
813            buffer.replica_id()
814        );
815        assert_eq!(
816            buffer
817                .diagnostics_in_range::<_, usize>(0..buffer.len(), false)
818                .collect::<Vec<_>>(),
819            first_buffer
820                .diagnostics_in_range::<_, usize>(0..first_buffer.len(), false)
821                .collect::<Vec<_>>(),
822            "Replica {} diagnostics != Replica 0 diagnostics",
823            buffer.replica_id()
824        );
825    }
826
827    for buffer in &buffers {
828        let buffer = buffer.read(cx).snapshot();
829        let actual_remote_selections = buffer
830            .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
831            .map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>()))
832            .collect::<Vec<_>>();
833        let expected_remote_selections = active_selections
834            .iter()
835            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
836            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
837            .collect::<Vec<_>>();
838        assert_eq!(actual_remote_selections, expected_remote_selections);
839    }
840}
841
842#[test]
843fn test_contiguous_ranges() {
844    assert_eq!(
845        contiguous_ranges([1, 2, 3, 5, 6, 9, 10, 11, 12].into_iter(), 100).collect::<Vec<_>>(),
846        &[1..4, 5..7, 9..13]
847    );
848
849    // Respects the `max_len` parameter
850    assert_eq!(
851        contiguous_ranges(
852            [2, 3, 4, 5, 6, 7, 8, 9, 23, 24, 25, 26, 30, 31].into_iter(),
853            3
854        )
855        .collect::<Vec<_>>(),
856        &[2..5, 5..8, 8..10, 23..26, 26..27, 30..32],
857    );
858}
859
860impl Buffer {
861    pub fn enclosing_bracket_point_ranges<T: ToOffset>(
862        &self,
863        range: Range<T>,
864    ) -> Option<(Range<Point>, Range<Point>)> {
865        self.snapshot()
866            .enclosing_bracket_ranges(range)
867            .map(|(start, end)| {
868                let point_start = start.start.to_point(self)..start.end.to_point(self);
869                let point_end = end.start.to_point(self)..end.end.to_point(self);
870                (point_start, point_end)
871            })
872    }
873}
874
875fn rust_lang() -> Language {
876    Language::new(
877        LanguageConfig {
878            name: "Rust".into(),
879            path_suffixes: vec!["rs".to_string()],
880            language_server: None,
881            ..Default::default()
882        },
883        Some(tree_sitter_rust::language()),
884    )
885    .with_indents_query(
886        r#"
887        (call_expression) @indent
888        (field_expression) @indent
889        (_ "(" ")" @end) @indent
890        (_ "{" "}" @end) @indent
891        "#,
892    )
893    .unwrap()
894    .with_brackets_query(
895        r#"
896        ("{" @open "}" @close)
897        "#,
898    )
899    .unwrap()
900}
901
902fn empty(point: Point) -> Range<Point> {
903    point..point
904}