1use crate::{
2 AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, MainThread, Model,
3 ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext,
4};
5use parking_lot::Mutex;
6use std::{future::Future, sync::Arc};
7
8#[derive(Clone)]
9pub struct TestAppContext {
10 pub app: Arc<Mutex<AppContext>>,
11 pub executor: Executor,
12}
13
14impl Context for TestAppContext {
15 type ModelContext<'a, T> = ModelContext<'a, T>;
16 type Result<T> = T;
17
18 fn build_model<T: 'static>(
19 &mut self,
20 build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T,
21 ) -> Self::Result<Model<T>>
22 where
23 T: 'static + Send,
24 {
25 let mut lock = self.app.lock();
26 lock.build_model(build_model)
27 }
28
29 fn update_model<T: 'static, R>(
30 &mut self,
31 handle: &Model<T>,
32 update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R,
33 ) -> Self::Result<R> {
34 let mut lock = self.app.lock();
35 lock.update_model(handle, update)
36 }
37}
38
39impl TestAppContext {
40 pub fn new(dispatcher: TestDispatcher) -> Self {
41 let executor = Executor::new(Arc::new(dispatcher));
42 let platform = Arc::new(TestPlatform::new(executor.clone()));
43 let asset_source = Arc::new(());
44 let http_client = util::http::FakeHttpClient::with_404_response();
45 Self {
46 app: AppContext::new(platform, asset_source, http_client),
47 executor,
48 }
49 }
50
51 pub fn quit(&self) {
52 self.app.lock().quit();
53 }
54
55 pub fn refresh(&mut self) -> Result<()> {
56 let mut lock = self.app.lock();
57 lock.refresh();
58 Ok(())
59 }
60
61 pub fn executor(&self) -> &Executor {
62 &self.executor
63 }
64
65 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> R {
66 let mut lock = self.app.lock();
67 f(&mut *lock)
68 }
69
70 pub fn read_window<R>(
71 &self,
72 handle: AnyWindowHandle,
73 read: impl FnOnce(&WindowContext) -> R,
74 ) -> R {
75 let mut app_context = self.app.lock();
76 app_context.read_window(handle.id, read).unwrap()
77 }
78
79 pub fn update_window<R>(
80 &self,
81 handle: AnyWindowHandle,
82 update: impl FnOnce(&mut WindowContext) -> R,
83 ) -> R {
84 let mut app = self.app.lock();
85 app.update_window(handle.id, update).unwrap()
86 }
87
88 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
89 where
90 Fut: Future<Output = R> + Send + 'static,
91 R: Send + 'static,
92 {
93 let cx = self.to_async();
94 self.executor.spawn(async move { f(cx).await })
95 }
96
97 pub fn spawn_on_main<Fut, R>(
98 &self,
99 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
100 ) -> Task<R>
101 where
102 Fut: Future<Output = R> + 'static,
103 R: Send + 'static,
104 {
105 let cx = self.to_async();
106 self.executor.spawn_on_main(|| f(cx))
107 }
108
109 pub fn run_on_main<R>(
110 &self,
111 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
112 ) -> Task<R>
113 where
114 R: Send + 'static,
115 {
116 let mut app_context = self.app.lock();
117 app_context.run_on_main(f)
118 }
119
120 pub fn has_global<G: 'static>(&self) -> bool {
121 let lock = self.app.lock();
122 lock.has_global::<G>()
123 }
124
125 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> R {
126 let lock = self.app.lock();
127 read(lock.global(), &lock)
128 }
129
130 pub fn try_read_global<G: 'static, R>(
131 &self,
132 read: impl FnOnce(&G, &AppContext) -> R,
133 ) -> Option<R> {
134 let lock = self.app.lock();
135 Some(read(lock.try_global()?, &lock))
136 }
137
138 pub fn update_global<G: 'static, R>(
139 &mut self,
140 update: impl FnOnce(&mut G, &mut AppContext) -> R,
141 ) -> R {
142 let mut lock = self.app.lock();
143 lock.update_global(update)
144 }
145
146 pub fn to_async(&self) -> AsyncAppContext {
147 AsyncAppContext {
148 app: Arc::downgrade(&self.app),
149 executor: self.executor.clone(),
150 }
151 }
152}