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};
 10use util::test::marked_text_ranges;
 11
 12#[cfg(test)]
 13#[ctor::ctor]
 14fn init_logger() {
 15    if std::env::var("RUST_LOG").is_ok() {
 16        env_logger::init();
 17    }
 18}
 19
 20#[test]
 21fn test_edit() {
 22    let mut buffer = Buffer::new(0, 0, History::new("abc".into()));
 23    assert_eq!(buffer.text(), "abc");
 24    buffer.edit(vec![3..3], "def");
 25    assert_eq!(buffer.text(), "abcdef");
 26    buffer.edit(vec![0..0], "ghi");
 27    assert_eq!(buffer.text(), "ghiabcdef");
 28    buffer.edit(vec![5..5], "jkl");
 29    assert_eq!(buffer.text(), "ghiabjklcdef");
 30    buffer.edit(vec![6..7], "");
 31    assert_eq!(buffer.text(), "ghiabjlcdef");
 32    buffer.edit(vec![4..9], "mno");
 33    assert_eq!(buffer.text(), "ghiamnoef");
 34}
 35
 36#[gpui::test(iterations = 100)]
 37fn test_random_edits(mut rng: StdRng) {
 38    let operations = env::var("OPERATIONS")
 39        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
 40        .unwrap_or(10);
 41
 42    let reference_string_len = rng.gen_range(0..3);
 43    let mut reference_string = RandomCharIter::new(&mut rng)
 44        .take(reference_string_len)
 45        .collect::<String>();
 46    let mut buffer = Buffer::new(0, 0, History::new(reference_string.clone().into()));
 47    buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200));
 48    let mut buffer_versions = Vec::new();
 49    log::info!(
 50        "buffer text {:?}, version: {:?}",
 51        buffer.text(),
 52        buffer.version()
 53    );
 54
 55    for _i in 0..operations {
 56        let (old_ranges, new_text, _) = buffer.randomly_edit(&mut rng, 5);
 57        for old_range in old_ranges.iter().rev() {
 58            reference_string.replace_range(old_range.clone(), &new_text);
 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        for _ in 0..5 {
110            let end_ix = old_buffer.clip_offset(rng.gen_range(0..=old_buffer.len()), Bias::Right);
111            let start_ix = old_buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left);
112            let range = old_buffer.anchor_before(start_ix)..old_buffer.anchor_after(end_ix);
113            let mut old_text = old_buffer.text_for_range(range.clone()).collect::<String>();
114            let edits = buffer
115                .edits_since_in_range::<usize>(&old_buffer.version, range.clone())
116                .collect::<Vec<_>>();
117            log::info!(
118                "applying edits since version {:?} to old text in range {:?}: {:?}: {:?}",
119                old_buffer.version(),
120                start_ix..end_ix,
121                old_text,
122                edits,
123            );
124
125            let new_text = buffer.text_for_range(range).collect::<String>();
126            for edit in edits {
127                old_text.replace_range(
128                    edit.new.start..edit.new.start + edit.old_len(),
129                    &new_text[edit.new],
130                );
131            }
132            assert_eq!(old_text, new_text);
133        }
134
135        let subscription_edits = subscription.consume();
136        log::info!(
137            "applying subscription edits since version {:?} to old text: {:?}: {:?}",
138            old_buffer.version(),
139            old_buffer.text(),
140            subscription_edits,
141        );
142
143        let mut text = old_buffer.visible_text.clone();
144        for edit in subscription_edits.into_inner() {
145            let new_text: String = buffer.text_for_range(edit.new.clone()).collect();
146            text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text);
147        }
148        assert_eq!(text.to_string(), buffer.text());
149    }
150}
151
152#[test]
153fn test_line_len() {
154    let mut buffer = Buffer::new(0, 0, History::new("".into()));
155    buffer.edit(vec![0..0], "abcd\nefg\nhij");
156    buffer.edit(vec![12..12], "kl\nmno");
157    buffer.edit(vec![18..18], "\npqrs\n");
158    buffer.edit(vec![18..21], "\nPQ");
159
160    assert_eq!(buffer.line_len(0), 4);
161    assert_eq!(buffer.line_len(1), 3);
162    assert_eq!(buffer.line_len(2), 5);
163    assert_eq!(buffer.line_len(3), 3);
164    assert_eq!(buffer.line_len(4), 4);
165    assert_eq!(buffer.line_len(5), 0);
166}
167
168#[test]
169fn test_common_prefix_at_positionn() {
170    let (text, ranges) = marked_text_ranges("a = [bcd]");
171    let buffer = Buffer::new(0, 0, History::new(text.into()));
172    let snapshot = &buffer.snapshot();
173    let expected_range = ranges[0].to_offset(&snapshot);
174    assert_eq!(
175        buffer.common_prefix_at(expected_range.end, "bcdef"),
176        expected_range
177    )
178}
179
180#[test]
181fn test_text_summary_for_range() {
182    let buffer = Buffer::new(0, 0, History::new("ab\nefg\nhklm\nnopqrs\ntuvwxyz".into()));
183    assert_eq!(
184        buffer.text_summary_for_range::<TextSummary, _>(1..3),
185        TextSummary {
186            bytes: 2,
187            lines: Point::new(1, 0),
188            lines_utf16: PointUtf16::new(1, 0),
189            first_line_chars: 1,
190            last_line_chars: 0,
191            longest_row: 0,
192            longest_row_chars: 1,
193        }
194    );
195    assert_eq!(
196        buffer.text_summary_for_range::<TextSummary, _>(1..12),
197        TextSummary {
198            bytes: 11,
199            lines: Point::new(3, 0),
200            lines_utf16: PointUtf16::new(3, 0),
201            first_line_chars: 1,
202            last_line_chars: 0,
203            longest_row: 2,
204            longest_row_chars: 4,
205        }
206    );
207    assert_eq!(
208        buffer.text_summary_for_range::<TextSummary, _>(0..20),
209        TextSummary {
210            bytes: 20,
211            lines: Point::new(4, 1),
212            lines_utf16: PointUtf16::new(4, 1),
213            first_line_chars: 2,
214            last_line_chars: 1,
215            longest_row: 3,
216            longest_row_chars: 6,
217        }
218    );
219    assert_eq!(
220        buffer.text_summary_for_range::<TextSummary, _>(0..22),
221        TextSummary {
222            bytes: 22,
223            lines: Point::new(4, 3),
224            lines_utf16: PointUtf16::new(4, 3),
225            first_line_chars: 2,
226            last_line_chars: 3,
227            longest_row: 3,
228            longest_row_chars: 6,
229        }
230    );
231    assert_eq!(
232        buffer.text_summary_for_range::<TextSummary, _>(7..22),
233        TextSummary {
234            bytes: 15,
235            lines: Point::new(2, 3),
236            lines_utf16: PointUtf16::new(2, 3),
237            first_line_chars: 4,
238            last_line_chars: 3,
239            longest_row: 1,
240            longest_row_chars: 6,
241        }
242    );
243}
244
245#[test]
246fn test_chars_at() {
247    let mut buffer = Buffer::new(0, 0, History::new("".into()));
248    buffer.edit(vec![0..0], "abcd\nefgh\nij");
249    buffer.edit(vec![12..12], "kl\nmno");
250    buffer.edit(vec![18..18], "\npqrs");
251    buffer.edit(vec![18..21], "\nPQ");
252
253    let chars = buffer.chars_at(Point::new(0, 0));
254    assert_eq!(chars.collect::<String>(), "abcd\nefgh\nijkl\nmno\nPQrs");
255
256    let chars = buffer.chars_at(Point::new(1, 0));
257    assert_eq!(chars.collect::<String>(), "efgh\nijkl\nmno\nPQrs");
258
259    let chars = buffer.chars_at(Point::new(2, 0));
260    assert_eq!(chars.collect::<String>(), "ijkl\nmno\nPQrs");
261
262    let chars = buffer.chars_at(Point::new(3, 0));
263    assert_eq!(chars.collect::<String>(), "mno\nPQrs");
264
265    let chars = buffer.chars_at(Point::new(4, 0));
266    assert_eq!(chars.collect::<String>(), "PQrs");
267
268    // Regression test:
269    let mut buffer = Buffer::new(0, 0, History::new("".into()));
270    buffer.edit(vec![0..0], "[workspace]\nmembers = [\n    \"xray_core\",\n    \"xray_server\",\n    \"xray_cli\",\n    \"xray_wasm\",\n]\n");
271    buffer.edit(vec![60..60], "\n");
272
273    let chars = buffer.chars_at(Point::new(6, 0));
274    assert_eq!(chars.collect::<String>(), "    \"xray_wasm\",\n]\n");
275}
276
277#[test]
278fn test_anchors() {
279    let mut buffer = Buffer::new(0, 0, History::new("".into()));
280    buffer.edit(vec![0..0], "abc");
281    let left_anchor = buffer.anchor_before(2);
282    let right_anchor = buffer.anchor_after(2);
283
284    buffer.edit(vec![1..1], "def\n");
285    assert_eq!(buffer.text(), "adef\nbc");
286    assert_eq!(left_anchor.to_offset(&buffer), 6);
287    assert_eq!(right_anchor.to_offset(&buffer), 6);
288    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
289    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
290
291    buffer.edit(vec![2..3], "");
292    assert_eq!(buffer.text(), "adf\nbc");
293    assert_eq!(left_anchor.to_offset(&buffer), 5);
294    assert_eq!(right_anchor.to_offset(&buffer), 5);
295    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
296    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
297
298    buffer.edit(vec![5..5], "ghi\n");
299    assert_eq!(buffer.text(), "adf\nbghi\nc");
300    assert_eq!(left_anchor.to_offset(&buffer), 5);
301    assert_eq!(right_anchor.to_offset(&buffer), 9);
302    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
303    assert_eq!(right_anchor.to_point(&buffer), Point { row: 2, column: 0 });
304
305    buffer.edit(vec![7..9], "");
306    assert_eq!(buffer.text(), "adf\nbghc");
307    assert_eq!(left_anchor.to_offset(&buffer), 5);
308    assert_eq!(right_anchor.to_offset(&buffer), 7);
309    assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 },);
310    assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 3 });
311
312    // Ensure anchoring to a point is equivalent to anchoring to an offset.
313    assert_eq!(
314        buffer.anchor_before(Point { row: 0, column: 0 }),
315        buffer.anchor_before(0)
316    );
317    assert_eq!(
318        buffer.anchor_before(Point { row: 0, column: 1 }),
319        buffer.anchor_before(1)
320    );
321    assert_eq!(
322        buffer.anchor_before(Point { row: 0, column: 2 }),
323        buffer.anchor_before(2)
324    );
325    assert_eq!(
326        buffer.anchor_before(Point { row: 0, column: 3 }),
327        buffer.anchor_before(3)
328    );
329    assert_eq!(
330        buffer.anchor_before(Point { row: 1, column: 0 }),
331        buffer.anchor_before(4)
332    );
333    assert_eq!(
334        buffer.anchor_before(Point { row: 1, column: 1 }),
335        buffer.anchor_before(5)
336    );
337    assert_eq!(
338        buffer.anchor_before(Point { row: 1, column: 2 }),
339        buffer.anchor_before(6)
340    );
341    assert_eq!(
342        buffer.anchor_before(Point { row: 1, column: 3 }),
343        buffer.anchor_before(7)
344    );
345    assert_eq!(
346        buffer.anchor_before(Point { row: 1, column: 4 }),
347        buffer.anchor_before(8)
348    );
349
350    // Comparison between anchors.
351    let anchor_at_offset_0 = buffer.anchor_before(0);
352    let anchor_at_offset_1 = buffer.anchor_before(1);
353    let anchor_at_offset_2 = buffer.anchor_before(2);
354
355    assert_eq!(
356        anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer),
357        Ordering::Equal
358    );
359    assert_eq!(
360        anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer),
361        Ordering::Equal
362    );
363    assert_eq!(
364        anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer),
365        Ordering::Equal
366    );
367
368    assert_eq!(
369        anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer),
370        Ordering::Less
371    );
372    assert_eq!(
373        anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer),
374        Ordering::Less
375    );
376    assert_eq!(
377        anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer),
378        Ordering::Less
379    );
380
381    assert_eq!(
382        anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer),
383        Ordering::Greater
384    );
385    assert_eq!(
386        anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer),
387        Ordering::Greater
388    );
389    assert_eq!(
390        anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer),
391        Ordering::Greater
392    );
393}
394
395#[test]
396fn test_anchors_at_start_and_end() {
397    let mut buffer = Buffer::new(0, 0, History::new("".into()));
398    let before_start_anchor = buffer.anchor_before(0);
399    let after_end_anchor = buffer.anchor_after(0);
400
401    buffer.edit(vec![0..0], "abc");
402    assert_eq!(buffer.text(), "abc");
403    assert_eq!(before_start_anchor.to_offset(&buffer), 0);
404    assert_eq!(after_end_anchor.to_offset(&buffer), 3);
405
406    let after_start_anchor = buffer.anchor_after(0);
407    let before_end_anchor = buffer.anchor_before(3);
408
409    buffer.edit(vec![3..3], "def");
410    buffer.edit(vec![0..0], "ghi");
411    assert_eq!(buffer.text(), "ghiabcdef");
412    assert_eq!(before_start_anchor.to_offset(&buffer), 0);
413    assert_eq!(after_start_anchor.to_offset(&buffer), 3);
414    assert_eq!(before_end_anchor.to_offset(&buffer), 6);
415    assert_eq!(after_end_anchor.to_offset(&buffer), 9);
416}
417
418#[test]
419fn test_undo_redo() {
420    let mut buffer = Buffer::new(0, 0, History::new("1234".into()));
421    // Set group interval to zero so as to not group edits in the undo stack.
422    buffer.history.group_interval = Duration::from_secs(0);
423
424    buffer.edit(vec![1..1], "abx");
425    buffer.edit(vec![3..4], "yzef");
426    buffer.edit(vec![3..5], "cd");
427    assert_eq!(buffer.text(), "1abcdef234");
428
429    let entries = buffer.history.undo_stack.clone();
430    assert_eq!(entries.len(), 3);
431
432    buffer.undo_or_redo(entries[0].transaction.clone()).unwrap();
433    assert_eq!(buffer.text(), "1cdef234");
434    buffer.undo_or_redo(entries[0].transaction.clone()).unwrap();
435    assert_eq!(buffer.text(), "1abcdef234");
436
437    buffer.undo_or_redo(entries[1].transaction.clone()).unwrap();
438    assert_eq!(buffer.text(), "1abcdx234");
439    buffer.undo_or_redo(entries[2].transaction.clone()).unwrap();
440    assert_eq!(buffer.text(), "1abx234");
441    buffer.undo_or_redo(entries[1].transaction.clone()).unwrap();
442    assert_eq!(buffer.text(), "1abyzef234");
443    buffer.undo_or_redo(entries[2].transaction.clone()).unwrap();
444    assert_eq!(buffer.text(), "1abcdef234");
445
446    buffer.undo_or_redo(entries[2].transaction.clone()).unwrap();
447    assert_eq!(buffer.text(), "1abyzef234");
448    buffer.undo_or_redo(entries[0].transaction.clone()).unwrap();
449    assert_eq!(buffer.text(), "1yzef234");
450    buffer.undo_or_redo(entries[1].transaction.clone()).unwrap();
451    assert_eq!(buffer.text(), "1234");
452}
453
454#[test]
455fn test_history() {
456    let mut now = Instant::now();
457    let mut buffer = Buffer::new(0, 0, History::new("123456".into()));
458
459    buffer.start_transaction_at(now);
460    buffer.edit(vec![2..4], "cd");
461    buffer.end_transaction_at(now);
462    assert_eq!(buffer.text(), "12cd56");
463
464    buffer.start_transaction_at(now);
465    buffer.edit(vec![4..5], "e");
466    buffer.end_transaction_at(now).unwrap();
467    assert_eq!(buffer.text(), "12cde6");
468
469    now += buffer.history.group_interval + Duration::from_millis(1);
470    buffer.start_transaction_at(now);
471    buffer.edit(vec![0..1], "a");
472    buffer.edit(vec![1..1], "b");
473    buffer.end_transaction_at(now).unwrap();
474    assert_eq!(buffer.text(), "ab2cde6");
475
476    // Last transaction happened past the group interval, undo it on its own.
477    buffer.undo();
478    assert_eq!(buffer.text(), "12cde6");
479
480    // First two transactions happened within the group interval, undo them together.
481    buffer.undo();
482    assert_eq!(buffer.text(), "123456");
483
484    // Redo the first two transactions together.
485    buffer.redo();
486    assert_eq!(buffer.text(), "12cde6");
487
488    // Redo the last transaction on its own.
489    buffer.redo();
490    assert_eq!(buffer.text(), "ab2cde6");
491
492    buffer.start_transaction_at(now);
493    assert!(buffer.end_transaction_at(now).is_none());
494    buffer.undo();
495    assert_eq!(buffer.text(), "12cde6");
496}
497
498#[test]
499fn test_finalize_last_transaction() {
500    let now = Instant::now();
501    let mut buffer = Buffer::new(0, 0, History::new("123456".into()));
502
503    buffer.start_transaction_at(now);
504    buffer.edit(vec![2..4], "cd");
505    buffer.end_transaction_at(now);
506    assert_eq!(buffer.text(), "12cd56");
507
508    buffer.finalize_last_transaction();
509    buffer.start_transaction_at(now);
510    buffer.edit(vec![4..5], "e");
511    buffer.end_transaction_at(now).unwrap();
512    assert_eq!(buffer.text(), "12cde6");
513
514    buffer.start_transaction_at(now);
515    buffer.edit(vec![0..1], "a");
516    buffer.edit(vec![1..1], "b");
517    buffer.end_transaction_at(now).unwrap();
518    assert_eq!(buffer.text(), "ab2cde6");
519
520    buffer.undo();
521    assert_eq!(buffer.text(), "12cd56");
522
523    buffer.undo();
524    assert_eq!(buffer.text(), "123456");
525
526    buffer.redo();
527    assert_eq!(buffer.text(), "12cd56");
528
529    buffer.redo();
530    assert_eq!(buffer.text(), "ab2cde6");
531}
532
533#[test]
534fn test_edited_ranges_for_transaction() {
535    let now = Instant::now();
536    let mut buffer = Buffer::new(0, 0, History::new("1234567".into()));
537
538    buffer.start_transaction_at(now);
539    buffer.edit(vec![2..4], "cd");
540    buffer.edit(vec![6..6], "efg");
541    buffer.end_transaction_at(now);
542    assert_eq!(buffer.text(), "12cd56efg7");
543
544    let tx = buffer.finalize_last_transaction().unwrap().clone();
545    assert_eq!(
546        buffer
547            .edited_ranges_for_transaction::<usize>(&tx)
548            .collect::<Vec<_>>(),
549        [2..4, 6..9]
550    );
551
552    buffer.edit(vec![5..5], "hijk");
553    assert_eq!(buffer.text(), "12cd5hijk6efg7");
554    assert_eq!(
555        buffer
556            .edited_ranges_for_transaction::<usize>(&tx)
557            .collect::<Vec<_>>(),
558        [2..4, 10..13]
559    );
560
561    buffer.edit(vec![4..4], "l");
562    assert_eq!(buffer.text(), "12cdl5hijk6efg7");
563    assert_eq!(
564        buffer
565            .edited_ranges_for_transaction::<usize>(&tx)
566            .collect::<Vec<_>>(),
567        [2..4, 11..14]
568    );
569}
570
571#[test]
572fn test_concurrent_edits() {
573    let text = "abcdef";
574
575    let mut buffer1 = Buffer::new(1, 0, History::new(text.into()));
576    let mut buffer2 = Buffer::new(2, 0, History::new(text.into()));
577    let mut buffer3 = Buffer::new(3, 0, History::new(text.into()));
578
579    let buf1_op = buffer1.edit(vec![1..2], "12");
580    assert_eq!(buffer1.text(), "a12cdef");
581    let buf2_op = buffer2.edit(vec![3..4], "34");
582    assert_eq!(buffer2.text(), "abc34ef");
583    let buf3_op = buffer3.edit(vec![5..6], "56");
584    assert_eq!(buffer3.text(), "abcde56");
585
586    buffer1.apply_op(buf2_op.clone()).unwrap();
587    buffer1.apply_op(buf3_op.clone()).unwrap();
588    buffer2.apply_op(buf1_op.clone()).unwrap();
589    buffer2.apply_op(buf3_op.clone()).unwrap();
590    buffer3.apply_op(buf1_op.clone()).unwrap();
591    buffer3.apply_op(buf2_op.clone()).unwrap();
592
593    assert_eq!(buffer1.text(), "a12c34e56");
594    assert_eq!(buffer2.text(), "a12c34e56");
595    assert_eq!(buffer3.text(), "a12c34e56");
596}
597
598#[gpui::test(iterations = 100)]
599fn test_random_concurrent_edits(mut rng: StdRng) {
600    let peers = env::var("PEERS")
601        .map(|i| i.parse().expect("invalid `PEERS` variable"))
602        .unwrap_or(5);
603    let operations = env::var("OPERATIONS")
604        .map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
605        .unwrap_or(10);
606
607    let base_text_len = rng.gen_range(0..10);
608    let base_text = RandomCharIter::new(&mut rng)
609        .take(base_text_len)
610        .collect::<String>();
611    let mut replica_ids = Vec::new();
612    let mut buffers = Vec::new();
613    let mut network = Network::new(rng.clone());
614
615    for i in 0..peers {
616        let mut buffer = Buffer::new(i as ReplicaId, 0, History::new(base_text.clone().into()));
617        buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200));
618        buffers.push(buffer);
619        replica_ids.push(i as u16);
620        network.add_peer(i as u16);
621    }
622
623    log::info!("initial text: {:?}", base_text);
624
625    let mut mutation_count = operations;
626    loop {
627        let replica_index = rng.gen_range(0..peers);
628        let replica_id = replica_ids[replica_index];
629        let buffer = &mut buffers[replica_index];
630        match rng.gen_range(0..=100) {
631            0..=50 if mutation_count != 0 => {
632                let op = buffer.randomly_edit(&mut rng, 5).2;
633                network.broadcast(buffer.replica_id, vec![op]);
634                log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text());
635                mutation_count -= 1;
636            }
637            51..=70 if mutation_count != 0 => {
638                let ops = buffer.randomly_undo_redo(&mut rng);
639                network.broadcast(buffer.replica_id, ops);
640                mutation_count -= 1;
641            }
642            71..=100 if network.has_unreceived(replica_id) => {
643                let ops = network.receive(replica_id);
644                if !ops.is_empty() {
645                    log::info!(
646                        "peer {} applying {} ops from the network.",
647                        replica_id,
648                        ops.len()
649                    );
650                    buffer.apply_ops(ops).unwrap();
651                }
652            }
653            _ => {}
654        }
655        buffer.check_invariants();
656
657        if mutation_count == 0 && network.is_idle() {
658            break;
659        }
660    }
661
662    let first_buffer = &buffers[0];
663    for buffer in &buffers[1..] {
664        assert_eq!(
665            buffer.text(),
666            first_buffer.text(),
667            "Replica {} text != Replica 0 text",
668            buffer.replica_id
669        );
670        buffer.check_invariants();
671    }
672}