diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index c223f20532..919a7915e1 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -14,6 +14,7 @@ pub struct TestAppContext { pub background_executor: BackgroundExecutor, pub foreground_executor: ForegroundExecutor, pub dispatcher: TestDispatcher, + pub test_platform: Rc, } impl Context for TestAppContext { @@ -77,17 +78,15 @@ impl TestAppContext { let arc_dispatcher = Arc::new(dispatcher.clone()); let background_executor = BackgroundExecutor::new(arc_dispatcher.clone()); let foreground_executor = ForegroundExecutor::new(arc_dispatcher); - let platform = Rc::new(TestPlatform::new( - background_executor.clone(), - foreground_executor.clone(), - )); + let platform = TestPlatform::new(background_executor.clone(), foreground_executor.clone()); let asset_source = Arc::new(()); let http_client = util::http::FakeHttpClient::with_404_response(); Self { - app: AppContext::new(platform, asset_source, http_client), + app: AppContext::new(platform.clone(), asset_source, http_client), background_executor, foreground_executor, dispatcher: dispatcher.clone(), + test_platform: platform, } } @@ -154,17 +153,17 @@ impl TestAppContext { pub fn simulate_new_path_selection( &self, - _select_path: impl FnOnce(&std::path::Path) -> Option, + select_path: impl FnOnce(&std::path::Path) -> Option, ) { - // + self.test_platform.simulate_new_path_selection(select_path); } - pub fn simulate_prompt_answer(&self, _button_ix: usize) { - // + pub fn simulate_prompt_answer(&self, button_ix: usize) { + self.test_platform.simulate_prompt_answer(button_ix); } pub fn has_pending_prompt(&self) -> bool { - false + self.test_platform.has_pending_prompt() } pub fn spawn(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task diff --git a/crates/gpui2/src/platform/test/platform.rs b/crates/gpui2/src/platform/test/platform.rs index 4afcc4fc1a..3e151ab810 100644 --- a/crates/gpui2/src/platform/test/platform.rs +++ b/crates/gpui2/src/platform/test/platform.rs @@ -3,8 +3,15 @@ use crate::{ PlatformDisplay, PlatformTextSystem, TestDisplay, TestWindow, WindowOptions, }; use anyhow::{anyhow, Result}; +use collections::VecDeque; +use futures::channel::oneshot; use parking_lot::Mutex; -use std::{rc::Rc, sync::Arc}; +use std::{ + cell::RefCell, + path::PathBuf, + rc::{Rc, Weak}, + sync::Arc, +}; pub struct TestPlatform { background_executor: BackgroundExecutor, @@ -13,18 +20,60 @@ pub struct TestPlatform { active_window: Arc>>, active_display: Rc, active_cursor: Mutex, + pub(crate) prompts: RefCell, + weak: Weak, +} + +#[derive(Default)] +pub(crate) struct TestPrompts { + multiple_choice: VecDeque>, + new_path: VecDeque<(PathBuf, oneshot::Sender>)>, } impl TestPlatform { - pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Self { - TestPlatform { + pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Rc { + Rc::new_cyclic(|weak| TestPlatform { background_executor: executor, foreground_executor, - + prompts: Default::default(), active_cursor: Default::default(), active_display: Rc::new(TestDisplay::new()), active_window: Default::default(), - } + weak: weak.clone(), + }) + } + + pub(crate) fn simulate_new_path_selection( + &self, + select_path: impl FnOnce(&std::path::Path) -> Option, + ) { + let (path, tx) = self + .prompts + .borrow_mut() + .new_path + .pop_front() + .expect("no pending new path prompt"); + tx.send(select_path(&path)).ok(); + } + + pub(crate) fn simulate_prompt_answer(&self, response_ix: usize) { + let tx = self + .prompts + .borrow_mut() + .multiple_choice + .pop_front() + .expect("no pending multiple choice prompt"); + tx.send(response_ix).ok(); + } + + pub(crate) fn has_pending_prompt(&self) -> bool { + !self.prompts.borrow().multiple_choice.is_empty() + } + + pub(crate) fn prompt(&self) -> oneshot::Receiver { + let (tx, rx) = oneshot::channel(); + self.prompts.borrow_mut().multiple_choice.push_back(tx); + rx } } @@ -88,7 +137,11 @@ impl Platform for TestPlatform { options: WindowOptions, ) -> Box { *self.active_window.lock() = Some(handle); - Box::new(TestWindow::new(options, self.active_display.clone())) + Box::new(TestWindow::new( + options, + self.weak.clone(), + self.active_display.clone(), + )) } fn set_display_link_output_callback( @@ -118,15 +171,20 @@ impl Platform for TestPlatform { fn prompt_for_paths( &self, _options: crate::PathPromptOptions, - ) -> futures::channel::oneshot::Receiver>> { + ) -> oneshot::Receiver>> { unimplemented!() } fn prompt_for_new_path( &self, - _directory: &std::path::Path, - ) -> futures::channel::oneshot::Receiver> { - unimplemented!() + directory: &std::path::Path, + ) -> oneshot::Receiver> { + let (tx, rx) = oneshot::channel(); + self.prompts + .borrow_mut() + .new_path + .push_back((directory.to_path_buf(), tx)); + rx } fn reveal_path(&self, _path: &std::path::Path) { diff --git a/crates/gpui2/src/platform/test/window.rs b/crates/gpui2/src/platform/test/window.rs index cf9143162e..adb15c4266 100644 --- a/crates/gpui2/src/platform/test/window.rs +++ b/crates/gpui2/src/platform/test/window.rs @@ -1,15 +1,13 @@ -use std::{ - rc::Rc, - sync::{self, Arc}, -}; - -use collections::HashMap; -use parking_lot::Mutex; - use crate::{ px, AtlasKey, AtlasTextureId, AtlasTile, Pixels, PlatformAtlas, PlatformDisplay, - PlatformInputHandler, PlatformWindow, Point, Scene, Size, TileId, WindowAppearance, - WindowBounds, WindowOptions, + PlatformInputHandler, PlatformWindow, Point, Scene, Size, TestPlatform, TileId, + WindowAppearance, WindowBounds, WindowOptions, +}; +use collections::HashMap; +use parking_lot::Mutex; +use std::{ + rc::{Rc, Weak}, + sync::{self, Arc}, }; #[derive(Default)] @@ -25,16 +23,22 @@ pub struct TestWindow { current_scene: Mutex>, display: Rc, input_handler: Option>, - handlers: Mutex, + platform: Weak, sprite_atlas: Arc, } + impl TestWindow { - pub fn new(options: WindowOptions, display: Rc) -> Self { + pub fn new( + options: WindowOptions, + platform: Weak, + display: Rc, + ) -> Self { Self { bounds: options.bounds, current_scene: Default::default(), display, + platform, input_handler: None, sprite_atlas: Arc::new(TestAtlas::new()), handlers: Default::default(), @@ -89,7 +93,7 @@ impl PlatformWindow for TestWindow { _msg: &str, _answers: &[&str], ) -> futures::channel::oneshot::Receiver { - todo!() + self.platform.upgrade().expect("platform dropped").prompt() } fn activate(&self) { diff --git a/crates/project_panel2/src/project_panel.rs b/crates/project_panel2/src/project_panel.rs index 1d44c4f116..ac58313351 100644 --- a/crates/project_panel2/src/project_panel.rs +++ b/crates/project_panel2/src/project_panel.rs @@ -2033,7 +2033,7 @@ mod tests { ); } - #[gpui::test(iterations = 30)] + #[gpui::test(iterations = 10)] async fn test_adding_directories_via_file(cx: &mut gpui::TestAppContext) { init_test(cx); @@ -2653,17 +2653,15 @@ mod tests { .unwrap(); // "Save as"" the buffer, creating a new backing file for it - workspace + let save_task = workspace .update(cx, |workspace, cx| { workspace.save_active_item(workspace::SaveIntent::Save, cx) }) - .unwrap() - .await .unwrap(); cx.executor().run_until_parked(); cx.simulate_new_path_selection(|_| Some(PathBuf::from("/root/new"))); - cx.executor().run_until_parked(); + save_task.await.unwrap(); // Rename the file select_path(&panel, "root/new", cx);