Avoid removing fake fs entry when rename fails later in the process

Julia and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

crates/fs/src/fs.rs            | 21 +++++++++++++++++----
crates/project/src/worktree.rs | 11 +++++++----
2 files changed, 24 insertions(+), 8 deletions(-)

Detailed changes

crates/fs/src/fs.rs 🔗

@@ -572,15 +572,15 @@ impl FakeFs {
         Ok(())
     }
 
-    pub async fn pause_events(&self) {
+    pub fn pause_events(&self) {
         self.state.lock().events_paused = true;
     }
 
-    pub async fn buffered_event_count(&self) -> usize {
+    pub fn buffered_event_count(&self) -> usize {
         self.state.lock().buffered_events.len()
     }
 
-    pub async fn flush_events(&self, count: usize) {
+    pub fn flush_events(&self, count: usize) {
         self.state.lock().flush_events(count);
     }
 
@@ -832,14 +832,16 @@ impl Fs for FakeFs {
 
         let old_path = normalize_path(old_path);
         let new_path = normalize_path(new_path);
+
         let mut state = self.state.lock();
         let moved_entry = state.write_path(&old_path, |e| {
             if let btree_map::Entry::Occupied(e) = e {
-                Ok(e.remove())
+                Ok(e.get().clone())
             } else {
                 Err(anyhow!("path does not exist: {}", &old_path.display()))
             }
         })?;
+
         state.write_path(&new_path, |e| {
             match e {
                 btree_map::Entry::Occupied(mut e) => {
@@ -855,6 +857,17 @@ impl Fs for FakeFs {
             }
             Ok(())
         })?;
+
+        state
+            .write_path(&old_path, |e| {
+                if let btree_map::Entry::Occupied(e) = e {
+                    Ok(e.remove())
+                } else {
+                    unreachable!()
+                }
+            })
+            .unwrap();
+
         state.emit_event(&[old_path, new_path]);
         Ok(())
     }

crates/project/src/worktree.rs 🔗

@@ -4632,6 +4632,7 @@ mod tests {
             .detach();
         });
 
+        fs.as_fake().pause_events();
         let mut snapshots = Vec::new();
         let mut mutations_len = operations;
         while mutations_len > 1 {
@@ -4641,16 +4642,16 @@ mod tests {
                         randomly_mutate_worktree(worktree, &mut rng, cx)
                     })
                     .await
-                    .unwrap();
+                    .log_err();
             } else {
                 randomly_mutate_fs(&fs, root_dir, 1.0, &mut rng).await;
             }
 
-            let buffered_event_count = fs.as_fake().buffered_event_count().await;
+            let buffered_event_count = fs.as_fake().buffered_event_count();
             if buffered_event_count > 0 && rng.gen_bool(0.3) {
                 let len = rng.gen_range(0..=buffered_event_count);
                 log::info!("flushing {} events", len);
-                fs.as_fake().flush_events(len).await;
+                fs.as_fake().flush_events(len);
             } else {
                 randomly_mutate_fs(&fs, root_dir, 0.6, &mut rng).await;
                 mutations_len -= 1;
@@ -4666,7 +4667,7 @@ mod tests {
         }
 
         log::info!("quiescing");
-        fs.as_fake().flush_events(usize::MAX).await;
+        fs.as_fake().flush_events(usize::MAX);
         cx.foreground().run_until_parked();
         let snapshot = worktree.read_with(cx, |tree, _| tree.as_local().unwrap().snapshot());
         snapshot.check_invariants();
@@ -4726,6 +4727,7 @@ mod tests {
         rng: &mut impl Rng,
         cx: &mut ModelContext<Worktree>,
     ) -> Task<Result<()>> {
+        log::info!("mutating worktree");
         let worktree = worktree.as_local_mut().unwrap();
         let snapshot = worktree.snapshot();
         let entry = snapshot.entries(false).choose(rng).unwrap();
@@ -4787,6 +4789,7 @@ mod tests {
         insertion_probability: f64,
         rng: &mut impl Rng,
     ) {
+        log::info!("mutating fs");
         let mut files = Vec::new();
         let mut dirs = Vec::new();
         for path in fs.as_fake().paths() {