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() -> ::std::process::ExitCode {
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        }
22    };
23    ( $( $name:path, $root:expr, $pattern:expr ),+ $(,)* ) => {
24        // This is the old format with datatest-stable 0.2. Print a nice message
25        // in this case.
26        const _: () = {
27            compile_error!(
28concat!(r"this format is no longer supported -- please switch to specifying as:
29
30datatest_stable::harness! {
31",
32    $(concat!("    { test = ", stringify!($name), ", root = ", stringify!($root), ", pattern = ", stringify!($pattern), " },\n"),)+
33r"}
34
35note: patterns are now evaluated relative to the provided root, not to the crate root
36"));
37        };
38    }
39}
40
41#[macro_export]
42#[doc(hidden)]
43macro_rules! harness_collect {
44    // Gather `test`
45    (@gather_test
46        $requirements:expr,
47        // Note: here and below, rest always ends with at least 1 comma
48        { test = $test:path, $($rest:tt)* } =>
49        { }
50    ) => {
51        $crate::harness_collect!(@gather_root
52            $requirements,
53            { $($rest)* } =>
54            { test = $test, }
55        );
56    };
57
58    // `test` not found
59    (@gather_test
60        $requirements:expr,
61        { $key:ident $($rest:tt)* } =>
62        { }
63    ) => {
64        compile_error!(concat!("expected `test`, found `", stringify!($key), "`"));
65    };
66
67    // No remaining arguments
68    (@gather_test
69        $requirements:expr,
70        { $(,)* } =>
71        { }
72    ) => {
73        compile_error!("expected `test`, but ran out of arguments");
74    };
75
76    // Something that isn't an identifier
77    (@gather_test
78        $requirements:expr,
79        { $($rest:tt)* } =>
80        { }
81    ) => {
82        compile_error!(concat!("expected `test`, found non-identifier token: (rest: ", stringify!($($rest)*), ")"));
83    };
84
85    // Gather `root`
86    (@gather_root
87        $requirements:expr,
88        { root = $root:expr, $($rest:tt)* } =>
89        { $($collected:tt)* }
90    ) => {
91        $crate::harness_collect!(@gather_pattern
92            $requirements,
93            { $($rest)* } =>
94            { $($collected)* root = $root, }
95        );
96    };
97
98    // `root` not found
99    (@gather_root
100        $requirements:expr,
101        { $key:ident $($rest:tt)* } =>
102        { $($collected:tt)* }
103    ) => {
104        compile_error!(concat!("expected `root`, found `", stringify!($key), "`"));
105    };
106
107    // No remaining arguments
108    (@gather_root
109        $requirements:expr,
110        { $(,)* } =>
111        { $($collected:tt)* }
112    ) => {
113        compile_error!(concat!("expected `root`, but ran out of arguments (collected: ", stringify!($($collected)*), ")"));
114    };
115
116    // Something that isn't an identifier
117    (@gather_root
118        $requirements:expr,
119        { $($rest:tt)* } =>
120        { $($collected:tt)* }
121    ) => {
122        compile_error!(concat!("expected `root`, found non-identifier token (rest: ", stringify!($($rest)*), ")"));
123    };
124
125    // Gather pattern
126    (@gather_pattern
127        $requirements:expr,
128        { pattern = $pattern:expr, $($rest:tt)* } =>
129        { $($collected:tt)* }
130    ) => {
131        $crate::harness_collect!(@finish
132            $requirements,
133            { $($rest)* } =>
134            { $($collected)* pattern = $pattern, }
135        );
136    };
137
138    // `pattern` not found
139    (@gather_pattern
140        $requirements:expr,
141        { $key:ident $($rest:tt)* } =>
142        { $($collected:tt)* }
143    ) => {
144        compile_error!(concat!("expected `pattern`, found `", stringify!($key), "`"));
145    };
146
147    // `pattern` not found: no remaining arguments
148    (@gather_pattern
149        $requirements:expr,
150        { $(,)* } =>
151        { $($collected:tt)* }
152    ) => {
153        $crate::harness_collect!(@finish
154            $requirements,
155            { } =>
156            { $($collected)* pattern = ".*", }
157        );
158    };
159
160    // Something that isn't an identifier
161    (@gather_pattern
162        $requirements:expr,
163        { $($rest:tt)* } =>
164        { $($collected:tt)* }
165    ) => {
166        compile_error!(concat!("expected `pattern`, found non-identifier token (rest: ", stringify!($($rest)*), ")"));
167    };
168
169    // Finish - no more arguments allowed
170    (@finish
171        $requirements:expr,
172        { $(,)* } =>
173        { test = $test:path, root = $root:expr, pattern = $pattern:expr, }
174    ) => {
175        $requirements.push(
176            $crate::Requirements::new(
177                $test.kind().resolve($test),
178                stringify!($test).to_string(),
179                $root.resolve_data_source(),
180                $pattern.to_string()
181            )
182        );
183    };
184
185    // Finish - unexpected extra arguments
186    (@finish
187        $requirements:expr,
188        { $($unexpected:tt)+ } =>
189        { $($collected:tt)* }
190    ) => {
191        compile_error!(concat!("unexpected extra arguments: ", stringify!($($unexpected)+)));
192    };
193}