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