Add test for pane nav history covering notification of pane's toolbar

Max Brunsfeld created

Change summary

crates/workspace/src/workspace.rs | 113 ++++++++++++++++++++++++++++++++
1 file changed, 110 insertions(+), 3 deletions(-)

Detailed changes

crates/workspace/src/workspace.rs 🔗

@@ -3142,25 +3142,104 @@ mod tests {
         item.read_with(cx, |item, _| assert_eq!(item.save_count, 5));
     }
 
-    #[derive(Clone)]
+    #[gpui::test]
+    async fn test_pane_navigation(
+        deterministic: Arc<Deterministic>,
+        cx: &mut gpui::TestAppContext,
+    ) {
+        deterministic.forbid_parking();
+        Settings::test_async(cx);
+        let fs = FakeFs::new(cx.background());
+
+        let project = Project::test(fs, [], cx).await;
+        let (window_id, workspace) = cx.add_window(|cx| Workspace::new(project, cx));
+
+        let item = cx.add_view(window_id, |_| {
+            let mut item = TestItem::new();
+            item.project_entry_ids = vec![ProjectEntryId::from_proto(1)];
+            item
+        });
+        let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone());
+        let toolbar = pane.read_with(cx, |pane, _| pane.toolbar().clone());
+        let toolbar_notify_count = Rc::new(RefCell::new(0));
+
+        workspace.update(cx, |workspace, cx| {
+            workspace.add_item(Box::new(item.clone()), cx);
+            let toolbar_notification_count = toolbar_notify_count.clone();
+            cx.observe(&toolbar, move |_, _, _| {
+                *toolbar_notification_count.borrow_mut() += 1
+            })
+            .detach();
+        });
+
+        pane.read_with(cx, |pane, _| {
+            assert!(!pane.can_navigate_backward());
+            assert!(!pane.can_navigate_forward());
+        });
+
+        item.update(cx, |item, cx| {
+            item.set_state("one".to_string(), cx);
+        });
+
+        // Toolbar must be notified to re-render the navigation buttons
+        assert_eq!(*toolbar_notify_count.borrow(), 1);
+
+        pane.read_with(cx, |pane, _| {
+            assert!(pane.can_navigate_backward());
+            assert!(!pane.can_navigate_forward());
+        });
+
+        workspace
+            .update(cx, |workspace, cx| {
+                Pane::go_back(workspace, Some(pane.clone()), cx)
+            })
+            .await;
+
+        assert_eq!(*toolbar_notify_count.borrow(), 3);
+        pane.read_with(cx, |pane, _| {
+            assert!(!pane.can_navigate_backward());
+            assert!(pane.can_navigate_forward());
+        });
+    }
+
     struct TestItem {
+        state: String,
         save_count: usize,
         save_as_count: usize,
         reload_count: usize,
         is_dirty: bool,
+        is_singleton: bool,
         has_conflict: bool,
         project_entry_ids: Vec<ProjectEntryId>,
         project_path: Option<ProjectPath>,
-        is_singleton: bool,
+        nav_history: Option<ItemNavHistory>,
     }
 
     enum TestItemEvent {
         Edit,
     }
 
+    impl Clone for TestItem {
+        fn clone(&self) -> Self {
+            Self {
+                state: self.state.clone(),
+                save_count: self.save_count,
+                save_as_count: self.save_as_count,
+                reload_count: self.reload_count,
+                is_dirty: self.is_dirty,
+                is_singleton: self.is_singleton,
+                has_conflict: self.has_conflict,
+                project_entry_ids: self.project_entry_ids.clone(),
+                project_path: self.project_path.clone(),
+                nav_history: None,
+            }
+        }
+    }
+
     impl TestItem {
         fn new() -> Self {
             Self {
+                state: String::new(),
                 save_count: 0,
                 save_as_count: 0,
                 reload_count: 0,
@@ -3169,6 +3248,18 @@ mod tests {
                 project_entry_ids: Vec::new(),
                 project_path: None,
                 is_singleton: true,
+                nav_history: None,
+            }
+        }
+
+        fn set_state(&mut self, state: String, cx: &mut ViewContext<Self>) {
+            self.push_to_nav_history(cx);
+            self.state = state;
+        }
+
+        fn push_to_nav_history(&mut self, cx: &mut ViewContext<Self>) {
+            if let Some(history) = &mut self.nav_history {
+                history.push(Some(Box::new(self.state.clone())), cx);
             }
         }
     }
@@ -3204,7 +3295,23 @@ mod tests {
             self.is_singleton
         }
 
-        fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>) {}
+        fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
+            self.nav_history = Some(history);
+        }
+
+        fn navigate(&mut self, state: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
+            let state = *state.downcast::<String>().unwrap_or_default();
+            if state != self.state {
+                self.state = state;
+                true
+            } else {
+                false
+            }
+        }
+
+        fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
+            self.push_to_nav_history(cx);
+        }
 
         fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
         where