Skip to main content

veecle_os_test/
execute.rs

1/// Execute a test case with a set of actors.
2///
3/// This macro's syntax mirrors that of `veecle_os::runtime::execute!` with an extra `validation` argument.
4/// The argument should be an async closure that runs any needed validations on the actors behaviors.
5///
6/// Any store lifetimes in the `validation` argument should use `'_` as a placeholder.
7///
8/// ```rust
9/// use veecle_os::runtime::single_writer::{Reader, Writer};
10/// use veecle_os::runtime::{Never, Storable};
11///
12/// #[derive(Clone, Copy, Debug, Eq, PartialEq, Storable)]
13/// pub struct Data(u32);
14///
15/// #[derive(Debug, Storable)]
16/// pub struct Trigger;
17///
18/// #[veecle_os::runtime::actor]
19/// async fn incrementor(mut writer: Writer<'_, Data>, mut trigger: Reader<'_, Trigger>) -> Never {
20///     loop {
21///         trigger.wait_for_update().await;
22///         writer.modify(|mut data| {
23///             *data = Some(data.map_or(Data(0), |data| Data(data.0 + 1)));
24///         }).await;
25///     }
26/// }
27///
28/// veecle_os_test::block_on_future(
29///     veecle_os_test::execute! {
30///         actors: [Incrementor],
31///
32///         validation: async |mut reader: Reader<'_, Data>, mut trigger: Writer<'_, Trigger>| {
33///             trigger.write(Trigger).await;
34///             assert_eq!(reader.read_updated_cloned().await, Data(0));
35///             trigger.write(Trigger).await;
36///             assert_eq!(reader.read_updated_cloned().await, Data(1));
37///             trigger.write(Trigger).await;
38///             assert_eq!(reader.read_updated_cloned().await, Data(2));
39///         },
40///     }
41/// );
42/// ```
43#[macro_export]
44macro_rules! execute {
45    (
46        actors: [
47            $($actor_type:ty $(: $init_context:expr )? ),* $(,)?
48        ],
49
50        validation: async |$(mut $arg_pat:ident : $arg_ty:ty),* $(,)?| $validation_body:block $(,)?
51    ) => {{
52        #[$crate::__exports::veecle_os_runtime::actor(crate = $crate::__exports::veecle_os_runtime)]
53        async fn veecle_os_test_validator_generated_actor(
54            $(mut $arg_pat : $arg_ty,)*
55            #[init_context] __complete: $crate::__exports::futures::channel::oneshot::Sender<()>,
56        ) -> $crate::__exports::veecle_os_runtime::Never {
57            $validation_body;
58            __complete.send(()).unwrap();
59            core::future::pending().await
60        }
61
62        async {
63            let (complete_tx, complete_rx) =
64                $crate::__exports::futures::channel::oneshot::channel::<()>();
65
66            let executor = core::pin::pin!(
67                $crate::__exports::veecle_os_runtime::execute! {
68                    actors: [
69                        $($actor_type $(: $init_context)? ,)*
70                        VeecleOsTestValidatorGeneratedActor: complete_tx,
71                    ],
72                }
73            );
74
75            $crate::__exports::futures::future::select(executor, complete_rx).await;
76        }
77    }};
78
79    // The previous arm doesn't support `validation: async ||` (no space between first `|´ and second ´|´) for some reason.
80    // To avoid forcing users to add whitespace between `||`, we add this arm.
81    (
82        actors: [
83            $($actor_type:ty $(: $init_context:expr )? ),* $(,)?
84        ],
85
86        validation: async || $validation_body:block $(,)?
87    ) => {{
88        $crate::execute!(
89            actors: [
90                $($actor_type $(: $init_context)? ),*
91            ],
92
93            validation: async | | $validation_body
94        )
95    }};
96}
97
98#[cfg(test)]
99#[cfg_attr(coverage_nightly, coverage(off))]
100mod tests {
101    #[veecle_os_runtime::actor]
102    async fn contextual_actor<T: core::fmt::Debug>(
103        #[init_context] _context: T,
104    ) -> veecle_os_runtime::Never {
105        std::future::pending().await
106    }
107
108    #[test]
109    fn local_context() {
110        let local = vec![1];
111        futures::executor::block_on(crate::execute! {
112            actors: [
113                ContextualActor<&Vec<i32>>: &local,
114            ],
115            validation: async || {}
116        });
117        dbg!(&local);
118    }
119}