From 5e00df62672b96baf73812eb8d5d4a4cb7491b70 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 6 Jul 2022 16:55:05 +0200 Subject: [PATCH] Move autosave tests down into `Workspace` --- crates/workspace/src/workspace.rs | 92 ++++++++++++++++++++++++++++++- crates/zed/src/zed.rs | 75 ------------------------- 2 files changed, 90 insertions(+), 77 deletions(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cf1092662f..2120695760 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2688,7 +2688,7 @@ fn open_new(app_state: &Arc, cx: &mut MutableAppContext) { #[cfg(test)] mod tests { use super::*; - use gpui::{ModelHandle, TestAppContext, ViewContext}; + use gpui::{executor::Deterministic, ModelHandle, TestAppContext, ViewContext}; use project::{FakeFs, Project, ProjectEntryId}; use serde_json::json; @@ -3026,6 +3026,86 @@ mod tests { }); } + #[gpui::test] + async fn test_autosave(deterministic: Arc, 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.is_dirty = true; + item + }); + let item_id = item.id(); + workspace.update(cx, |workspace, cx| { + workspace.add_item(Box::new(item.clone()), cx); + }); + + // Autosave on window change. + item.update(cx, |_, cx| { + cx.update_global(|settings: &mut Settings, _| { + settings.autosave = Autosave::OnWindowChange; + }); + }); + + // Deactivating the window saves the file. + cx.simulate_window_activation(None); + deterministic.run_until_parked(); + item.read_with(cx, |item, _| assert_eq!(item.save_count, 1)); + + // Autosave on focus change. + item.update(cx, |_, cx| { + cx.focus_self(); + cx.update_global(|settings: &mut Settings, _| { + settings.autosave = Autosave::OnFocusChange; + }); + }); + + // Blurring the item saves the file. + item.update(cx, |_, cx| cx.blur()); + deterministic.run_until_parked(); + item.read_with(cx, |item, _| assert_eq!(item.save_count, 2)); + + // Autosave after delay. + item.update(cx, |_, cx| { + cx.update_global(|settings: &mut Settings, _| { + settings.autosave = Autosave::AfterDelay { milliseconds: 500 }; + }); + cx.emit(TestItemEvent::Edit); + }); + + // Delay hasn't fully expired, so the file is still dirty and unsaved. + deterministic.advance_clock(Duration::from_millis(250)); + item.read_with(cx, |item, _| assert_eq!(item.save_count, 2)); + + // After delay expires, the file is saved. + deterministic.advance_clock(Duration::from_millis(250)); + item.read_with(cx, |item, _| assert_eq!(item.save_count, 3)); + + // Autosave on focus change, ensuring closing the tab counts as such. + item.update(cx, |_, cx| { + cx.update_global(|settings: &mut Settings, _| { + settings.autosave = Autosave::OnFocusChange; + }); + }); + + workspace + .update(cx, |workspace, cx| { + let pane = workspace.active_pane().clone(); + Pane::close_items(workspace, pane, cx, move |id| id == item_id) + }) + .await + .unwrap(); + assert!(!cx.has_pending_prompt(window_id)); + item.read_with(cx, |item, _| assert_eq!(item.save_count, 4)); + } + #[derive(Clone)] struct TestItem { save_count: usize, @@ -3038,6 +3118,10 @@ mod tests { is_singleton: bool, } + enum TestItemEvent { + Edit, + } + impl TestItem { fn new() -> Self { Self { @@ -3054,7 +3138,7 @@ mod tests { } impl Entity for TestItem { - type Event = (); + type Event = TestItemEvent; } impl View for TestItem { @@ -3136,5 +3220,9 @@ mod tests { fn should_update_tab_on_event(_: &Self::Event) -> bool { true } + + fn is_edit_event(event: &Self::Event) -> bool { + matches!(event, TestItemEvent::Edit) + } } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 4fa2e238bf..f88aee3d7c 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -396,11 +396,9 @@ mod tests { }; use project::{Project, ProjectPath}; use serde_json::json; - use settings::Autosave; use std::{ collections::HashSet, path::{Path, PathBuf}, - time::Duration, }; use theme::{Theme, ThemeRegistry, DEFAULT_THEME_NAME}; use workspace::{ @@ -979,79 +977,6 @@ mod tests { }) } - #[gpui::test] - async fn test_autosave(deterministic: Arc, cx: &mut gpui::TestAppContext) { - let app_state = init(cx); - let fs = app_state.fs.clone(); - fs.as_fake() - .insert_tree("/root", json!({ "a.txt": "" })) - .await; - - let project = Project::test(fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| Workspace::new(project, cx)); - cx.update(|cx| { - workspace.update(cx, |view, cx| { - view.open_paths(vec![PathBuf::from("/root/a.txt")], true, cx) - }) - }) - .await; - let editor = cx.read(|cx| { - let pane = workspace.read(cx).active_pane().read(cx); - let item = pane.active_item().unwrap(); - item.downcast::().unwrap() - }); - - // Autosave on window change. - editor.update(cx, |editor, cx| { - cx.update_global(|settings: &mut Settings, _| { - settings.autosave = Autosave::OnWindowChange; - }); - editor.insert("X", cx); - assert!(editor.is_dirty(cx)) - }); - - // Deactivating the window saves the file. - cx.simulate_window_activation(None); - deterministic.run_until_parked(); - assert_eq!(fs.load(Path::new("/root/a.txt")).await.unwrap(), "X"); - editor.read_with(cx, |editor, cx| assert!(!editor.is_dirty(cx))); - - // Autosave on focus change. - editor.update(cx, |editor, cx| { - cx.focus_self(); - cx.update_global(|settings: &mut Settings, _| { - settings.autosave = Autosave::OnFocusChange; - }); - editor.insert("X", cx); - assert!(editor.is_dirty(cx)) - }); - - // Blurring the editor saves the file. - editor.update(cx, |_, cx| cx.blur()); - deterministic.run_until_parked(); - assert_eq!(fs.load(Path::new("/root/a.txt")).await.unwrap(), "XX"); - editor.read_with(cx, |editor, cx| assert!(!editor.is_dirty(cx))); - - // Autosave after delay. - editor.update(cx, |editor, cx| { - cx.update_global(|settings: &mut Settings, _| { - settings.autosave = Autosave::AfterDelay { milliseconds: 500 }; - }); - editor.insert("X", cx); - assert!(editor.is_dirty(cx)) - }); - - // Delay hasn't fully expired, so the file is still dirty and unsaved. - deterministic.advance_clock(Duration::from_millis(250)); - assert_eq!(fs.load(Path::new("/root/a.txt")).await.unwrap(), "XX"); - editor.read_with(cx, |editor, cx| assert!(editor.is_dirty(cx))); - - // After delay expires, the file is saved. - deterministic.advance_clock(Duration::from_millis(250)); - assert_eq!(fs.load(Path::new("/root/a.txt")).await.unwrap(), "XXX"); - editor.read_with(cx, |editor, cx| assert!(!editor.is_dirty(cx))); - } - #[gpui::test] async fn test_setting_language_when_saving_as_single_file_worktree(cx: &mut TestAppContext) { let app_state = init(cx);