datatest_stable/
macros.rs

1// Copyright (c) The datatest-stable Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4/// `datatest-stable` test harness entry point. Should be declared in the test module.
5///
6/// Also, `harness` should be set to `false` for that test module in `Cargo.toml` (see [Configuring
7/// a target](https://doc.rust-lang.org/cargo/reference/manifest.html#configuring-a-target)).
8#[macro_export]
9macro_rules! harness {
10    ( $( { $($args:tt)* } ),+ $(,)* ) => {
11        fn main() -> $crate::Result<()> {
12            let mut requirements = Vec::new();
13            use $crate::data_source_kinds::*;
14            use $crate::test_kinds::*;
15
16            $(
17                $crate::harness_collect!(@gather_test requirements, { $($args)*, } => { });
18            )+
19
20            $crate::runner(&requirements);
21            Ok(())
22        }
23    };
24    ( $( $name:path, $root:expr, $pattern:expr ),+ $(,)* ) => {
25        // This is the old format with datatest-stable 0.2. Print a nice message
26        // in this case.
27        const _: () = {
28            compile_error!(
29concat!(r"this format is no longer supported -- please switch to specifying as:
30
31datatest_stable::harness! {
32",
33    $(concat!("    { test = ", stringify!($name), ", root = ", stringify!($root), ", pattern = ", stringify!($pattern), " },\n"),)+
34r"}
35
36note: patterns are now evaluated relative to the provided root, not to the crate root
37"));
38        };
39    }
40}
41
42#[macro_export]
43#[doc(hidden)]
44macro_rules! harness_collect {
45    // Gather `test`
46    (@gather_test
47        $requirements:expr,
48        // Note: here and below, rest always ends with at least 1 comma
49        { test = $test:path, $($rest:tt)* } =>
50        { }
51    ) => {
52        $crate::harness_collect!(@gather_root
53            $requirements,
54            { $($rest)* } =>
55            { test = $test, }
56        );
57    };
58
59    // `test` not found
60    (@gather_test
61        $requirements:expr,
62        { $key:ident $($rest:tt)* } =>
63        { }
64    ) => {
65        compile_error!(concat!("expected `test`, found `", stringify!($key), "`"));
66    };
67
68    // No remaining arguments
69    (@gather_test
70        $requirements:expr,
71        { $(,)* } =>
72        { }
73    ) => {
74        compile_error!("expected `test`, but ran out of arguments");
75    };
76
77    // Something that isn't an identifier
78    (@gather_test
79        $requirements:expr,
80        { $($rest:tt)* } =>
81        { }
82    ) => {
83        compile_error!(concat!("expected `test`, found non-identifier token: (rest: ", stringify!($($rest)*), ")"));
84    };
85
86    // Gather `root`
87    (@gather_root
88        $requirements:expr,
89        { root = $root:expr, $($rest:tt)* } =>
90        { $($collected:tt)* }
91    ) => {
92        $crate::harness_collect!(@gather_pattern
93            $requirements,
94            { $($rest)* } =>
95            { $($collected)* root = $root, }
96        );
97    };
98
99    // `root` not found
100    (@gather_root
101        $requirements:expr,
102        { $key:ident $($rest:tt)* } =>
103        { $($collected:tt)* }
104    ) => {
105        compile_error!(concat!("expected `root`, found `", stringify!($key), "`"));
106    };
107
108    // No remaining arguments
109    (@gather_root
110        $requirements:expr,
111        { $(,)* } =>
112        { $($collected:tt)* }
113    ) => {
114        compile_error!(concat!("expected `root`, but ran out of arguments (collected: ", stringify!($($collected)*), ")"));
115    };
116
117    // Something that isn't an identifier
118    (@gather_root
119        $requirements:expr,
120        { $($rest:tt)* } =>
121        { $($collected:tt)* }
122    ) => {
123        compile_error!(concat!("expected `root`, found non-identifier token (rest: ", stringify!($($rest)*), ")"));
124    };
125
126    // Gather pattern
127    (@gather_pattern
128        $requirements:expr,
129        { pattern = $pattern:expr, $($rest:tt)* } =>
130        { $($collected:tt)* }
131    ) => {
132        $crate::harness_collect!(@finish
133            $requirements,
134            { $($rest)* } =>
135            { $($collected)* pattern = $pattern, }
136        );
137    };
138
139    // `pattern` not found
140    (@gather_pattern
141        $requirements:expr,
142        { $key:ident $($rest:tt)* } =>
143        { $($collected:tt)* }
144    ) => {
145        compile_error!(concat!("expected `pattern`, found `", stringify!($key), "`"));
146    };
147
148    // `pattern` not found: no remaining arguments
149    (@gather_pattern
150        $requirements:expr,
151        { $(,)* } =>
152        { $($collected:tt)* }
153    ) => {
154        $crate::harness_collect!(@finish
155            $requirements,
156            { } =>
157            { $($collected)* pattern = ".*", }
158        );
159    };
160
161    // Something that isn't an identifier
162    (@gather_pattern
163        $requirements:expr,
164        { $($rest:tt)* } =>
165        { $($collected:tt)* }
166    ) => {
167        compile_error!(concat!("expected `pattern`, found non-identifier token (rest: ", stringify!($($rest)*), ")"));
168    };
169
170    // Finish - no more arguments allowed
171    (@finish
172        $requirements:expr,
173        { $(,)* } =>
174        { test = $test:path, root = $root:expr, pattern = $pattern:expr, }
175    ) => {
176        $requirements.push(
177            $crate::Requirements::new(
178                $test.kind().resolve($test),
179                stringify!($test).to_string(),
180                $root.resolve_data_source(),
181                $pattern.to_string()
182            )
183        );
184    };
185
186    // Finish - unexpected extra arguments
187    (@finish
188        $requirements:expr,
189        { $($unexpected:tt)+ } =>
190        { $($collected:tt)* }
191    ) => {
192        compile_error!(concat!("unexpected extra arguments: ", stringify!($($unexpected)+)));
193    };
194}