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