Detailed changes
@@ -2414,27 +2414,18 @@ impl Buffer {
#[cfg(any(test, feature = "test-support"))]
impl Buffer {
- pub fn randomly_edit<T>(
- &mut self,
- rng: &mut T,
- old_range_count: usize,
- _: &mut ModelContext<Self>,
- ) -> (Vec<Range<usize>>, String)
+ pub fn randomly_edit<T>(&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<T>(
- &mut self,
- rng: &mut T,
- _: &mut ModelContext<Self>,
- ) -> (Vec<Range<usize>>, String)
+ pub fn randomly_mutate<T>(&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<Range<usize>>, String)
+ ) -> (Vec<Range<usize>>, 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<T>(&mut self, rng: &mut T) -> (Vec<Range<usize>>, String)
+ pub fn randomly_mutate<T>(&mut self, rng: &mut T) -> Vec<Operation>
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::<Vec<_>>();
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<Operation> {
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<I>(&self, ranges: I) -> Result<Vec<Selection>>
@@ -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);
-
-// let base_text_len = rng.gen_range(0..10);
-// let base_text = RandomCharIter::new(&mut rng)
-// .take(base_text_len)
-// .collect::<String>();
-// 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);
-// }
-
-// 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();
-// }
-// }
-// _ => {}
-// });
-
-// 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::<HashMap<_, _>>(),
-// first_buffer.selection_sets().collect::<HashMap<_, _>>()
-// );
-// assert_eq!(
-// buffer.all_selection_ranges().collect::<HashMap<_, _>>(),
-// first_buffer
-// .all_selection_ranges()
-// .collect::<HashMap<_, _>>()
-// );
-// }
-// }
+#[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::<String>();
+ let mut replica_ids = Vec::new();
+ let mut buffers = Vec::new();
+ let mut network = Network::new(rng.clone());
+
+ 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);
+
+ 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;
+ }
+ }
+
+ 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::<HashMap<_, _>>(),
+ first_buffer.selection_sets().collect::<HashMap<_, _>>()
+ );
+ assert_eq!(
+ buffer.all_selection_ranges().collect::<HashMap<_, _>>(),
+ first_buffer
+ .all_selection_ranges()
+ .collect::<HashMap<_, _>>()
+ );
+ }
+}
#[derive(Clone)]
struct Envelope<T: Clone> {
@@ -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));
}
}
@@ -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::<Vec<_>>()
});
log::info!("editing {:?}", edits);
@@ -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));
}
}