diff --git a/zed/src/test.rs b/zed/src/test.rs index 7e2d80efe0..da965b257b 100644 --- a/zed/src/test.rs +++ b/zed/src/test.rs @@ -2,6 +2,7 @@ use rand::Rng; use std::{ collections::BTreeMap, path::{Path, PathBuf}, + time::{Duration, Instant}, }; use tempdir::TempDir; @@ -136,3 +137,18 @@ fn write_tree(path: &Path, tree: serde_json::Value) { panic!("You must pass a JSON object to this helper") } } + +pub async fn assert_condition(poll_interval: u64, timeout: u64, mut f: impl FnMut() -> bool) { + let poll_interval = Duration::from_millis(poll_interval); + let timeout = Duration::from_millis(timeout); + let start = Instant::now(); + loop { + if f() { + return; + } else if Instant::now().duration_since(start) < timeout { + smol::Timer::after(poll_interval).await; + } else { + panic!("timed out waiting on condition"); + } + } +} diff --git a/zed/src/worktree/worktree.rs b/zed/src/worktree/worktree.rs index b789a9d139..e7f1714427 100644 --- a/zed/src/worktree/worktree.rs +++ b/zed/src/worktree/worktree.rs @@ -279,6 +279,28 @@ impl Worktree { Ok(path.join(self.entry_path(entry_id)?)) } + #[cfg(test)] + fn entry_for_path(&self, path: impl AsRef) -> Option { + let path = path.as_ref(); + let state = self.0.read(); + state.root_ino.and_then(|mut ino| { + 'components: for component in path { + if let Entry::Dir { children, .. } = &state.entries[&ino] { + for child in children { + if state.entries[child].name() == component { + ino = *child; + continue 'components; + } + } + return None; + } else { + return None; + } + } + Some(ino) + }) + } + fn fmt_entry(&self, f: &mut fmt::Formatter<'_>, entry_id: u64, indent: usize) -> fmt::Result { match &self.0.read().entries[&entry_id] { Entry::Dir { name, children, .. } => { @@ -740,4 +762,40 @@ mod test { assert_eq!(history.base_text.as_ref(), buffer.text()); }); } + + #[test] + fn test_rescan() { + App::test_async((), |mut app| async move { + let dir = temp_tree(json!({ + "dir1": { + "file": "contents" + }, + "dir2": { + } + })); + + let tree = app.add_model(|ctx| Worktree::new(1, dir.path(), ctx)); + app.finish_pending_tasks().await; + + let file_entry = app.read(|ctx| tree.read(ctx).entry_for_path("dir1/file").unwrap()); + + app.read(|ctx| { + let tree = tree.read(ctx); + assert_eq!( + tree.abs_entry_path(file_entry).unwrap(), + tree.path().join("dir1/file") + ); + }); + + std::fs::rename(dir.path().join("dir1/file"), dir.path().join("dir2/file")).unwrap(); + + assert_condition(1, 300, || { + app.read(|ctx| { + let tree = tree.read(ctx); + tree.abs_entry_path(file_entry).unwrap() == tree.path().join("dir2/file") + }) + }) + .await + }); + } }