test_suite_rs/lib.rs
1//! Provides a macro to create a test suite with a setup and teardown function.
2//! Each test block generates a separate test function that will run
3//! setup and teardown functions if provided.
4//!
5//! # Example
6//! ```
7//!
8//! # mod test {
9//! use test_suite_rs::test_suite;
10//!
11//! fn setup() -> (i32, String) {
12//! (43, "my_string".to_owned())
13//! }
14//!
15//! fn teardown() {}
16//!
17//! test_suite! {
18//! - name: test_mod
19//! - setup: setup(i32, String)
20//! - teardown: teardown
21//!
22//! test should_return_true(nbr, my_string) {
23//! assert_eq!(nbr, 43);
24//! assert_eq!(&my_string, "my_string");
25//! }
26//!
27//! test should_return_false {
28//! assert!(true);
29//! }
30//! }
31//! # }
32//!```
33//!
34//! Generates the following code (simplified):
35//!
36//!```
37//! # fn setup() -> (i32, String) {
38//! # (43, "my_string".to_owned())
39//! # }
40//!
41//! # fn teardown() {}
42//!
43//! mod test_mod {
44//! # use std::assert_eq;
45//! use super::*;
46//!
47//! #[test]
48//! fn should_return_true() {
49//! let (nbr, my_string) = setup();
50//!
51//! assert_eq!(nbr, 43);
52//! assert_eq!(&my_string, "my_string");
53//! teardown();
54//! }
55//! }
56
57/// Creates a test suite with a setup and teardown function.
58/// Each test block generates a separate test function that will run
59/// setup and teardown functions if provided.
60///
61/// # Example
62/// ```
63///
64/// # mod test {
65/// use test_suite_rs::test_suite;
66///
67/// fn setup() -> (i32, String) {
68/// (43, "my_string".to_owned())
69/// }
70///
71/// fn teardown() {}
72///
73/// test_suite! {
74/// - name: test_mod
75/// - setup: setup(i32, String)
76/// - teardown: teardown
77///
78/// test should_return_true(nbr, my_string) {
79/// assert_eq!(nbr, 43);
80/// assert_eq!(&my_string, "my_string");
81/// }
82///
83/// test should_return_false {
84/// assert!(true);
85/// }
86/// }
87/// # }
88///```
89///
90/// Generates the following code (simplified):
91///
92///```
93/// # fn setup() -> (i32, String) {
94/// # (43, "my_string".to_owned())
95/// # }
96///
97/// # fn teardown() {}
98///
99/// mod test_mod {
100/// # use std::assert_eq;
101/// use super::*;
102///
103/// #[test]
104/// fn should_return_true() {
105/// let (nbr, my_string) = setup();
106///
107/// assert_eq!(nbr, 43);
108/// assert_eq!(&my_string, "my_string");
109/// teardown();
110/// }
111/// }
112#[macro_export]
113macro_rules! test_suite {
114 (
115 - name: $suite_name:ident
116 $(- setup: $setup:ident $(($($arg_type:ty),+))?)?
117 $(- teardown: $teardown:ident)?
118 $(use $top_level_imports:ident::*;)?
119 $(mod $mod_name:ident {
120 $(use $mod_imports:ident::*;)?
121 $(test $test_name:ident$(($($($arg_name:ident)*),+))? $test:block)*
122 })*
123 ) => {
124 mod $suite_name {
125 $(use super::$setup;)?
126 $(use super::$teardown;)?
127 $(use $top_level_imports::*;)?
128
129 fn __internal_test_suite_setup() $($(-> ($($arg_type),*))?)? {
130 $($setup())?
131 }
132
133 fn __internal_test_suite_teardown() {
134 $($teardown();)?
135 }
136
137 $(
138 mod $mod_name {
139 use super::__internal_test_suite_setup;
140 use super::__internal_test_suite_teardown;
141 $(use $mod_imports::*;)?
142
143 $(
144 #[test]
145 fn $test_name() {
146 // Assign the return value of the setup function to the given names (if specified)
147 $(let ($($($arg_name)*),*) =)? __internal_test_suite_setup();
148 // Running test code
149 let test_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { $test }));
150 // Running teardown function
151 let teardown_result = std::panic::catch_unwind(move || { __internal_test_suite_teardown(); });
152 // Process test results
153 test_result.unwrap();
154 teardown_result.unwrap();
155 }
156 )*
157 }
158 )*
159 }
160 };
161 (
162 - name: $suite_name:ident
163 $(- setup: $setup:ident $(($($arg_type:ty),+))?)?
164 $(- teardown: $teardown:ident)?
165 $(use $top_level_imports:ident::*;)?
166 $(test $test_name:ident$(($($($arg_name:ident)*),+))? $test:block)*
167 ) => {
168 mod $suite_name {
169 $(use super::$setup;)?
170 $(use super::$teardown;)?
171 $(use $top_level_imports::*;)?
172
173 fn __internal_test_suite_setup() $($(-> ($($arg_type),*))?)? {
174 $($setup())?
175 }
176
177 fn __internal_test_suite_teardown() {
178 $($teardown();)?
179 }
180
181 $(
182 #[test]
183 fn $test_name() {
184 // Assign the return value of the setup function to the given names (if specified)
185 $(let ($($($arg_name)*),*) =)? __internal_test_suite_setup();
186 // Running test code
187 let test_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { $test }));
188 // Running teardown function
189 let teardown_result = std::panic::catch_unwind(move || { __internal_test_suite_teardown(); });
190 // Process test results
191 test_result.unwrap();
192 teardown_result.unwrap();
193 }
194 )*
195 }
196 };
197}
198
199#[cfg(test)]
200mod test {
201 fn setup() -> (i32, &'static str) {
202 (43, "my_string")
203 }
204
205 fn teardown() {}
206
207 fn test_func_in_super() -> bool {
208 true
209 }
210
211 test_suite! {
212 - name: test_suite_full
213 - setup: setup(i32, &'static str)
214 - teardown: teardown
215
216 test creates_the_test(nbr, string) {
217 assert_eq!(string, "my_string");
218 assert_eq!(nbr, 43);
219 }
220 }
221
222 test_suite! {
223 - name: test_suite_no_teardown
224 - setup: setup(i32, &'static str)
225
226 test creates_the_test(nbr, string) {
227 assert_eq!(string, "my_string");
228 assert_eq!(nbr, 43);
229 }
230 }
231
232 test_suite! {
233 - name: test_suite_no_setup
234 - teardown: teardown
235
236 use super::*;
237
238 test creates_the_test {
239 assert!(test_func_in_super());
240 }
241 }
242
243 test_suite! {
244 - name: test_suite_mutability
245 - setup: setup(i32, &'static str)
246
247 test creates_the_test(mut nbr, _string) {
248 assert_eq!(nbr, 43);
249 nbr = 100;
250 assert_eq!(nbr, 100);
251 }
252 }
253
254 test_suite! {
255 - name: test_suite_with_mods
256
257 use super::*;
258
259 mod test_mod {
260 use super::*;
261
262 test test1 {
263 assert!(test_func_in_super())
264 }
265
266 test test2 {
267 assert_eq!(1, 1);
268 }
269 }
270 }
271
272 test_suite! {
273 - name: test_suite_with_mods_and_setup
274 - setup: setup(i32, &'static str)
275
276 use super::*;
277
278 mod test_mod {
279 use super::*;
280
281 test test1 {
282 assert!(test_func_in_super())
283 }
284
285 test test2(nbr, _string) {
286 assert_eq!(nbr, 43);
287 }
288 }
289 }
290}