Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T06:32:46.787Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

visual_test.rs

265 lines · 7.8 KB · rust
1//! Visual test platform that combines real rendering (macOs-only for now) with controllable TestDispatcher.
2//!
3//! This platform is used for visual tests that need:
4//! - Real rendering (e.g. Metal/compositor) for accurate screenshots
5//! - Deterministic task scheduling via TestDispatcher
6//! - Controllable time via `advance_clock`
7
8use crate::ScreenCaptureSource;
9use crate::{
10    AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, ForegroundExecutor, Keymap,
11    Menu, MenuItem, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay,
12    PlatformKeyboardLayout, PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Task,
13    TestDispatcher, WindowAppearance, WindowParams,
14};
15use anyhow::Result;
16use futures::channel::oneshot;
17use parking_lot::Mutex;
18
19use std::{
20    path::{Path, PathBuf},
21    rc::Rc,
22    sync::Arc,
23};
24
25/// A platform that combines real Mac rendering with controllable TestDispatcher.
26///
27/// This allows visual tests to:
28/// - Render real UI via Metal for accurate screenshots
29/// - Control task scheduling deterministically via TestDispatcher
30/// - Advance simulated time for testing time-based behaviors (tooltips, animations, etc.)
31pub struct VisualTestPlatform {
32    dispatcher: TestDispatcher,
33    background_executor: BackgroundExecutor,
34    foreground_executor: ForegroundExecutor,
35    platform: Rc<dyn Platform>,
36    clipboard: Mutex<Option<ClipboardItem>>,
37    find_pasteboard: Mutex<Option<ClipboardItem>>,
38}
39
40impl VisualTestPlatform {
41    /// Creates a new VisualTestPlatform with the given random seed.
42    ///
43    /// The seed is used for deterministic random number generation in the TestDispatcher.
44    pub fn new(platform: Rc<dyn Platform>, seed: u64) -> Self {
45        let dispatcher = TestDispatcher::new(seed);
46        let arc_dispatcher = Arc::new(dispatcher.clone());
47
48        let background_executor = BackgroundExecutor::new(arc_dispatcher.clone());
49        let foreground_executor = ForegroundExecutor::new(arc_dispatcher);
50
51        Self {
52            dispatcher,
53            background_executor,
54            foreground_executor,
55            platform,
56            clipboard: Mutex::new(None),
57            find_pasteboard: Mutex::new(None),
58        }
59    }
60
61    /// Returns a reference to the TestDispatcher for controlling task scheduling and time.
62    pub fn dispatcher(&self) -> &TestDispatcher {
63        &self.dispatcher
64    }
65}
66
67impl Platform for VisualTestPlatform {
68    fn background_executor(&self) -> BackgroundExecutor {
69        self.background_executor.clone()
70    }
71
72    fn foreground_executor(&self) -> ForegroundExecutor {
73        self.foreground_executor.clone()
74    }
75
76    fn text_system(&self) -> Arc<dyn PlatformTextSystem> {
77        self.platform.text_system()
78    }
79
80    fn run(&self, _on_finish_launching: Box<dyn 'static + FnOnce()>) {
81        panic!("VisualTestPlatform::run should not be called in tests")
82    }
83
84    fn quit(&self) {}
85
86    fn restart(&self, _binary_path: Option<PathBuf>) {}
87
88    fn activate(&self, _ignoring_other_apps: bool) {}
89
90    fn hide(&self) {}
91
92    fn hide_other_apps(&self) {}
93
94    fn unhide_other_apps(&self) {}
95
96    fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
97        self.platform.displays()
98    }
99
100    fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
101        self.platform.primary_display()
102    }
103
104    fn active_window(&self) -> Option<AnyWindowHandle> {
105        self.platform.active_window()
106    }
107
108    fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
109        self.platform.window_stack()
110    }
111
112    fn is_screen_capture_supported(&self) -> bool {
113        self.platform.is_screen_capture_supported()
114    }
115
116    fn screen_capture_sources(
117        &self,
118    ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
119        self.platform.screen_capture_sources()
120    }
121
122    fn open_window(
123        &self,
124        handle: AnyWindowHandle,
125        options: WindowParams,
126    ) -> Result<Box<dyn PlatformWindow>> {
127        self.platform.open_window(handle, options)
128    }
129
130    fn window_appearance(&self) -> WindowAppearance {
131        self.platform.window_appearance()
132    }
133
134    fn open_url(&self, url: &str) {
135        self.platform.open_url(url)
136    }
137
138    fn on_open_urls(&self, _callback: Box<dyn FnMut(Vec<String>)>) {}
139
140    fn register_url_scheme(&self, _url: &str) -> Task<Result<()>> {
141        Task::ready(Ok(()))
142    }
143
144    fn prompt_for_paths(
145        &self,
146        _options: PathPromptOptions,
147    ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
148        let (tx, rx) = oneshot::channel();
149        tx.send(Ok(None)).ok();
150        rx
151    }
152
153    fn prompt_for_new_path(
154        &self,
155        _directory: &Path,
156        _suggested_name: Option<&str>,
157    ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
158        let (tx, rx) = oneshot::channel();
159        tx.send(Ok(None)).ok();
160        rx
161    }
162
163    fn can_select_mixed_files_and_dirs(&self) -> bool {
164        true
165    }
166
167    fn reveal_path(&self, path: &Path) {
168        self.platform.reveal_path(path)
169    }
170
171    fn open_with_system(&self, path: &Path) {
172        self.platform.open_with_system(path)
173    }
174
175    fn on_quit(&self, _callback: Box<dyn FnMut()>) {}
176
177    fn on_reopen(&self, _callback: Box<dyn FnMut()>) {}
178
179    fn on_system_wake(&self, _callback: Box<dyn FnMut()>) {}
180
181    fn set_menus(&self, _menus: Vec<Menu>, _keymap: &Keymap) {}
182
183    fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
184        None
185    }
186
187    fn set_dock_menu(&self, _menu: Vec<MenuItem>, _keymap: &Keymap) {}
188
189    fn on_app_menu_action(&self, _callback: Box<dyn FnMut(&dyn crate::Action)>) {}
190
191    fn on_will_open_app_menu(&self, _callback: Box<dyn FnMut()>) {}
192
193    fn on_validate_app_menu_command(&self, _callback: Box<dyn FnMut(&dyn crate::Action) -> bool>) {}
194
195    fn app_path(&self) -> Result<PathBuf> {
196        self.platform.app_path()
197    }
198
199    fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
200        self.platform.path_for_auxiliary_executable(name)
201    }
202
203    fn set_cursor_style(&self, style: CursorStyle) {
204        self.platform.set_cursor_style(style)
205    }
206
207    fn hide_cursor_until_mouse_moves(&self) {
208        self.platform.hide_cursor_until_mouse_moves();
209    }
210
211    fn is_cursor_visible(&self) -> bool {
212        self.platform.is_cursor_visible()
213    }
214
215    fn should_auto_hide_scrollbars(&self) -> bool {
216        self.platform.should_auto_hide_scrollbars()
217    }
218
219    fn read_from_clipboard(&self) -> Option<ClipboardItem> {
220        self.clipboard.lock().clone()
221    }
222
223    fn write_to_clipboard(&self, item: ClipboardItem) {
224        *self.clipboard.lock() = Some(item);
225    }
226
227    #[cfg(target_os = "macos")]
228    fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
229        self.find_pasteboard.lock().clone()
230    }
231
232    #[cfg(target_os = "macos")]
233    fn write_to_find_pasteboard(&self, item: ClipboardItem) {
234        *self.find_pasteboard.lock() = Some(item);
235    }
236
237    fn write_credentials(&self, _url: &str, _username: &str, _password: &[u8]) -> Task<Result<()>> {
238        Task::ready(Ok(()))
239    }
240
241    fn read_credentials(&self, _url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
242        Task::ready(Ok(None))
243    }
244
245    fn delete_credentials(&self, _url: &str) -> Task<Result<()>> {
246        Task::ready(Ok(()))
247    }
248
249    fn keyboard_layout(&self) -> Box<dyn PlatformKeyboardLayout> {
250        self.platform.keyboard_layout()
251    }
252
253    fn keyboard_mapper(&self) -> Rc<dyn PlatformKeyboardMapper> {
254        self.platform.keyboard_mapper()
255    }
256
257    fn on_keyboard_layout_change(&self, _callback: Box<dyn FnMut()>) {}
258
259    fn thermal_state(&self) -> super::ThermalState {
260        super::ThermalState::Nominal
261    }
262
263    fn on_thermal_state_change(&self, _callback: Box<dyn FnMut()>) {}
264}
265
Served at tenant.openagents/omega Member data and write actions are omitted.