Verify that selections are replicated correctly in randomized test

Antonio Scandurra created

Change summary

crates/language/src/tests.rs | 44 ++++++++++++++++++++++++++++++++++++-
crates/text/src/text.rs      |  6 ----
2 files changed, 43 insertions(+), 7 deletions(-)

Detailed changes

crates/language/src/tests.rs 🔗

@@ -1,5 +1,6 @@
 use super::*;
 use clock::ReplicaId;
+use collections::BTreeMap;
 use gpui::{ModelHandle, MutableAppContext};
 use rand::prelude::*;
 use std::{
@@ -848,13 +849,14 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
 
     let mut now = Instant::now();
     let mut mutation_count = operations;
+    let mut active_selections = BTreeMap::default();
     loop {
         let replica_index = rng.gen_range(0..replica_ids.len());
         let replica_id = replica_ids[replica_index];
         let buffer = &mut buffers[replica_index];
         let mut new_buffer = None;
         match rng.gen_range(0..100) {
-            0..=34 if mutation_count != 0 => {
+            0..=29 if mutation_count != 0 => {
                 buffer.update(cx, |buffer, cx| {
                     buffer.start_transaction_at(now);
                     buffer.randomly_edit(&mut rng, 5, cx);
@@ -863,7 +865,31 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
                 });
                 mutation_count -= 1;
             }
-            35..=49 if replica_ids.len() < max_peers => {
+            30..=39 if mutation_count != 0 => {
+                buffer.update(cx, |buffer, cx| {
+                    let mut selections = Vec::new();
+                    for id in 0..rng.gen_range(1..=5) {
+                        let range = buffer.random_byte_range(0, &mut rng);
+                        selections.push(Selection {
+                            id,
+                            start: buffer.anchor_before(range.start),
+                            end: buffer.anchor_before(range.end),
+                            reversed: false,
+                            goal: SelectionGoal::None,
+                        });
+                    }
+                    let selections: Arc<[Selection<Anchor>]> = selections.into();
+                    log::info!(
+                        "peer {} setting active selections: {:?}",
+                        replica_id,
+                        selections
+                    );
+                    active_selections.insert(replica_id, selections.clone());
+                    buffer.set_active_selections(selections, cx);
+                });
+                mutation_count -= 1;
+            }
+            40..=49 if replica_ids.len() < max_peers => {
                 let old_buffer = buffer.read(cx).to_proto();
                 let new_replica_id = replica_ids.len() as ReplicaId;
                 log::info!(
@@ -930,6 +956,20 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) {
             buffer.replica_id()
         );
     }
+
+    for buffer in &buffers {
+        let buffer = buffer.read(cx).snapshot();
+        let expected_remote_selections = active_selections
+            .iter()
+            .filter(|(replica_id, _)| **replica_id != buffer.replica_id())
+            .map(|(replica_id, selections)| (*replica_id, selections.iter().collect::<Vec<_>>()))
+            .collect::<Vec<_>>();
+        let actual_remote_selections = buffer
+            .remote_selections_in_range(Anchor::min()..Anchor::max())
+            .map(|(replica_id, selections)| (replica_id, selections.collect::<Vec<_>>()))
+            .collect::<Vec<_>>();
+        assert_eq!(actual_remote_selections, expected_remote_selections);
+    }
 }
 
 fn chunks_with_diagnostics<T: ToOffset + ToPoint>(

crates/text/src/text.rs 🔗

@@ -1248,11 +1248,7 @@ impl Buffer {
         self.history.group_interval = group_interval;
     }
 
-    pub fn random_byte_range(
-        &mut self,
-        start_offset: usize,
-        rng: &mut impl rand::Rng,
-    ) -> Range<usize> {
+    pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range<usize> {
         let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right);
         let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right);
         start..end