test_context.rs

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