tests.rs

  1use super::{network::Network, *};
  2use clock::ReplicaId;
  3use rand::prelude::*;
  4use std::{
  5    cmp::Ordering,
  6    env,
  7    iter::Iterator,
  8    time::{Duration, Instant},
  9};
 10
 11#[cfg(test)]
 12#[ctor::ctor]
 13fn init_logger() {
 14    zlog::init_test();
 15}
 16
 17#[test]
 18fn test_edit() {
 19    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "abc");
 20    assert_eq!(buffer.text(), "abc");
 21    buffer.edit([(3..3, "def")]);
 22    assert_eq!(buffer.text(), "abcdef");
 23    buffer.edit([(0..0, "ghi")]);
 24    assert_eq!(buffer.text(), "ghiabcdef");
 25    buffer.edit([(5..5, "jkl")]);
 26    assert_eq!(buffer.text(), "ghiabjklcdef");
 27    buffer.edit([(6..7, "")]);
 28    assert_eq!(buffer.text(), "ghiabjlcdef");
 29    buffer.edit([(4..9, "mno")]);
 30    assert_eq!(buffer.text(), "ghiamnoef");
 31}
 32
 33#[gpui::test(iterations = 100)]
 34fn test_random_edits(mut rng: StdRng) {
 35    let operations = env::var("OPERATIONS")
 36        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
 37        .unwrap_or(10);
 38
 39    let reference_string_len = rng.gen_range(0..3);
 40    let mut reference_string = RandomCharIter::new(&mut rng)
 41        .take(reference_string_len)
 42        .collect::<String>();
 43    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), reference_string.clone());
 44    LineEnding::normalize(&mut reference_string);
 45
 46    buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
 47    let mut buffer_versions = Vec::new();
 48    log::info!(
 49        "buffer text {:?}, version: {:?}",
 50        buffer.text(),
 51        buffer.version()
 52    );
 53
 54    for _i in 0..operations {
 55        let (edits, _) = buffer.randomly_edit(&mut rng, 5);
 56        for (old_range, new_text) in edits.iter().rev() {
 57            reference_string.replace_range(old_range.clone(), new_text);
 58        }
 59
 60        assert_eq!(buffer.text(), reference_string);
 61        log::info!(
 62            "buffer text {:?}, version: {:?}",
 63            buffer.text(),
 64            buffer.version()
 65        );
 66
 67        if rng.gen_bool(0.25) {
 68            buffer.randomly_undo_redo(&mut rng);
 69            reference_string = buffer.text();
 70            log::info!(
 71                "buffer text {:?}, version: {:?}",
 72                buffer.text(),
 73                buffer.version()
 74            );
 75        }
 76
 77        let range = buffer.random_byte_range(0, &mut rng);
 78        assert_eq!(
 79            buffer.text_summary_for_range::<TextSummary, _>(range.clone()),
 80            TextSummary::from(&reference_string[range])
 81        );
 82
 83        buffer.check_invariants();
 84
 85        if rng.gen_bool(0.3) {
 86            buffer_versions.push((buffer.clone(), buffer.subscribe()));
 87        }
 88    }
 89
 90    for (old_buffer, subscription) in buffer_versions {
 91        let edits = buffer
 92            .edits_since::<usize>(&old_buffer.version)
 93            .collect::<Vec<_>>();
 94
 95        log::info!(
 96            "applying edits since version {:?} to old text: {:?}: {:?}",
 97            old_buffer.version(),
 98            old_buffer.text(),
 99            edits,
100        );
101
102        let mut text = old_buffer.visible_text.clone();
103        for edit in edits {
104            let new_text: String = buffer.text_for_range(edit.new.clone()).collect();
105            text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text);
106        }
107        assert_eq!(text.to_string(), buffer.text());
108
109        assert_eq!(
110            buffer.rope_for_version(old_buffer.version()).to_string(),
111            old_buffer.text()
112        );
113
114        for _ in 0..5 {
115            let end_ix = old_buffer.clip_offset(rng.gen_range(0..=old_buffer.len()), Bias::Right);
116            let start_ix = old_buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
117            let range = old_buffer.anchor_before(start_ix)..old_buffer.anchor_after(end_ix);
118            let mut old_text = old_buffer.text_for_range(range.clone()).collect::<String>();
119            let edits = buffer
120                .edits_since_in_range::<usize>(&old_buffer.version, range.clone())
121                .collect::<Vec<_>>();
122            log::info!(
123                "applying edits since version {:?} to old text in range {:?}: {:?}: {:?}",
124                old_buffer.version(),
125                start_ix..end_ix,
126                old_text,
127                edits,
128            );
129
130            let new_text = buffer.text_for_range(range).collect::<String>();
131            for edit in edits {
132                old_text.replace_range(
133                    edit.new.start..edit.new.start + edit.old_len(),
134                    &new_text[edit.new],
135                );
136            }
137            assert_eq!(old_text, new_text);
138        }
139
140        assert_eq!(
141            buffer.has_edits_since(&old_buffer.version),
142            buffer
143                .edits_since::<usize>(&old_buffer.version)
144                .next()
145                .is_some(),
146        );
147
148        let subscription_edits = subscription.consume();
149        log::info!(
150            "applying subscription edits since version {:?} to old text: {:?}: {:?}",
151            old_buffer.version(),
152            old_buffer.text(),
153            subscription_edits,
154        );
155
156        let mut text = old_buffer.visible_text.clone();
157        for edit in subscription_edits.into_inner() {
158            let new_text: String = buffer.text_for_range(edit.new.clone()).collect();
159            text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text);
160        }
161        assert_eq!(text.to_string(), buffer.text());
162    }
163}
164
165#[test]
166fn test_line_endings() {
167    assert_eq!(LineEnding::detect(&"🍐✅\n".repeat(1000)), LineEnding::Unix);
168    assert_eq!(LineEnding::detect(&"abcd\n".repeat(1000)), LineEnding::Unix);
169    assert_eq!(
170        LineEnding::detect(&"🍐✅\r\n".repeat(1000)),
171        LineEnding::Windows
172    );
173    assert_eq!(
174        LineEnding::detect(&"abcd\r\n".repeat(1000)),
175        LineEnding::Windows
176    );
177
178    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "one\r\ntwo\rthree");
179    assert_eq!(buffer.text(), "one\ntwo\nthree");
180    assert_eq!(buffer.line_ending(), LineEnding::Windows);
181    buffer.check_invariants();
182
183    buffer.edit([(buffer.len()..buffer.len(), "\r\nfour")]);
184    buffer.edit([(0..0, "zero\r\n")]);
185    assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
186    assert_eq!(buffer.line_ending(), LineEnding::Windows);
187    buffer.check_invariants();
188}
189
190#[test]
191fn test_line_len() {
192    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
193    buffer.edit([(0..0, "abcd\nefg\nhij")]);
194    buffer.edit([(12..12, "kl\nmno")]);
195    buffer.edit([(18..18, "\npqrs\n")]);
196    buffer.edit([(18..21, "\nPQ")]);
197
198    assert_eq!(buffer.line_len(0), 4);
199    assert_eq!(buffer.line_len(1), 3);
200    assert_eq!(buffer.line_len(2), 5);
201    assert_eq!(buffer.line_len(3), 3);
202    assert_eq!(buffer.line_len(4), 4);
203    assert_eq!(buffer.line_len(5), 0);
204}
205
206#[test]
207fn test_common_prefix_at_position() {
208    let text = "a = str; b = δα";
209    let buffer = Buffer::new(0, BufferId::new(1).unwrap(), text);
210
211    let offset1 = offset_after(text, "str");
212    let offset2 = offset_after(text, "δα");
213
214    // the preceding word is a prefix of the suggestion
215    assert_eq!(
216        buffer.common_prefix_at(offset1, "string"),
217        range_of(text, "str"),
218    );
219    // a suffix of the preceding word is a prefix of the suggestion
220    assert_eq!(
221        buffer.common_prefix_at(offset1, "tree"),
222        range_of(text, "tr"),
223    );
224    // the preceding word is a substring of the suggestion, but not a prefix
225    assert_eq!(
226        buffer.common_prefix_at(offset1, "astro"),
227        empty_range_after(text, "str"),
228    );
229
230    // prefix matching is case insensitive.
231    assert_eq!(
232        buffer.common_prefix_at(offset1, "Strαngε"),
233        range_of(text, "str"),
234    );
235    assert_eq!(
236        buffer.common_prefix_at(offset2, "ΔΑΜΝ"),
237        range_of(text, "δα"),
238    );
239
240    fn offset_after(text: &str, part: &str) -> usize {
241        text.find(part).unwrap() + part.len()
242    }
243
244    fn empty_range_after(text: &str, part: &str) -> Range<usize> {
245        let offset = offset_after(text, part);
246        offset..offset
247    }
248
249    fn range_of(text: &str, part: &str) -> Range<usize> {
250        let start = text.find(part).unwrap();
251        start..start + part.len()
252    }
253}
254
255#[test]
256fn test_text_summary_for_range() {
257    let buffer = Buffer::new(
258        0,
259        BufferId::new(1).unwrap(),
260        "ab\nefg\nhklm\nnopqrs\ntuvwxyz",
261    );
262    assert_eq!(
263        buffer.text_summary_for_range::<TextSummary, _>(0..2),
264        TextSummary {
265            len: 2,
266            chars: 2,
267            len_utf16: OffsetUtf16(2),
268            lines: Point::new(0, 2),
269            first_line_chars: 2,
270            last_line_chars: 2,
271            last_line_len_utf16: 2,
272            longest_row: 0,
273            longest_row_chars: 2,
274        }
275    );
276    assert_eq!(
277        buffer.text_summary_for_range::<TextSummary, _>(1..3),
278        TextSummary {
279            len: 2,
280            chars: 2,
281            len_utf16: OffsetUtf16(2),
282            lines: Point::new(1, 0),
283            first_line_chars: 1,
284            last_line_chars: 0,
285            last_line_len_utf16: 0,
286            longest_row: 0,
287            longest_row_chars: 1,
288        }
289    );
290    assert_eq!(
291        buffer.text_summary_for_range::<TextSummary, _>(1..12),
292        TextSummary {
293            len: 11,
294            chars: 11,
295            len_utf16: OffsetUtf16(11),
296            lines: Point::new(3, 0),
297            first_line_chars: 1,
298            last_line_chars: 0,
299            last_line_len_utf16: 0,
300            longest_row: 2,
301            longest_row_chars: 4,
302        }
303    );
304    assert_eq!(
305        buffer.text_summary_for_range::<TextSummary, _>(0..20),
306        TextSummary {
307            len: 20,
308            chars: 20,
309            len_utf16: OffsetUtf16(20),
310            lines: Point::new(4, 1),
311            first_line_chars: 2,
312            last_line_chars: 1,
313            last_line_len_utf16: 1,
314            longest_row: 3,
315            longest_row_chars: 6,
316        }
317    );
318    assert_eq!(
319        buffer.text_summary_for_range::<TextSummary, _>(0..22),
320        TextSummary {
321            len: 22,
322            chars: 22,
323            len_utf16: OffsetUtf16(22),
324            lines: Point::new(4, 3),
325            first_line_chars: 2,
326            last_line_chars: 3,
327            last_line_len_utf16: 3,
328            longest_row: 3,
329            longest_row_chars: 6,
330        }
331    );
332    assert_eq!(
333        buffer.text_summary_for_range::<TextSummary, _>(7..22),
334        TextSummary {
335            len: 15,
336            chars: 15,
337            len_utf16: OffsetUtf16(15),
338            lines: Point::new(2, 3),
339            first_line_chars: 4,
340            last_line_chars: 3,
341            last_line_len_utf16: 3,
342            longest_row: 1,
343            longest_row_chars: 6,
344        }
345    );
346}
347
348#[test]
349fn test_chars_at() {
350    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
351    buffer.edit([(0..0, "abcd\nefgh\nij")]);
352    buffer.edit([(12..12, "kl\nmno")]);
353    buffer.edit([(18..18, "\npqrs")]);
354    buffer.edit([(18..21, "\nPQ")]);
355
356    let chars = buffer.chars_at(Point::new(0, 0));
357    assert_eq!(chars.collect::<String>(), "abcd\nefgh\nijkl\nmno\nPQrs");
358
359    let chars = buffer.chars_at(Point::new(1, 0));
360    assert_eq!(chars.collect::<String>(), "efgh\nijkl\nmno\nPQrs");
361
362    let chars = buffer.chars_at(Point::new(2, 0));
363    assert_eq!(chars.collect::<String>(), "ijkl\nmno\nPQrs");
364
365    let chars = buffer.chars_at(Point::new(3, 0));
366    assert_eq!(chars.collect::<String>(), "mno\nPQrs");
367
368    let chars = buffer.chars_at(Point::new(4, 0));
369    assert_eq!(chars.collect::<String>(), "PQrs");
370
371    // Regression test:
372    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
373    buffer.edit([(0..0, "[workspace]\nmembers = [\n    \"xray_core\",\n    \"xray_server\",\n    \"xray_cli\",\n    \"xray_wasm\",\n]\n")]);
374    buffer.edit([(60..60, "\n")]);
375
376    let chars = buffer.chars_at(Point::new(6, 0));
377    assert_eq!(chars.collect::<String>(), "    \"xray_wasm\",\n]\n");
378}
379
380#[test]
381fn test_anchors() {
382    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
383    buffer.edit([(0..0, "abc")]);
384    let left_anchor = buffer.anchor_before(2);
385    let right_anchor = buffer.anchor_after(2);
386
387    buffer.edit([(1..1, "def\n")]);
388    assert_eq!(buffer.text(), "adef\nbc");
389    assert_eq!(left_anchor.to_offset(&buffer), 6);
390    assert_eq!(right_anchor.to_offset(&buffer), 6);
391    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
392    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
393
394    buffer.edit([(2..3, "")]);
395    assert_eq!(buffer.text(), "adf\nbc");
396    assert_eq!(left_anchor.to_offset(&buffer), 5);
397    assert_eq!(right_anchor.to_offset(&buffer), 5);
398    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
399    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
400
401    buffer.edit([(5..5, "ghi\n")]);
402    assert_eq!(buffer.text(), "adf\nbghi\nc");
403    assert_eq!(left_anchor.to_offset(&buffer), 5);
404    assert_eq!(right_anchor.to_offset(&buffer), 9);
405    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
406    assert_eq!(right_anchor.to_point(&buffer), Point { row: 2, column: 0 });
407
408    buffer.edit([(7..9, "")]);
409    assert_eq!(buffer.text(), "adf\nbghc");
410    assert_eq!(left_anchor.to_offset(&buffer), 5);
411    assert_eq!(right_anchor.to_offset(&buffer), 7);
412    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 },);
413    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 3 });
414
415    // Ensure anchoring to a point is equivalent to anchoring to an offset.
416    assert_eq!(
417        buffer.anchor_before(Point { row: 0, column: 0 }),
418        buffer.anchor_before(0)
419    );
420    assert_eq!(
421        buffer.anchor_before(Point { row: 0, column: 1 }),
422        buffer.anchor_before(1)
423    );
424    assert_eq!(
425        buffer.anchor_before(Point { row: 0, column: 2 }),
426        buffer.anchor_before(2)
427    );
428    assert_eq!(
429        buffer.anchor_before(Point { row: 0, column: 3 }),
430        buffer.anchor_before(3)
431    );
432    assert_eq!(
433        buffer.anchor_before(Point { row: 1, column: 0 }),
434        buffer.anchor_before(4)
435    );
436    assert_eq!(
437        buffer.anchor_before(Point { row: 1, column: 1 }),
438        buffer.anchor_before(5)
439    );
440    assert_eq!(
441        buffer.anchor_before(Point { row: 1, column: 2 }),
442        buffer.anchor_before(6)
443    );
444    assert_eq!(
445        buffer.anchor_before(Point { row: 1, column: 3 }),
446        buffer.anchor_before(7)
447    );
448    assert_eq!(
449        buffer.anchor_before(Point { row: 1, column: 4 }),
450        buffer.anchor_before(8)
451    );
452
453    // Comparison between anchors.
454    let anchor_at_offset_0 = buffer.anchor_before(0);
455    let anchor_at_offset_1 = buffer.anchor_before(1);
456    let anchor_at_offset_2 = buffer.anchor_before(2);
457
458    assert_eq!(
459        anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer),
460        Ordering::Equal
461    );
462    assert_eq!(
463        anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer),
464        Ordering::Equal
465    );
466    assert_eq!(
467        anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer),
468        Ordering::Equal
469    );
470
471    assert_eq!(
472        anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer),
473        Ordering::Less
474    );
475    assert_eq!(
476        anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer),
477        Ordering::Less
478    );
479    assert_eq!(
480        anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer),
481        Ordering::Less
482    );
483
484    assert_eq!(
485        anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer),
486        Ordering::Greater
487    );
488    assert_eq!(
489        anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer),
490        Ordering::Greater
491    );
492    assert_eq!(
493        anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer),
494        Ordering::Greater
495    );
496}
497
498#[test]
499fn test_anchors_at_start_and_end() {
500    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "");
501    let before_start_anchor = buffer.anchor_before(0);
502    let after_end_anchor = buffer.anchor_after(0);
503
504    buffer.edit([(0..0, "abc")]);
505    assert_eq!(buffer.text(), "abc");
506    assert_eq!(before_start_anchor.to_offset(&buffer), 0);
507    assert_eq!(after_end_anchor.to_offset(&buffer), 3);
508
509    let after_start_anchor = buffer.anchor_after(0);
510    let before_end_anchor = buffer.anchor_before(3);
511
512    buffer.edit([(3..3, "def")]);
513    buffer.edit([(0..0, "ghi")]);
514    assert_eq!(buffer.text(), "ghiabcdef");
515    assert_eq!(before_start_anchor.to_offset(&buffer), 0);
516    assert_eq!(after_start_anchor.to_offset(&buffer), 3);
517    assert_eq!(before_end_anchor.to_offset(&buffer), 6);
518    assert_eq!(after_end_anchor.to_offset(&buffer), 9);
519}
520
521#[test]
522fn test_undo_redo() {
523    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234");
524    // Set group interval to zero so as to not group edits in the undo stack.
525    buffer.set_group_interval(Duration::from_secs(0));
526
527    buffer.edit([(1..1, "abx")]);
528    buffer.edit([(3..4, "yzef")]);
529    buffer.edit([(3..5, "cd")]);
530    assert_eq!(buffer.text(), "1abcdef234");
531
532    let entries = buffer.history.undo_stack.clone();
533    assert_eq!(entries.len(), 3);
534
535    buffer.undo_or_redo(entries[0].transaction.clone());
536    assert_eq!(buffer.text(), "1cdef234");
537    buffer.undo_or_redo(entries[0].transaction.clone());
538    assert_eq!(buffer.text(), "1abcdef234");
539
540    buffer.undo_or_redo(entries[1].transaction.clone());
541    assert_eq!(buffer.text(), "1abcdx234");
542    buffer.undo_or_redo(entries[2].transaction.clone());
543    assert_eq!(buffer.text(), "1abx234");
544    buffer.undo_or_redo(entries[1].transaction.clone());
545    assert_eq!(buffer.text(), "1abyzef234");
546    buffer.undo_or_redo(entries[2].transaction.clone());
547    assert_eq!(buffer.text(), "1abcdef234");
548
549    buffer.undo_or_redo(entries[2].transaction.clone());
550    assert_eq!(buffer.text(), "1abyzef234");
551    buffer.undo_or_redo(entries[0].transaction.clone());
552    assert_eq!(buffer.text(), "1yzef234");
553    buffer.undo_or_redo(entries[1].transaction.clone());
554    assert_eq!(buffer.text(), "1234");
555}
556
557#[test]
558fn test_history() {
559    let mut now = Instant::now();
560    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456");
561    buffer.set_group_interval(Duration::from_millis(300));
562
563    let transaction_1 = buffer.start_transaction_at(now).unwrap();
564    buffer.edit([(2..4, "cd")]);
565    buffer.end_transaction_at(now);
566    assert_eq!(buffer.text(), "12cd56");
567
568    buffer.start_transaction_at(now);
569    buffer.edit([(4..5, "e")]);
570    buffer.end_transaction_at(now).unwrap();
571    assert_eq!(buffer.text(), "12cde6");
572
573    now += buffer.transaction_group_interval() + Duration::from_millis(1);
574    buffer.start_transaction_at(now);
575    buffer.edit([(0..1, "a")]);
576    buffer.edit([(1..1, "b")]);
577    buffer.end_transaction_at(now).unwrap();
578    assert_eq!(buffer.text(), "ab2cde6");
579
580    // Last transaction happened past the group interval, undo it on its own.
581    buffer.undo();
582    assert_eq!(buffer.text(), "12cde6");
583
584    // First two transactions happened within the group interval, undo them together.
585    buffer.undo();
586    assert_eq!(buffer.text(), "123456");
587
588    // Redo the first two transactions together.
589    buffer.redo();
590    assert_eq!(buffer.text(), "12cde6");
591
592    // Redo the last transaction on its own.
593    buffer.redo();
594    assert_eq!(buffer.text(), "ab2cde6");
595
596    buffer.start_transaction_at(now);
597    assert!(buffer.end_transaction_at(now).is_none());
598    buffer.undo();
599    assert_eq!(buffer.text(), "12cde6");
600
601    // Redo stack gets cleared after performing an edit.
602    buffer.start_transaction_at(now);
603    buffer.edit([(0..0, "X")]);
604    buffer.end_transaction_at(now);
605    assert_eq!(buffer.text(), "X12cde6");
606    buffer.redo();
607    assert_eq!(buffer.text(), "X12cde6");
608    buffer.undo();
609    assert_eq!(buffer.text(), "12cde6");
610    buffer.undo();
611    assert_eq!(buffer.text(), "123456");
612
613    // Transactions can be grouped manually.
614    buffer.redo();
615    buffer.redo();
616    assert_eq!(buffer.text(), "X12cde6");
617    buffer.group_until_transaction(transaction_1);
618    buffer.undo();
619    assert_eq!(buffer.text(), "123456");
620    buffer.redo();
621    assert_eq!(buffer.text(), "X12cde6");
622}
623
624#[test]
625fn test_finalize_last_transaction() {
626    let now = Instant::now();
627    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "123456");
628    buffer.history.group_interval = Duration::from_millis(1);
629
630    buffer.start_transaction_at(now);
631    buffer.edit([(2..4, "cd")]);
632    buffer.end_transaction_at(now);
633    assert_eq!(buffer.text(), "12cd56");
634
635    buffer.finalize_last_transaction();
636    buffer.start_transaction_at(now);
637    buffer.edit([(4..5, "e")]);
638    buffer.end_transaction_at(now).unwrap();
639    assert_eq!(buffer.text(), "12cde6");
640
641    buffer.start_transaction_at(now);
642    buffer.edit([(0..1, "a")]);
643    buffer.edit([(1..1, "b")]);
644    buffer.end_transaction_at(now).unwrap();
645    assert_eq!(buffer.text(), "ab2cde6");
646
647    buffer.undo();
648    assert_eq!(buffer.text(), "12cd56");
649
650    buffer.undo();
651    assert_eq!(buffer.text(), "123456");
652
653    buffer.redo();
654    assert_eq!(buffer.text(), "12cd56");
655
656    buffer.redo();
657    assert_eq!(buffer.text(), "ab2cde6");
658}
659
660#[test]
661fn test_edited_ranges_for_transaction() {
662    let now = Instant::now();
663    let mut buffer = Buffer::new(0, BufferId::new(1).unwrap(), "1234567");
664
665    buffer.start_transaction_at(now);
666    buffer.edit([(2..4, "cd")]);
667    buffer.edit([(6..6, "efg")]);
668    buffer.end_transaction_at(now);
669    assert_eq!(buffer.text(), "12cd56efg7");
670
671    let tx = buffer.finalize_last_transaction().unwrap().clone();
672    assert_eq!(
673        buffer
674            .edited_ranges_for_transaction::<usize>(&tx)
675            .collect::<Vec<_>>(),
676        [2..4, 6..9]
677    );
678
679    buffer.edit([(5..5, "hijk")]);
680    assert_eq!(buffer.text(), "12cd5hijk6efg7");
681    assert_eq!(
682        buffer
683            .edited_ranges_for_transaction::<usize>(&tx)
684            .collect::<Vec<_>>(),
685        [2..4, 10..13]
686    );
687
688    buffer.edit([(4..4, "l")]);
689    assert_eq!(buffer.text(), "12cdl5hijk6efg7");
690    assert_eq!(
691        buffer
692            .edited_ranges_for_transaction::<usize>(&tx)
693            .collect::<Vec<_>>(),
694        [2..4, 11..14]
695    );
696}
697
698#[test]
699fn test_concurrent_edits() {
700    let text = "abcdef";
701
702    let mut buffer1 = Buffer::new(1, BufferId::new(1).unwrap(), text);
703    let mut buffer2 = Buffer::new(2, BufferId::new(1).unwrap(), text);
704    let mut buffer3 = Buffer::new(3, BufferId::new(1).unwrap(), text);
705
706    let buf1_op = buffer1.edit([(1..2, "12")]);
707    assert_eq!(buffer1.text(), "a12cdef");
708    let buf2_op = buffer2.edit([(3..4, "34")]);
709    assert_eq!(buffer2.text(), "abc34ef");
710    let buf3_op = buffer3.edit([(5..6, "56")]);
711    assert_eq!(buffer3.text(), "abcde56");
712
713    buffer1.apply_op(buf2_op.clone());
714    buffer1.apply_op(buf3_op.clone());
715    buffer2.apply_op(buf1_op.clone());
716    buffer2.apply_op(buf3_op);
717    buffer3.apply_op(buf1_op);
718    buffer3.apply_op(buf2_op);
719
720    assert_eq!(buffer1.text(), "a12c34e56");
721    assert_eq!(buffer2.text(), "a12c34e56");
722    assert_eq!(buffer3.text(), "a12c34e56");
723}
724
725#[gpui::test(iterations = 100)]
726fn test_random_concurrent_edits(mut rng: StdRng) {
727    let peers = env::var("PEERS")
728        .map(|i| i.parse().expect("invalid `PEERS` variable"))
729        .unwrap_or(5);
730    let operations = env::var("OPERATIONS")
731        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
732        .unwrap_or(10);
733
734    let base_text_len = rng.gen_range(0..10);
735    let base_text = RandomCharIter::new(&mut rng)
736        .take(base_text_len)
737        .collect::<String>();
738    let mut replica_ids = Vec::new();
739    let mut buffers = Vec::new();
740    let mut network = Network::new(rng.clone());
741
742    for i in 0..peers {
743        let mut buffer = Buffer::new(i as ReplicaId, BufferId::new(1).unwrap(), base_text.clone());
744        buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200));
745        buffers.push(buffer);
746        replica_ids.push(i as u16);
747        network.add_peer(i as u16);
748    }
749
750    log::info!("initial text: {:?}", base_text);
751
752    let mut mutation_count = operations;
753    loop {
754        let replica_index = rng.gen_range(0..peers);
755        let replica_id = replica_ids[replica_index];
756        let buffer = &mut buffers[replica_index];
757        match rng.gen_range(0..=100) {
758            0..=50 if mutation_count != 0 => {
759                let op = buffer.randomly_edit(&mut rng, 5).1;
760                network.broadcast(buffer.replica_id, vec![op]);
761                log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text());
762                mutation_count -= 1;
763            }
764            51..=70 if mutation_count != 0 => {
765                let ops = buffer.randomly_undo_redo(&mut rng);
766                network.broadcast(buffer.replica_id, ops);
767                mutation_count -= 1;
768            }
769            71..=100 if network.has_unreceived(replica_id) => {
770                let ops = network.receive(replica_id);
771                if !ops.is_empty() {
772                    log::info!(
773                        "peer {} applying {} ops from the network.",
774                        replica_id,
775                        ops.len()
776                    );
777                    buffer.apply_ops(ops);
778                }
779            }
780            _ => {}
781        }
782        buffer.check_invariants();
783
784        if mutation_count == 0 && network.is_idle() {
785            break;
786        }
787    }
788
789    let first_buffer = &buffers[0];
790    for buffer in &buffers[1..] {
791        assert_eq!(
792            buffer.text(),
793            first_buffer.text(),
794            "Replica {} text != Replica 0 text",
795            buffer.replica_id
796        );
797        buffer.check_invariants();
798    }
799}