diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index ad3a319421..c8d9c80d5e 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -2414,27 +2414,18 @@ impl Buffer { #[cfg(any(test, feature = "test-support"))] impl Buffer { - pub fn randomly_edit( - &mut self, - rng: &mut T, - old_range_count: usize, - _: &mut ModelContext, - ) -> (Vec>, String) + pub fn randomly_edit(&mut self, rng: &mut T, old_range_count: usize) where T: rand::Rng, { - self.buffer.randomly_edit(rng, old_range_count) + self.buffer.randomly_edit(rng, old_range_count); } - pub fn randomly_mutate( - &mut self, - rng: &mut T, - _: &mut ModelContext, - ) -> (Vec>, String) + pub fn randomly_mutate(&mut self, rng: &mut T) where T: rand::Rng, { - self.buffer.randomly_mutate(rng) + self.buffer.randomly_mutate(rng); } } @@ -2450,7 +2441,7 @@ impl TextBuffer { &mut self, rng: &mut T, old_range_count: usize, - ) -> (Vec>, String) + ) -> (Vec>, String, Operation) where T: rand::Rng, { @@ -2472,17 +2463,17 @@ impl TextBuffer { old_ranges, new_text ); - self.edit(old_ranges.iter().cloned(), new_text.as_str()); - (old_ranges, new_text) + let op = self.edit(old_ranges.iter().cloned(), new_text.as_str()); + (old_ranges, new_text, Operation::Edit(op)) } - pub fn randomly_mutate(&mut self, rng: &mut T) -> (Vec>, String) + pub fn randomly_mutate(&mut self, rng: &mut T) -> Vec where T: rand::Rng, { use rand::prelude::*; - let (old_ranges, new_text) = self.randomly_edit(rng, 5); + let mut ops = vec![self.randomly_edit(rng, 5).2]; // Randomly add, remove or mutate selection sets. let replica_selection_sets = &self @@ -2492,7 +2483,7 @@ impl TextBuffer { .collect::>(); let set_id = replica_selection_sets.choose(rng); if set_id.is_some() && rng.gen_bool(1.0 / 6.0) { - self.remove_selection_set(*set_id.unwrap()).unwrap(); + ops.push(self.remove_selection_set(*set_id.unwrap()).unwrap()); } else { let mut ranges = Vec::new(); for _ in 0..5 { @@ -2500,20 +2491,22 @@ impl TextBuffer { } let new_selections = self.selections_from_ranges(ranges).unwrap(); - if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { - self.add_selection_set(new_selections); + let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { + self.add_selection_set(new_selections) } else { self.update_selection_set(*set_id.unwrap(), new_selections) - .unwrap(); - } + .unwrap() + }; + ops.push(op); } - (old_ranges, new_text) + ops } - pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng) { + pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng) -> Vec { use rand::prelude::*; + let mut ops = Vec::new(); for _ in 0..rng.gen_range(1..=5) { if let Some(transaction) = self.history.undo_stack.choose(rng).cloned() { log::info!( @@ -2521,9 +2514,10 @@ impl TextBuffer { self.replica_id, transaction ); - self.undo_or_redo(transaction).unwrap(); + ops.push(self.undo_or_redo(transaction).unwrap()); } } + ops } fn selections_from_ranges(&self, ranges: I) -> Result> diff --git a/crates/buffer/src/tests/buffer.rs b/crates/buffer/src/tests/buffer.rs index 74c27e99de..f0c9051daa 100644 --- a/crates/buffer/src/tests/buffer.rs +++ b/crates/buffer/src/tests/buffer.rs @@ -6,7 +6,6 @@ use std::{ cmp::Ordering, env, iter::Iterator, - mem, rc::Rc, time::{Duration, Instant}, }; @@ -104,7 +103,7 @@ fn test_random_edits(mut rng: StdRng) { ); for _i in 0..operations { - let (old_ranges, new_text) = buffer.randomly_mutate(&mut rng); + let (old_ranges, new_text, _) = buffer.randomly_edit(&mut rng, 5); for old_range in old_ranges.iter().rev() { reference_string.replace_range(old_range.clone(), &new_text); } @@ -571,92 +570,89 @@ fn test_concurrent_edits() { assert_eq!(buffer3.text(), "a12c34e56"); } -// #[gpui::test(iterations = 100)] -// fn test_random_concurrent_edits(cx: &mut gpui::MutableAppContext, mut rng: StdRng) { -// let peers = env::var("PEERS") -// .map(|i| i.parse().expect("invalid `PEERS` variable")) -// .unwrap_or(5); -// let operations = env::var("OPERATIONS") -// .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) -// .unwrap_or(10); +#[gpui::test(iterations = 100)] +fn test_random_concurrent_edits(mut rng: StdRng) { + let peers = env::var("PEERS") + .map(|i| i.parse().expect("invalid `PEERS` variable")) + .unwrap_or(5); + let operations = env::var("OPERATIONS") + .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + .unwrap_or(10); -// let base_text_len = rng.gen_range(0..10); -// let base_text = RandomCharIter::new(&mut rng) -// .take(base_text_len) -// .collect::(); -// let mut replica_ids = Vec::new(); -// let mut buffers = Vec::new(); -// let mut network = Network::new(rng.clone()); + let base_text_len = rng.gen_range(0..10); + let base_text = RandomCharIter::new(&mut rng) + .take(base_text_len) + .collect::(); + let mut replica_ids = Vec::new(); + let mut buffers = Vec::new(); + let mut network = Network::new(rng.clone()); -// for i in 0..peers { -// let buffer = cx.add_model(|cx| { -// let mut buf = Buffer::new(i as ReplicaId, base_text.as_str(), cx); -// buf.history.group_interval = Duration::from_millis(rng.gen_range(0..=200)); -// buf -// }); -// buffers.push(buffer); -// replica_ids.push(i as u16); -// network.add_peer(i as u16); -// } + for i in 0..peers { + let mut buffer = TextBuffer::new(i as ReplicaId, 0, History::new(base_text.clone().into())); + buffer.history.group_interval = Duration::from_millis(rng.gen_range(0..=200)); + buffers.push(buffer); + replica_ids.push(i as u16); + network.add_peer(i as u16); + } -// log::info!("initial text: {:?}", base_text); + log::info!("initial text: {:?}", base_text); -// let mut mutation_count = operations; -// loop { -// let replica_index = rng.gen_range(0..peers); -// let replica_id = replica_ids[replica_index]; -// buffers[replica_index].update(cx, |buffer, cx| match rng.gen_range(0..=100) { -// 0..=50 if mutation_count != 0 => { -// buffer.randomly_mutate(&mut rng, cx); -// network.broadcast(buffer.replica_id, mem::take(&mut buffer.operations)); -// log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text()); -// mutation_count -= 1; -// } -// 51..=70 if mutation_count != 0 => { -// buffer.randomly_undo_redo(&mut rng, cx); -// network.broadcast(buffer.replica_id, mem::take(&mut buffer.operations)); -// mutation_count -= 1; -// } -// 71..=100 if network.has_unreceived(replica_id) => { -// let ops = network.receive(replica_id); -// if !ops.is_empty() { -// log::info!( -// "peer {} applying {} ops from the network.", -// replica_id, -// ops.len() -// ); -// buffer.apply_ops(ops, cx).unwrap(); -// } -// } -// _ => {} -// }); + let mut mutation_count = operations; + loop { + let replica_index = rng.gen_range(0..peers); + let replica_id = replica_ids[replica_index]; + let buffer = &mut buffers[replica_index]; + match rng.gen_range(0..=100) { + 0..=50 if mutation_count != 0 => { + let ops = buffer.randomly_mutate(&mut rng); + network.broadcast(buffer.replica_id, ops); + log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text()); + mutation_count -= 1; + } + 51..=70 if mutation_count != 0 => { + let ops = buffer.randomly_undo_redo(&mut rng); + network.broadcast(buffer.replica_id, ops); + mutation_count -= 1; + } + 71..=100 if network.has_unreceived(replica_id) => { + let ops = network.receive(replica_id); + if !ops.is_empty() { + log::info!( + "peer {} applying {} ops from the network.", + replica_id, + ops.len() + ); + buffer.apply_ops(ops).unwrap(); + } + } + _ => {} + } -// if mutation_count == 0 && network.is_idle() { -// break; -// } -// } + if mutation_count == 0 && network.is_idle() { + break; + } + } -// let first_buffer = buffers[0].read(cx); -// for buffer in &buffers[1..] { -// let buffer = buffer.read(cx); -// assert_eq!( -// buffer.text(), -// first_buffer.text(), -// "Replica {} text != Replica 0 text", -// buffer.replica_id -// ); -// assert_eq!( -// buffer.selection_sets().collect::>(), -// first_buffer.selection_sets().collect::>() -// ); -// assert_eq!( -// buffer.all_selection_ranges().collect::>(), -// first_buffer -// .all_selection_ranges() -// .collect::>() -// ); -// } -// } + let first_buffer = &buffers[0]; + for buffer in &buffers[1..] { + assert_eq!( + buffer.text(), + first_buffer.text(), + "Replica {} text != Replica 0 text", + buffer.replica_id + ); + assert_eq!( + buffer.selection_sets().collect::>(), + first_buffer.selection_sets().collect::>() + ); + assert_eq!( + buffer.all_selection_ranges().collect::>(), + first_buffer + .all_selection_ranges() + .collect::>() + ); + } +} #[derive(Clone)] struct Envelope { diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 209d639407..dd348b6e46 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -436,7 +436,7 @@ mod tests { } } _ => { - buffer.update(&mut cx, |buffer, cx| buffer.randomly_edit(&mut rng, 5, cx)); + buffer.update(&mut cx, |buffer, cx| buffer.randomly_edit(&mut rng, 5)); } } diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 3dc671e59d..0a1e01e0c0 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -1,4 +1,4 @@ -use buffer::{Anchor, Buffer, Point, ToOffset, AnchorRangeExt, HighlightId, TextSummary}; +use buffer::{Anchor, AnchorRangeExt, Buffer, HighlightId, Point, TextSummary, ToOffset}; use gpui::{AppContext, ModelHandle}; use parking_lot::Mutex; use std::{ @@ -1334,7 +1334,7 @@ mod tests { let edits = buffer.update(cx, |buffer, cx| { let start_version = buffer.version.clone(); let edit_count = rng.gen_range(1..=5); - buffer.randomly_edit(&mut rng, edit_count, cx); + buffer.randomly_edit(&mut rng, edit_count); buffer.edits_since(start_version).collect::>() }); log::info!("editing {:?}", edits); diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index fa26685a65..884657f502 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -990,7 +990,7 @@ mod tests { } } _ => { - buffer.update(&mut cx, |buffer, cx| buffer.randomly_mutate(&mut rng, cx)); + buffer.update(&mut cx, |buffer, cx| buffer.randomly_mutate(&mut rng)); } }