test_context.rs

  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}