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