Check projects' buffers have unique absolute paths in random collab test

Max Brunsfeld created

Change summary

crates/project/src/project.rs | 78 +++++++++++++++++++++++++++---------
crates/server/src/rpc.rs      | 32 ++++++++------
2 files changed, 77 insertions(+), 33 deletions(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -413,6 +413,65 @@ impl Project {
         &self.languages
     }
 
+    #[cfg(any(test, feature = "test-support"))]
+    pub fn check_invariants(&self, cx: &AppContext) {
+        if self.is_local() {
+            let buffers = self.buffers(cx);
+            for (i, buffer) in buffers.iter().enumerate() {
+                let buffer = buffer.read(cx);
+                let path = buffer.file().unwrap().as_local().unwrap().abs_path(cx);
+                for other_buffer in &buffers[0..i] {
+                    let other_buffer = other_buffer.read(cx);
+                    let other_path = other_buffer
+                        .file()
+                        .unwrap()
+                        .as_local()
+                        .unwrap()
+                        .abs_path(cx);
+                    if other_path == path {
+                        panic!(
+                            "buffers {} and {} have the same absolute path: {:?}",
+                            buffer.remote_id(),
+                            other_buffer.remote_id(),
+                            path,
+                        );
+                    }
+                }
+            }
+        }
+    }
+
+    #[cfg(any(test, feature = "test-support"))]
+    pub fn buffers(&self, cx: &AppContext) -> Vec<ModelHandle<Buffer>> {
+        self.opened_buffers
+            .values()
+            .filter_map(|buffer| match buffer {
+                OpenBuffer::Strong(buffer) => Some(buffer.clone()),
+                OpenBuffer::Weak(buffer) => buffer.upgrade(cx),
+                OpenBuffer::Loading(_) => None,
+            })
+            .collect()
+    }
+
+    #[cfg(any(test, feature = "test-support"))]
+    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
+        let path = path.into();
+        if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
+            self.opened_buffers.iter().any(|(_, buffer)| {
+                if let Some(buffer) = buffer.upgrade(cx) {
+                    if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
+                        if file.worktree == worktree && file.path() == &path.path {
+                            return true;
+                        }
+                    }
+                }
+                false
+            })
+        } else {
+            false
+        }
+    }
+
     pub fn fs(&self) -> &Arc<dyn Fs> {
         &self.fs
     }
@@ -811,25 +870,6 @@ impl Project {
         })
     }
 
-    #[cfg(any(test, feature = "test-support"))]
-    pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
-        let path = path.into();
-        if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
-            self.opened_buffers.iter().any(|(_, buffer)| {
-                if let Some(buffer) = buffer.upgrade(cx) {
-                    if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
-                        if file.worktree == worktree && file.path() == &path.path {
-                            return true;
-                        }
-                    }
-                }
-                false
-            })
-        } else {
-            false
-        }
-    }
-
     pub fn get_open_buffer(
         &mut self,
         path: &ProjectPath,

crates/server/src/rpc.rs 🔗

@@ -4246,6 +4246,12 @@ mod tests {
                 .collect::<BTreeMap<_, _>>()
         });
 
+        host_client
+            .project
+            .as_ref()
+            .unwrap()
+            .read_with(&host_cx, |project, cx| project.check_invariants(cx));
+
         for (guest_client, mut guest_cx) in clients.into_iter() {
             let guest_id = guest_client.client.id();
             let worktree_snapshots =
@@ -4287,18 +4293,6 @@ mod tests {
                 );
             }
 
-            guest_client
-                .project
-                .as_ref()
-                .unwrap()
-                .read_with(&guest_cx, |project, cx| {
-                    assert!(
-                        !project.has_deferred_operations(cx),
-                        "guest {} has deferred operations",
-                        guest_id,
-                    );
-                });
-
             for guest_buffer in &guest_client.buffers {
                 let buffer_id = guest_buffer.read_with(&guest_cx, |buffer, _| buffer.remote_id());
                 let host_buffer = host_project.read_with(&host_cx, |project, cx| {
@@ -4307,14 +4301,24 @@ mod tests {
                         guest_id, guest_client.peer_id, buffer_id
                     ))
                 });
+                let path = host_buffer
+                    .read_with(&host_cx, |buffer, cx| buffer.file().unwrap().full_path(cx));
+
+                assert_eq!(
+                    guest_buffer.read_with(&guest_cx, |buffer, _| buffer.deferred_ops_len()),
+                    0,
+                    "guest {}, buffer {}, path {:?} has deferred operations",
+                    guest_id,
+                    buffer_id,
+                    path,
+                );
                 assert_eq!(
                     guest_buffer.read_with(&guest_cx, |buffer, _| buffer.text()),
                     host_buffer.read_with(&host_cx, |buffer, _| buffer.text()),
                     "guest {}, buffer {}, path {:?}, differs from the host's buffer",
                     guest_id,
                     buffer_id,
-                    host_buffer
-                        .read_with(&host_cx, |buffer, cx| buffer.file().unwrap().full_path(cx))
+                    path
                 );
             }