xref: /aosp_15_r20/platform_testing/libraries/rdroidtest/src/lib.rs (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
1 //! Test harness which supports ignoring tests at runtime.
2 
3 pub mod runner;
4 
5 // Re-export the attribute macros.
6 pub use rdroidtest_macro::{ignore_if, rdroidtest};
7 
8 #[doc(hidden)]
9 pub use libtest_mimic as _libtest_mimic;
10 #[doc(hidden)]
11 pub use linkme as _linkme;
12 #[doc(hidden)]
13 pub use paste as _paste;
14 
15 /// Macro to generate the main function for the test harness.
16 #[macro_export]
17 macro_rules! test_main {
18     () => {
19         #[cfg(test)]
20         fn main() {
21             $crate::runner::main()
22         }
23     };
24 }
25 
26 /// Macro to generate a wrapper function for a single test.
27 ///
28 /// # Usage
29 ///
30 /// ```
31 /// use rdroidtest::test;
32 ///
33 /// test!(test_string_equality);
34 /// fn test_string_equality() {
35 ///   assert_eq!("", "");
36 /// }
37 /// ```
38 #[macro_export]
39 macro_rules! test {
40     ($test_name:ident) => {
41         $crate::_paste::paste!(
42             #[$crate::_linkme::distributed_slice($crate::runner::RDROIDTEST_TESTS)]
43             fn [< __test_ $test_name >]() -> $crate::_libtest_mimic::Trial {
44                 $crate::_libtest_mimic::Trial::test(
45                     $crate::_prepend_module_path!(::std::stringify!($test_name)),
46                     move || $crate::runner::run($test_name),
47                 )
48             }
49         );
50     };
51     ($test_name:ident, ignore_if: $ignore_expr:expr) => {
52         $crate::_paste::paste!(
53             #[$crate::_linkme::distributed_slice($crate::runner::RDROIDTEST_TESTS)]
54             fn [< __test_ $test_name >]() -> $crate::_libtest_mimic::Trial {
55                 $crate::_libtest_mimic::Trial::test(
56                     $crate::_prepend_module_path!(::std::stringify!($test_name)),
57                     move || $crate::runner::run($test_name),
58                 ).with_ignored_flag($ignore_expr)
59             }
60         );
61     };
62 }
63 
64 /// Macro to generate a wrapper function for a parameterized test.
65 ///
66 /// # Usage
67 ///
68 /// ```
69 ///  use rdroidtest::ptest;
70 ///
71 /// /// Return (param name, param value) tuples of type `(String, T)`.
72 /// /// The parameter value can be any type T (not just `u32`).
73 /// fn my_instances() -> Vec<(String, u32)> {
74 ///     vec![
75 ///         ("one".to_string(), 1),
76 ///         ("two".to_string(), 2),
77 ///         ("three".to_string(), 3),
78 ///     ]
79 /// }
80 ///
81 /// ptest!(is_even, my_instances());
82 /// fn is_even(param: u32) {
83 ///     // Test method takes a parameter of type T.
84 ///     assert_eq!(param % 2, 0);
85 /// }
86 /// ```
87 #[macro_export]
88 macro_rules! ptest {
89     ($test_name:ident, $param_gen:expr) => {
90         $crate::_paste::paste!(
91             #[$crate::_linkme::distributed_slice($crate::runner::RDROIDTEST_PTESTS)]
92             fn [< __ptest_ $test_name >]() -> Vec<$crate::_libtest_mimic::Trial> {
93                 $param_gen.into_iter().map(|(name, val)| {
94                     $crate::_libtest_mimic::Trial::test(
95                         format!(
96                             "{}/{}",
97                             $crate::_prepend_module_path!(::std::stringify!($test_name)),
98                             name
99                         ),
100                         move || $crate::runner::run(|| $test_name(val)),
101                     )
102                 }).collect()
103             }
104         );
105     };
106     ($test_name:ident, $param_gen:expr, ignore_if: $ignore_expr:expr) => {
107         $crate::_paste::paste!(
108             #[$crate::_linkme::distributed_slice($crate::runner::RDROIDTEST_PTESTS)]
109             fn [< __ptest_ $test_name >]() -> Vec<$crate::_libtest_mimic::Trial> {
110                 $param_gen.into_iter().map(|(name, val)| {
111                     let ignored = $ignore_expr(&val);
112                     $crate::_libtest_mimic::Trial::test(
113                         format!(
114                             "{}/{}",
115                             $crate::_prepend_module_path!(::std::stringify!($test_name)),
116                             name
117                         ),
118                         move || $crate::runner::run(|| $test_name(val)),
119                     ).with_ignored_flag(ignored)
120                 }).collect()
121             }
122         );
123     };
124 }
125 
126 /// Prepends module path (without the crate name) to the test name and returns
127 /// the new string.
128 #[doc(hidden)]
129 #[macro_export]
130 macro_rules! _prepend_module_path {
131     ($test_name:expr) => {{
132         match module_path!().split_once("::") {
133             Some((_, path)) => format!("{}::{}", path, $test_name),
134             None => format!("{}", $test_name),
135         }
136     }};
137 }
138