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}