Fix tests that were not aware of `Worktree::open_local` being async

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

zed/src/workspace.rs | 128 +++++++++++++++++++++++----------------------
zed/src/worktree.rs  |  52 +++++++++--------
2 files changed, 92 insertions(+), 88 deletions(-)

Detailed changes

zed/src/workspace.rs 🔗

@@ -29,7 +29,10 @@ use std::{
 
 pub fn init(cx: &mut MutableAppContext) {
     cx.add_global_action("workspace:open", open);
-    cx.add_global_action("workspace:open_paths", open_paths);
+    cx.add_global_action(
+        "workspace:open_paths",
+        |params: &OpenParams, cx: &mut MutableAppContext| open_paths(params, cx).detach(),
+    );
     cx.add_global_action("workspace:new_file", open_new);
     cx.add_global_action("workspace:join_worktree", join_worktree);
     cx.add_action("workspace:save", Workspace::save_active_item);
@@ -65,23 +68,23 @@ fn open(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
     );
 }
 
-fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) {
+fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) -> Task<()> {
     log::info!("open paths {:?}", params.paths);
 
     // Open paths in existing workspace if possible
     for window_id in cx.window_ids().collect::<Vec<_>>() {
         if let Some(handle) = cx.root_view::<Workspace>(window_id) {
-            if handle.update(cx, |view, cx| {
+            let task = handle.update(cx, |view, cx| {
                 if view.contains_paths(&params.paths, cx.as_ref()) {
-                    let open_paths = view.open_paths(&params.paths, cx);
-                    cx.foreground().spawn(open_paths).detach();
                     log::info!("open paths on existing workspace");
-                    true
+                    Some(view.open_paths(&params.paths, cx))
                 } else {
-                    false
+                    None
                 }
-            }) {
-                return;
+            });
+
+            if let Some(task) = task {
+                return task;
             }
         }
     }
@@ -89,12 +92,8 @@ fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) {
     log::info!("open new workspace");
 
     // Add a new workspace if necessary
-    cx.add_window(|cx| {
-        let mut view = Workspace::new(&params.app_state, cx);
-        let open_paths = view.open_paths(&params.paths, cx);
-        cx.foreground().spawn(open_paths).detach();
-        view
-    });
+    let (_, workspace) = cx.add_window(|cx| Workspace::new(&params.app_state, cx));
+    workspace.update(cx, |workspace, cx| workspace.open_paths(&params.paths, cx))
 }
 
 fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
@@ -382,11 +381,7 @@ impl Workspace {
         }
     }
 
-    pub fn open_paths(
-        &mut self,
-        abs_paths: &[PathBuf],
-        cx: &mut ViewContext<Self>,
-    ) -> impl Future<Output = ()> {
+    pub fn open_paths(&mut self, abs_paths: &[PathBuf], cx: &mut ViewContext<Self>) -> Task<()> {
         let entries = abs_paths
             .iter()
             .cloned()
@@ -415,13 +410,14 @@ impl Workspace {
                 })
             })
             .collect::<Vec<Task<Result<()>>>>();
-        async move {
+
+        cx.foreground().spawn(async move {
             for task in tasks {
                 if let Err(error) = task.await {
                     log::error!("error opening paths {}", error);
                 }
             }
-        }
+        })
     }
 
     fn worktree_for_abs_path(
@@ -933,11 +929,8 @@ mod tests {
     use tempdir::TempDir;
 
     #[gpui::test]
-    fn test_open_paths_action(cx: &mut gpui::MutableAppContext) {
-        let app_state = build_app_state(cx.as_ref());
-
-        init(cx);
-
+    async fn test_open_paths_action(mut cx: gpui::TestAppContext) {
+        let app_state = cx.read(build_app_state);
         let dir = temp_tree(json!({
             "a": {
                 "aa": null,
@@ -953,42 +946,51 @@ mod tests {
             },
         }));
 
-        cx.dispatch_global_action(
-            "workspace:open_paths",
-            OpenParams {
-                paths: vec![
-                    dir.path().join("a").to_path_buf(),
-                    dir.path().join("b").to_path_buf(),
-                ],
-                app_state: app_state.clone(),
-            },
-        );
-        assert_eq!(cx.window_ids().count(), 1);
-
-        cx.dispatch_global_action(
-            "workspace:open_paths",
-            OpenParams {
-                paths: vec![dir.path().join("a").to_path_buf()],
-                app_state: app_state.clone(),
-            },
-        );
-        assert_eq!(cx.window_ids().count(), 1);
-        let workspace_view_1 = cx
-            .root_view::<Workspace>(cx.window_ids().next().unwrap())
-            .unwrap();
-        assert_eq!(workspace_view_1.read(cx).worktrees().len(), 2);
-
-        cx.dispatch_global_action(
-            "workspace:open_paths",
-            OpenParams {
-                paths: vec![
-                    dir.path().join("b").to_path_buf(),
-                    dir.path().join("c").to_path_buf(),
-                ],
-                app_state: app_state.clone(),
-            },
-        );
-        assert_eq!(cx.window_ids().count(), 2);
+        cx.update(|cx| {
+            open_paths(
+                &OpenParams {
+                    paths: vec![
+                        dir.path().join("a").to_path_buf(),
+                        dir.path().join("b").to_path_buf(),
+                    ],
+                    app_state: app_state.clone(),
+                },
+                cx,
+            )
+        })
+        .await;
+        assert_eq!(cx.window_ids().len(), 1);
+
+        cx.update(|cx| {
+            open_paths(
+                &OpenParams {
+                    paths: vec![dir.path().join("a").to_path_buf()],
+                    app_state: app_state.clone(),
+                },
+                cx,
+            )
+        })
+        .await;
+        assert_eq!(cx.window_ids().len(), 1);
+        let workspace_view_1 = cx.root_view::<Workspace>(cx.window_ids()[0]).unwrap();
+        workspace_view_1.read_with(&cx, |workspace, _| {
+            assert_eq!(workspace.worktrees().len(), 2)
+        });
+
+        cx.update(|cx| {
+            open_paths(
+                &OpenParams {
+                    paths: vec![
+                        dir.path().join("b").to_path_buf(),
+                        dir.path().join("c").to_path_buf(),
+                    ],
+                    app_state: app_state.clone(),
+                },
+                cx,
+            )
+        })
+        .await;
+        assert_eq!(cx.window_ids().len(), 2);
     }
 
     #[gpui::test]

zed/src/worktree.rs 🔗

@@ -3352,21 +3352,34 @@ mod tests {
             log::info!("Generated initial tree");
 
             let (notify_tx, _notify_rx) = smol::channel::unbounded();
+            let fs = Arc::new(RealFs);
+            let next_entry_id = Arc::new(AtomicUsize::new(0));
+            let mut initial_snapshot = Snapshot {
+                id: 0,
+                scan_id: 0,
+                abs_path: root_dir.path().into(),
+                entries_by_path: Default::default(),
+                entries_by_id: Default::default(),
+                removed_entry_ids: Default::default(),
+                ignores: Default::default(),
+                root_name: Default::default(),
+                root_char_bag: Default::default(),
+                next_entry_id: next_entry_id.clone(),
+            };
+            initial_snapshot.insert_entry(
+                smol::block_on(fs.entry(
+                    Default::default(),
+                    &next_entry_id,
+                    Path::new("").into(),
+                    root_dir.path().into(),
+                ))
+                .unwrap()
+                .unwrap(),
+            );
             let mut scanner = BackgroundScanner::new(
-                Arc::new(Mutex::new(Snapshot {
-                    id: 0,
-                    scan_id: 0,
-                    abs_path: root_dir.path().into(),
-                    entries_by_path: Default::default(),
-                    entries_by_id: Default::default(),
-                    removed_entry_ids: Default::default(),
-                    ignores: Default::default(),
-                    root_name: Default::default(),
-                    root_char_bag: Default::default(),
-                    next_entry_id: Default::default(),
-                })),
+                Arc::new(Mutex::new(initial_snapshot.clone())),
                 notify_tx,
-                Arc::new(RealFs),
+                fs.clone(),
                 Arc::new(gpui::executor::Background::new()),
             );
             smol::block_on(scanner.scan_dirs()).unwrap();
@@ -3392,18 +3405,7 @@ mod tests {
 
             let (notify_tx, _notify_rx) = smol::channel::unbounded();
             let mut new_scanner = BackgroundScanner::new(
-                Arc::new(Mutex::new(Snapshot {
-                    id: 0,
-                    scan_id: 0,
-                    abs_path: root_dir.path().into(),
-                    entries_by_path: Default::default(),
-                    entries_by_id: Default::default(),
-                    removed_entry_ids: Default::default(),
-                    ignores: Default::default(),
-                    root_name: Default::default(),
-                    root_char_bag: Default::default(),
-                    next_entry_id: Default::default(),
-                })),
+                Arc::new(Mutex::new(initial_snapshot)),
                 notify_tx,
                 scanner.fs.clone(),
                 scanner.executor.clone(),