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