1//! Convenience crate that re-exports GPUI's platform traits and the
2//! `current_platform` constructor so consumers don't need `#[cfg]` gating.
3
4pub use gpui::Platform;
5
6use std::rc::Rc;
7
8/// Returns a background executor for the current platform.
9pub fn background_executor() -> gpui::BackgroundExecutor {
10 current_platform(true).background_executor()
11}
12
13pub fn application() -> gpui::Application {
14 gpui::Application::with_platform(current_platform(false))
15}
16
17pub fn headless() -> gpui::Application {
18 gpui::Application::with_platform(current_platform(true))
19}
20
21/// Returns the default [`Platform`] for the current OS.
22pub fn current_platform(headless: bool) -> Rc<dyn Platform> {
23 #[cfg(target_os = "macos")]
24 {
25 Rc::new(gpui_macos::MacPlatform::new(headless))
26 }
27
28 #[cfg(target_os = "windows")]
29 {
30 Rc::new(
31 gpui_windows::WindowsPlatform::new(headless)
32 .expect("failed to initialize Windows platform"),
33 )
34 }
35
36 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
37 {
38 gpui_linux::current_platform(headless)
39 }
40}
41
42#[cfg(all(test, target_os = "macos"))]
43mod tests {
44 use super::*;
45 use gpui::{AppContext, Empty, VisualTestAppContext};
46 use std::cell::RefCell;
47 use std::time::Duration;
48
49 // Note: All VisualTestAppContext tests are ignored by default because they require
50 // the macOS main thread. Standard Rust tests run on worker threads, which causes
51 // SIGABRT when interacting with macOS AppKit/Cocoa APIs.
52 //
53 // To run these tests, use:
54 // cargo test -p gpui visual_test_context -- --ignored --test-threads=1
55
56 #[test]
57 #[ignore] // Requires macOS main thread
58 fn test_foreground_tasks_run_with_run_until_parked() {
59 let mut cx = VisualTestAppContext::new(current_platform(false));
60
61 let task_ran = Rc::new(RefCell::new(false));
62
63 // Spawn a foreground task via the App's spawn method
64 // This should use our TestDispatcher, not the MacDispatcher
65 {
66 let task_ran = task_ran.clone();
67 cx.update(|cx| {
68 cx.spawn(async move |_| {
69 *task_ran.borrow_mut() = true;
70 })
71 .detach();
72 });
73 }
74
75 // The task should not have run yet
76 assert!(!*task_ran.borrow());
77
78 // Run until parked should execute the foreground task
79 cx.run_until_parked();
80
81 // Now the task should have run
82 assert!(*task_ran.borrow());
83 }
84
85 #[test]
86 #[ignore] // Requires macOS main thread
87 fn test_advance_clock_triggers_delayed_tasks() {
88 let mut cx = VisualTestAppContext::new(current_platform(false));
89
90 let task_ran = Rc::new(RefCell::new(false));
91
92 // Spawn a task that waits for a timer
93 {
94 let task_ran = task_ran.clone();
95 let executor = cx.background_executor.clone();
96 cx.update(|cx| {
97 cx.spawn(async move |_| {
98 executor.timer(Duration::from_millis(500)).await;
99 *task_ran.borrow_mut() = true;
100 })
101 .detach();
102 });
103 }
104
105 // Run until parked - the task should be waiting on the timer
106 cx.run_until_parked();
107 assert!(!*task_ran.borrow());
108
109 // Advance clock past the timer duration
110 cx.advance_clock(Duration::from_millis(600));
111
112 // Now the task should have completed
113 assert!(*task_ran.borrow());
114 }
115
116 #[test]
117 #[ignore] // Requires macOS main thread - window creation fails on test threads
118 fn test_window_spawn_uses_test_dispatcher() {
119 let mut cx = VisualTestAppContext::new(current_platform(false));
120
121 let task_ran = Rc::new(RefCell::new(false));
122
123 let window = cx
124 .open_offscreen_window_default(|_, cx| cx.new(|_| Empty))
125 .expect("Failed to open window");
126
127 // Spawn a task via window.spawn - this is the critical test case
128 // for tooltip behavior, as tooltips use window.spawn for delayed show
129 {
130 let task_ran = task_ran.clone();
131 cx.update_window(window.into(), |_, window, cx| {
132 window
133 .spawn(cx, async move |_| {
134 *task_ran.borrow_mut() = true;
135 })
136 .detach();
137 })
138 .ok();
139 }
140
141 // The task should not have run yet
142 assert!(!*task_ran.borrow());
143
144 // Run until parked should execute the foreground task spawned via window
145 cx.run_until_parked();
146
147 // Now the task should have run
148 assert!(*task_ran.borrow());
149 }
150}