1use crate::{
2 AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, Handle, MainThread,
3 ModelContext, Result, Task, 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 refresh(&mut self) -> Result<()> {
41 let mut lock = self.app.lock();
42 lock.refresh();
43 Ok(())
44 }
45
46 pub fn executor(&self) -> &Executor {
47 &self.executor
48 }
49
50 pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
51 let mut lock = self.app.lock();
52 Ok(f(&mut *lock))
53 }
54
55 pub fn read_window<R>(
56 &self,
57 handle: AnyWindowHandle,
58 update: impl FnOnce(&WindowContext) -> R,
59 ) -> Result<R> {
60 let mut app_context = self.app.lock();
61 app_context.read_window(handle.id, update)
62 }
63
64 pub fn update_window<R>(
65 &self,
66 handle: AnyWindowHandle,
67 update: impl FnOnce(&mut WindowContext) -> R,
68 ) -> Result<R> {
69 let mut app = self.app.lock();
70 app.update_window(handle.id, update)
71 }
72
73 pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
74 where
75 Fut: Future<Output = R> + Send + 'static,
76 R: Send + 'static,
77 {
78 let cx = self.to_async();
79 self.executor.spawn(async move { f(cx).await })
80 }
81
82 pub fn spawn_on_main<Fut, R>(
83 &self,
84 f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
85 ) -> Task<R>
86 where
87 Fut: Future<Output = R> + 'static,
88 R: Send + 'static,
89 {
90 let cx = self.to_async();
91 self.executor.spawn_on_main(|| f(cx))
92 }
93
94 pub fn run_on_main<R>(
95 &self,
96 f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
97 ) -> Result<Task<R>>
98 where
99 R: Send + 'static,
100 {
101 let mut app_context = self.app.lock();
102 Ok(app_context.run_on_main(f))
103 }
104
105 pub fn has_global<G: 'static>(&self) -> Result<bool> {
106 let lock = self.app.lock();
107 Ok(lock.has_global::<G>())
108 }
109
110 pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
111 let lock = self.app.lock();
112 Ok(read(lock.global(), &lock))
113 }
114
115 pub fn try_read_global<G: 'static, R>(
116 &self,
117 read: impl FnOnce(&G, &AppContext) -> R,
118 ) -> Option<R> {
119 let lock = self.app.lock();
120 Some(read(lock.try_global()?, &lock))
121 }
122
123 pub fn update_global<G: 'static, R>(
124 &mut self,
125 update: impl FnOnce(&mut G, &mut AppContext) -> R,
126 ) -> Result<R> {
127 let mut lock = self.app.lock();
128 Ok(lock.update_global(update))
129 }
130
131 fn to_async(&self) -> AsyncAppContext {
132 AsyncAppContext {
133 app: Arc::downgrade(&self.app),
134 executor: self.executor.clone(),
135 }
136 }
137}