1 //! This crate will help you to write simpler tests by leveraging a software testing concept called
2 //! [test fixtures](https://en.wikipedia.org/wiki/Test_fixture#Software). A fixture is something
3 //! that you can use in your tests to encapsulate a test's dependencies.
4 //!
5 //! The general idea is to have smaller tests that only describe the thing you're testing while you
6 //! hide the auxiliary utilities your tests make use of somewhere else.
7 //! For instance, if you have an application that has many tests with users, shopping baskets, and
8 //! products, you'd have to create a user, a shopping basket, and product every single time in
9 //! every test which becomes unwieldy quickly. In order to cut down on that repetition, you can
10 //! instead use fixtures to declare that you need those objects for your function and the fixtures
11 //! will take care of creating those by themselves. Focus on the important stuff in your tests!
12 //!
13 //! In `rstest` a fixture is a function that can return any kind of valid Rust type. This
14 //! effectively means that your fixtures are not limited by the kind of data they can return.
15 //! A test can consume an arbitrary number of fixtures at the same time.
16 //!
17 //! ## What
18 //!
19 //! The `rstest` crate defines the following procedural macros:
20 //!
21 //! - [`[rstest]`](macro@rstest): Declare that a test or a group of tests that may take
22 //! [fixtures](attr.rstest.html#injecting-fixtures),
23 //! [input table](attr.rstest.html#test-parametrized-cases) or
24 //! [list of values](attr.rstest.html#values-lists).
25 //! - [`[fixture]`](macro@fixture): To mark a function as a fixture.
26 //!
27 //! ## Why
28 //!
29 //! Very often in Rust we write tests like this
30 //!
31 //! ```
32 //! #[test]
33 //! fn should_process_two_users() {
34 //!     let mut repository = create_repository();
35 //!     repository.add("Bob", 21);
36 //!     repository.add("Alice", 22);
37 //!
38 //!     let processor = string_processor();
39 //!     processor.send_all(&repository, "Good Morning");
40 //!
41 //!     assert_eq!(2, processor.output.find("Good Morning").count());
42 //!     assert!(processor.output.contains("Bob"));
43 //!     assert!(processor.output.contains("Alice"));
44 //! }
45 //! ```
46 //!
47 //! By making use of [`[rstest]`](macro@rstest) we can isolate the dependencies `empty_repository` and
48 //! `string_processor` by passing them as fixtures:
49 //!
50 //! ```
51 //! # use rstest::*;
52 //! #[rstest]
53 //! fn should_process_two_users(mut empty_repository: impl Repository,
54 //!                             string_processor: FakeProcessor) {
55 //!     empty_repository.add("Bob", 21);
56 //!     empty_repository.add("Alice", 22);
57 //!
58 //!     string_processor.send_all("Good Morning");
59 //!
60 //!     assert_eq!(2, string_processor.output.find("Good Morning").count());
61 //!     assert!(string_processor.output.contains("Bob"));
62 //!     assert!(string_processor.output.contains("Alice"));
63 //! }
64 //! ```
65 //!
66 //! ... or if you use `"Alice"` and `"Bob"` in other tests, you can isolate `alice_and_bob` fixture
67 //! and use it directly:
68 //!
69 //! ```
70 //! # use rstest::*;
71 //! # trait Repository { fn add(&mut self, name: &str, age: u8); }
72 //! # struct Rep;
73 //! # impl Repository for Rep { fn add(&mut self, name: &str, age: u8) {} }
74 //! # #[fixture]
75 //! # fn empty_repository() -> Rep {
76 //! #     Rep
77 //! # }
78 //! #[fixture]
79 //! fn alice_and_bob(mut empty_repository: impl Repository) -> impl Repository {
80 //!     empty_repository.add("Bob", 21);
81 //!     empty_repository.add("Alice", 22);
82 //!     empty_repository
83 //! }
84 //!
85 //! #[rstest]
86 //! fn should_process_two_users(alice_and_bob: impl Repository,
87 //!                             string_processor: FakeProcessor) {
88 //!     string_processor.send_all("Good Morning");
89 //!
90 //!     assert_eq!(2, string_processor.output.find("Good Morning").count());
91 //!     assert!(string_processor.output.contains("Bob"));
92 //!     assert!(string_processor.output.contains("Alice"));
93 //! }
94 //! ```
95 //!
96 //! ## Injecting fixtures as function arguments
97 //!
98 //! `rstest` functions can receive fixtures by using them as input arguments.
99 //! A function decorated with [`[rstest]`](attr.rstest.html#injecting-fixtures)
100 //! will resolve each argument name by call the fixture function.
101 //! Fixtures should be annotated with the [`[fixture]`](macro@fixture) attribute.
102 //!
103 //! Fixtures will be resolved like function calls by following the standard resolution rules.
104 //! Therefore, an identically named fixture can be use in different context.
105 //!
106 //! ```
107 //! # use rstest::*;
108 //! # trait Repository { }
109 //! # #[derive(Default)]
110 //! # struct DataSet {}
111 //! # impl Repository for DataSet { }
112 //! mod empty_cases {
113 //! # use rstest::*;
114 //! # trait Repository { }
115 //! # #[derive(Default)]
116 //! # struct DataSet {}
117 //! # impl Repository for DataSet { }
118 //!     use super::*;
119 //!
120 //!     #[fixture]
121 //!     fn repository() -> impl Repository {
122 //!         DataSet::default()
123 //!     }
124 //!
125 //!     #[rstest]
126 //!     fn should_do_nothing(repository: impl Repository) {
127 //!         //.. test impl ..
128 //!     }
129 //! }
130 //!
131 //! mod non_trivial_case {
132 //! # use rstest::*;
133 //! # trait Repository { }
134 //! # #[derive(Default)]
135 //! # struct DataSet {}
136 //! # impl Repository for DataSet { }
137 //!     use super::*;
138 //!
139 //!     #[fixture]
140 //!     fn repository() -> impl Repository {
141 //!         let mut ds = DataSet::default();
142 //!         // Fill your dataset with interesting case
143 //!         ds
144 //!     }
145 //!
146 //!     #[rstest]
147 //!     fn should_notify_all_entries(repository: impl Repository) {
148 //!         //.. test impl ..
149 //!     }
150 //! }
151 //!
152 //! ```
153 //!
154 //! Last but not least, fixtures can be injected like we saw in `alice_and_bob` example.
155 //!
156 //! ## Creating parametrized tests
157 //!
158 //! You can use also [`[rstest]`](attr.rstest.html#test-parametrized-cases) to create
159 //! simple table-based tests. Let's see the classic Fibonacci example:
160 //!
161 //! ```
162 //! use rstest::rstest;
163 //!
164 //! #[rstest]
165 //! #[case(0, 0)]
166 //! #[case(1, 1)]
167 //! #[case(2, 1)]
168 //! #[case(3, 2)]
169 //! #[case(4, 3)]
170 //! #[case(5, 5)]
171 //! #[case(6, 8)]
172 //! fn fibonacci_test(#[case] input: u32,#[case] expected: u32) {
173 //!     assert_eq!(expected, fibonacci(input))
174 //! }
175 //!
176 //! fn fibonacci(input: u32) -> u32 {
177 //!     match input {
178 //!         0 => 0,
179 //!         1 => 1,
180 //!         n => fibonacci(n - 2) + fibonacci(n - 1)
181 //!     }
182 //! }
183 //! ```
184 //! This will generate a bunch of tests, one for every `#[case(a, b)]`.
185 //!
186 //! ## Creating a test for each combinations of given values
187 //!
188 //! In some cases you need to test your code for each combinations of some input values. In this
189 //! cases [`[rstest]`](attr.rstest.html#values-lists) give you the ability to define a list
190 //! of values (rust expressions) to use for an arguments.
191 //!
192 //! ```
193 //! # use rstest::rstest;
194 //! # #[derive(PartialEq, Debug)]
195 //! # enum State { Init, Start, Processing, Terminated }
196 //! # #[derive(PartialEq, Debug)]
197 //! # enum Event { Error, Fatal }
198 //! # impl State { fn process(self, event: Event) -> Self { self } }
199 //!
200 //! #[rstest]
201 //! fn should_terminate(
202 //!     #[values(State::Init, State::Start, State::Processing)]
203 //!     state: State,
204 //!     #[values(Event::Error, Event::Fatal)]
205 //!     event: Event
206 //! ) {
207 //!     assert_eq!(State::Terminated, state.process(event))
208 //! }
209 //! ```
210 //!
211 //! This will generate a test for each combination of `state` and `event`.
212 //!
213 //! ## Magic Conversion
214 //!
215 //! If you need a value where its type implement `FromStr()` trait you
216 //! can use a literal string to build it.
217 //!
218 //! ```
219 //! # use rstest::rstest;
220 //! # use std::net::SocketAddr;
221 //! #[rstest]
222 //! #[case("1.2.3.4:8080", 8080)]
223 //! #[case("127.0.0.1:9000", 9000)]
224 //! fn check_port(#[case] addr: SocketAddr, #[case] expected: u16) {
225 //!     assert_eq!(expected, addr.port());
226 //! }
227 //! ```
228 //! You can use this feature also in value list and in fixture default value.
229 
230 #![cfg_attr(use_proc_macro_diagnostic, feature(proc_macro_diagnostic))]
231 extern crate proc_macro;
232 
233 // Test utility module
234 #[cfg(test)]
235 pub(crate) mod test;
236 #[cfg(test)]
237 use rstest_reuse;
238 
239 #[macro_use]
240 mod error;
241 mod parse;
242 mod refident;
243 mod render;
244 mod resolver;
245 mod utils;
246 
247 use syn::{parse_macro_input, ItemFn};
248 
249 use crate::parse::{fixture::FixtureInfo, future::ReplaceFutureAttribute, rstest::RsTestInfo};
250 use parse::ExtendWithFunctionAttrs;
251 use quote::ToTokens;
252 
253 /// Define a fixture that you can use in all `rstest`'s test arguments. You should just mark your
254 /// function as `#[fixture]` and then use it as a test's argument. Fixture functions can also
255 /// use other fixtures.
256 ///
257 /// Let's see a trivial example:
258 ///
259 /// ```
260 /// use rstest::*;
261 ///
262 /// #[fixture]
263 /// fn twenty_one() -> i32 { 21 }
264 ///
265 /// #[fixture]
266 /// fn two() -> i32 { 2 }
267 ///
268 /// #[fixture]
269 /// fn injected(twenty_one: i32, two: i32) -> i32 { twenty_one * two }
270 ///
271 /// #[rstest]
272 /// fn the_test(injected: i32) {
273 ///     assert_eq!(42, injected)
274 /// }
275 /// ```
276 ///
277 /// If the fixture function is an [`async` function](#async) your fixture become an `async`
278 /// fixture.
279 ///
280 /// # Default values
281 ///
282 /// If you need to define argument default value you can use `#[default(expression)]`
283 /// argument's attribute:
284 ///
285 /// ```
286 /// use rstest::*;
287 ///
288 /// #[fixture]
289 /// fn injected(
290 ///     #[default(21)]
291 ///     twenty_one: i32,
292 ///     #[default(1 + 1)]
293 ///     two: i32
294 /// ) -> i32 { twenty_one * two }
295 ///
296 /// #[rstest]
297 /// fn the_test(injected: i32) {
298 ///     assert_eq!(42, injected)
299 /// }
300 /// ```
301 /// The `expression` could be any valid rust expression, even an `async` block if you need.
302 /// Moreover, if the type implements `FromStr` trait you can use a literal string to build it.
303 ///
304 /// ```
305 /// # use rstest::*;
306 /// # use std::net::SocketAddr;
307 /// # struct DbConnection {}
308 /// #[fixture]
309 /// fn db_connection(
310 ///     #[default("127.0.0.1:9000")]
311 ///     addr: SocketAddr
312 /// ) -> DbConnection {
313 ///     // create connection
314 /// # DbConnection{}
315 /// }
316 /// ```
317 ///
318 /// # Async
319 ///
320 /// If you need you can write `async` fixtures to use in your `async` tests. Simply use `async`
321 /// keyword for your function and the fixture become an `async` fixture.
322 ///
323 /// ```
324 /// use rstest::*;
325 ///
326 /// #[fixture]
327 /// async fn async_fixture() -> i32 { 42 }
328 ///
329 ///
330 /// #[rstest]
331 /// async fn the_test(#[future] async_fixture: i32) {
332 ///     assert_eq!(42, async_fixture.await)
333 /// }
334 /// ```
335 /// The `#[future]` argument attribute helps to remove the `impl Future<Output = T>` boilerplate.
336 /// In this case the macro expands it in:
337 ///
338 /// ```
339 /// # use rstest::*;
340 /// # use std::future::Future;
341 /// # #[fixture]
342 /// # async fn async_fixture() -> i32 { 42 }
343 /// #[rstest]
344 /// async fn the_test(async_fixture: impl std::future::Future<Output = i32>) {
345 ///     assert_eq!(42, async_fixture.await)
346 /// }
347 /// ```
348 /// If you need, you can use `#[future]` attribute also with an implicit lifetime reference
349 /// because the macro will replace the implicit lifetime with an explicit one.
350 ///
351 /// # Rename
352 ///
353 /// Sometimes you want to have long and descriptive name for your fixture but you prefer to use a much
354 /// shorter name for argument that represent it in your fixture or test. You can rename the fixture
355 /// using `#[from(short_name)]` attribute like following example:
356 ///
357 /// ```
358 /// use rstest::*;
359 ///
360 /// #[fixture]
361 /// fn long_and_boring_descriptive_name() -> i32 { 42 }
362 ///
363 /// #[rstest]
364 /// fn the_test(#[from(long_and_boring_descriptive_name)] short: i32) {
365 ///     assert_eq!(42, short)
366 /// }
367 /// ```
368 ///
369 /// # Partial Injection
370 ///
371 /// You can also partialy inject fixture dependency using `#[with(v1, v2, ..)]` attribute:
372 ///
373 /// ```
374 /// use rstest::*;
375 ///
376 /// #[fixture]
377 /// fn base() -> i32 { 1 }
378 ///
379 /// #[fixture]
380 /// fn first(base: i32) -> i32 { 1 * base }
381 ///
382 /// #[fixture]
383 /// fn second(base: i32) -> i32 { 2 * base }
384 ///
385 /// #[fixture]
386 /// fn injected(first: i32, #[with(3)] second: i32) -> i32 { first * second }
387 ///
388 /// #[rstest]
389 /// fn the_test(injected: i32) {
390 ///     assert_eq!(-6, injected)
391 /// }
392 /// ```
393 /// Note that injected value can be an arbitrary rust expression. `#[with(v1, ..., vn)]`
394 /// attribute will inject `v1, ..., vn` expression as fixture arguments: all remaining arguments
395 /// will be resolved as fixtures.
396 ///
397 /// Sometimes the return type cannot be infered so you must define it: For the few times you may
398 /// need to do it, you can use the `#[default(type)]`, `#[partial_n(type)]` function attribute
399 /// to define it:
400 ///
401 /// ```
402 /// use rstest::*;
403 /// # use std::fmt::Debug;
404 ///
405 /// #[fixture]
406 /// pub fn i() -> u32 {
407 ///     42
408 /// }
409 ///
410 /// #[fixture]
411 /// pub fn j() -> i32 {
412 ///     -42
413 /// }
414 ///
415 /// #[fixture]
416 /// #[default(impl Iterator<Item=(u32, i32)>)]
417 /// #[partial_1(impl Iterator<Item=(I,i32)>)]
418 /// pub fn fx<I, J>(i: I, j: J) -> impl Iterator<Item=(I, J)> {
419 ///     std::iter::once((i, j))
420 /// }
421 ///
422 /// #[rstest]
423 /// fn resolve_by_default<I: Debug + PartialEq>(mut fx: impl Iterator<Item=I>) {
424 ///     assert_eq!((42, -42), fx.next().unwrap())
425 /// }
426 ///
427 /// #[rstest]
428 /// fn resolve_partial<I: Debug + PartialEq>(#[with(42.0)] mut fx: impl Iterator<Item=I>) {
429 ///     assert_eq!((42.0, -42), fx.next().unwrap())
430 /// }
431 /// ```
432 /// `partial_i` is the fixture used when you inject the first `i` arguments in test call.
433 ///
434 /// # Old _compact_ syntax
435 ///
436 /// There is also a compact form for all previous features. This will mantained for a long time
437 /// but for `fixture` I strongly recomand to migrate your code because you'll pay a little
438 /// verbosity but get back a more readable code.
439 ///
440 /// Follow the previous examples in old _compact_ syntax.
441 ///
442 /// ## Default
443 /// ```
444 /// # use rstest::*;
445 /// #[fixture(twenty_one=21, two=2)]
446 /// fn injected(twenty_one: i32, two: i32) -> i32 { twenty_one * two }
447 /// ```
448 ///
449 /// ## Rename
450 /// ```
451 /// # use rstest::*;
452 /// #[fixture]
453 /// fn long_and_boring_descriptive_name() -> i32 { 42 }
454 ///
455 /// #[rstest(long_and_boring_descriptive_name as short)]
456 /// fn the_test(short: i32) {
457 ///     assert_eq!(42, short)
458 /// }
459 /// ```
460 ///
461 /// ## Partial Injection
462 /// ```
463 /// # use rstest::*;
464 /// # #[fixture]
465 /// # fn base() -> i32 { 1 }
466 /// #
467 /// # #[fixture]
468 /// # fn first(base: i32) -> i32 { 1 * base }
469 /// #
470 /// # #[fixture]
471 /// # fn second(base: i32) -> i32 { 2 * base }
472 /// #
473 /// #[fixture(second(-3))]
474 /// fn injected(first: i32, second: i32) -> i32 { first * second }
475 /// ```
476 /// ## Partial Type Injection
477 /// ```
478 /// # use rstest::*;
479 /// # use std::fmt::Debug;
480 /// #
481 /// # #[fixture]
482 /// # pub fn i() -> u32 {
483 /// #     42
484 /// # }
485 /// #
486 /// # #[fixture]
487 /// # pub fn j() -> i32 {
488 /// #     -42
489 /// # }
490 /// #
491 /// #[fixture(::default<impl Iterator<Item=(u32, i32)>>::partial_1<impl Iterator<Item=(I,i32)>>)]
492 /// pub fn fx<I, J>(i: I, j: J) -> impl Iterator<Item=(I, J)> {
493 ///     std::iter::once((i, j))
494 /// }
495 /// ```
496 
497 #[proc_macro_attribute]
fixture( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream498 pub fn fixture(
499     args: proc_macro::TokenStream,
500     input: proc_macro::TokenStream,
501 ) -> proc_macro::TokenStream {
502     let mut info: FixtureInfo = parse_macro_input!(args as FixtureInfo);
503     let mut fixture = parse_macro_input!(input as ItemFn);
504 
505     let replace_result = ReplaceFutureAttribute::replace(&mut fixture);
506     let extend_result = info.extend_with_function_attrs(&mut fixture);
507 
508     let mut errors = error::fixture(&fixture, &info);
509 
510     if let Err(attrs_errors) = replace_result {
511         attrs_errors.to_tokens(&mut errors);
512     }
513     if let Err(attrs_errors) = extend_result {
514         attrs_errors.to_tokens(&mut errors);
515     }
516 
517     if errors.is_empty() {
518         render::fixture(fixture, info)
519     } else {
520         errors
521     }
522     .into()
523 }
524 
525 /// The attribute that you should use for your tests. Your
526 /// annotated function's arguments can be
527 /// [injected](attr.rstest.html#injecting-fixtures) with
528 /// [`[fixture]`](macro@fixture)s, provided by
529 /// [parametrized cases](attr.rstest.html#test-parametrized-cases)
530 /// or by [value lists](attr.rstest.html#values-lists).
531 ///
532 /// `rstest` attribute can be applied to _any_ function and you can costumize its
533 /// parameters by using function and arguments attributes.
534 ///
535 /// Your test function can use generics, `impl` or `dyn` and like any kind of rust tests:
536 ///
537 /// - return results
538 /// - marked by `#[should_panic]` attribute
539 ///
540 /// If the test function is an [`async` function](#async) `rstest` will run all tests as `async`
541 /// tests. You can use it just with `async-std` and you should include `attributes` in
542 /// `async-std`'s features.
543 ///
544 /// In your test function you can:
545 ///
546 /// - [injecting fixtures](#injecting-fixtures)
547 /// - Generate [parametrized test cases](#test-parametrized-cases)
548 /// - Generate tests for each combination of [value lists](#values-lists)
549 ///
550 /// ## Injecting Fixtures
551 ///
552 /// The simplest case is write a test that can be injected with
553 /// [`[fixture]`](macro@fixture)s. You can just declare all used fixtures by passing
554 /// them as a function's arguments. This can help your test to be neat
555 /// and make your dependecy clear.
556 ///
557 /// ```
558 /// use rstest::*;
559 ///
560 /// #[fixture]
561 /// fn injected() -> i32 { 42 }
562 ///
563 /// #[rstest]
564 /// fn the_test(injected: i32) {
565 ///     assert_eq!(42, injected)
566 /// }
567 /// ```
568 ///
569 /// [`[rstest]`](macro@rstest) procedural macro will desugar it to something that isn't
570 /// so far from
571 ///
572 /// ```
573 /// #[test]
574 /// fn the_test() {
575 ///     let injected=injected();
576 ///     assert_eq!(42, injected)
577 /// }
578 /// ```
579 ///
580 /// If you want to use long and descriptive names for your fixture but prefer to use
581 /// shorter names inside your tests you use rename feature described in
582 /// [fixture rename](attr.fixture.html#rename):
583 ///
584 /// ```
585 /// use rstest::*;
586 ///
587 /// #[fixture]
588 /// fn long_and_boring_descriptive_name() -> i32 { 42 }
589 ///
590 /// #[rstest]
591 /// fn the_test(#[from(long_and_boring_descriptive_name)] short: i32) {
592 ///     assert_eq!(42, short)
593 /// }
594 /// ```
595 ///
596 /// Sometimes is useful to have some parametes in your fixtures but your test would
597 /// override the fixture's default values in some cases. Like in
598 /// [fixture partial injection](attr.fixture.html#partial-injection) you use `#[with]`
599 /// attribute to indicate some fixture's arguments also in `rstest`.
600 ///
601 /// ```
602 /// # struct User(String, u8);
603 /// # impl User { fn name(&self) -> &str {&self.0} }
604 /// use rstest::*;
605 ///
606 /// #[fixture]
607 /// fn user(
608 ///     #[default("Alice")] name: impl AsRef<str>,
609 ///     #[default(22)] age: u8
610 /// ) -> User { User(name.as_ref().to_owned(), age) }
611 ///
612 /// #[rstest]
613 /// fn check_user(#[with("Bob")] user: User) {
614 ///     assert_eq("Bob", user.name())
615 /// }
616 /// ```
617 ///
618 /// ## Test Parametrized Cases
619 ///
620 /// If you would execute your test for a set of input data cases
621 /// you can define the arguments to use and the cases list. Let see
622 /// the classical Fibonacci example. In this case we would give the
623 /// `input` value and the `expected` result for a set of cases to test.
624 ///
625 /// ```
626 /// use rstest::rstest;
627 ///
628 /// #[rstest]
629 /// #[case(0, 0)]
630 /// #[case(1, 1)]
631 /// #[case(2, 1)]
632 /// #[case(3, 2)]
633 /// #[case(4, 3)]
634 /// fn fibonacci_test(#[case] input: u32,#[case] expected: u32) {
635 ///     assert_eq!(expected, fibonacci(input))
636 /// }
637 ///
638 /// fn fibonacci(input: u32) -> u32 {
639 ///     match input {
640 ///         0 => 0,
641 ///         1 => 1,
642 ///         n => fibonacci(n - 2) + fibonacci(n - 1)
643 ///     }
644 /// }
645 /// ```
646 ///
647 /// `rstest` will produce 5 indipendent tests and not just one that
648 /// check every case. Every test can fail indipendently and `cargo test`
649 /// will give follow output:
650 ///
651 /// ```text
652 /// running 5 tests
653 /// test fibonacci_test::case_1 ... ok
654 /// test fibonacci_test::case_2 ... ok
655 /// test fibonacci_test::case_3 ... ok
656 /// test fibonacci_test::case_4 ... ok
657 /// test fibonacci_test::case_5 ... ok
658 ///
659 /// test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
660 /// ```
661 ///
662 /// The cases input values can be arbitrary Rust expresions that return the
663 /// argument type.
664 ///
665 /// ```
666 /// use rstest::rstest;
667 ///
668 /// fn sum(a: usize, b: usize) -> usize { a + b }
669 ///
670 /// #[rstest]
671 /// #[case("foo", 3)]
672 /// #[case(String::from("foo"), 2 + 1)]
673 /// #[case(format!("foo"), sum(2, 1))]
674 /// fn test_len(#[case] s: impl AsRef<str>,#[case] len: usize) {
675 ///     assert_eq!(s.as_ref().len(), len);
676 /// }
677 /// ```
678 ///
679 /// ### Magic Conversion
680 ///
681 /// You can use the magic conversion feature every time you would define a variable
682 /// where its type define `FromStr` trait: test will parse the string to build the value.
683 ///
684 /// ```
685 /// # use rstest::rstest;
686 /// # use std::path::PathBuf;
687 /// # fn count_words(path: PathBuf) -> usize {0}
688 /// #[rstest]
689 /// #[case("resources/empty", 0)]
690 /// #[case("resources/divine_commedy", 101.698)]
691 /// fn test_count_words(#[case] path: PathBuf, #[case] expected: usize) {
692 ///     assert_eq!(expected, count_words(path))
693 /// }
694 /// ```
695 ///
696 /// ### Optional case description
697 ///
698 /// Optionally you can give a _description_ to every case simple by follow `case`
699 /// with `::my_case_description` where `my_case_description` should be a a valid
700 /// Rust ident.
701 ///
702 /// ```
703 /// # use rstest::*;
704 /// #[rstest]
705 /// #[case::zero_base_case(0, 0)]
706 /// #[case::one_base_case(1, 1)]
707 /// #[case(2, 1)]
708 /// #[case(3, 2)]
709 /// fn fibonacci_test(#[case] input: u32,#[case] expected: u32) {
710 ///     assert_eq!(expected, fibonacci(input))
711 /// }
712 ///
713 /// # fn fibonacci(input: u32) -> u32 {
714 /// #     match input {
715 /// #         0 => 0,
716 /// #         1 => 1,
717 /// #         n => fibonacci(n - 2) + fibonacci(n - 1)
718 /// #     }
719 /// # }
720 /// ```
721 ///
722 /// Outuput will be
723 /// ```text
724 /// running 4 tests
725 /// test fibonacci_test::case_1_zero_base_case ... ok
726 /// test fibonacci_test::case_2_one_base_case ... ok
727 /// test fibonacci_test::case_3 ... ok
728 /// test fibonacci_test::case_4 ... ok
729 ///
730 /// test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
731 /// ```
732 ///
733 /// ### Use specific `case` attributes
734 ///
735 /// Every function's attributes that preceding a `#[case]` attribute will
736 /// be used in this test case and all function's attributes that follow the
737 /// last `#[case]` attribute will mark all test cases.
738 ///
739 /// This feature can be use to mark just some cases as `should_panic`
740 /// and choose to have a fine grain on expected panic messages.
741 ///
742 /// In follow example we run 3 tests where the first pass without any
743 /// panic, in the second we catch a panic but we don't care about the message
744 /// and in the third one we also check the panic message.
745 ///
746 /// ```
747 /// use rstest::rstest;
748 ///
749 /// #[rstest]
750 /// #[case::no_panic(0)]
751 /// #[should_panic]
752 /// #[case::panic(1)]
753 /// #[should_panic(expected="expected")]
754 /// #[case::panic_with_message(2)]
755 /// fn attribute_per_case(#[case] val: i32) {
756 ///     match val {
757 ///         0 => assert!(true),
758 ///         1 => panic!("No catch"),
759 ///         2 => panic!("expected"),
760 ///         _ => unreachable!(),
761 ///     }
762 /// }
763 /// ```
764 ///
765 /// Output:
766 ///
767 /// ```text
768 /// running 3 tests
769 /// test attribute_per_case::case_1_no_panic ... ok
770 /// test attribute_per_case::case_3_panic_with_message ... ok
771 /// test attribute_per_case::case_2_panic ... ok
772 ///
773 /// test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
774 /// ```
775 ///
776 /// To mark all your tests as `#[should_panic]` use:
777 ///
778 /// ```
779 /// # use rstest::rstest;
780 /// #[rstest]
781 /// #[case(1)]
782 /// #[case(2)]
783 /// #[case(3)]
784 /// #[should_panic]
785 /// fn fail(#[case] v: u32) { assert_eq!(0, v) }
786 /// ```
787 ///
788 /// ## Values Lists
789 ///
790 /// Another useful way to write a test and execute it for some values
791 /// is to use the values list syntax. This syntax can be usefull both
792 /// for a plain list and for testing all combination of input arguments.
793 ///
794 /// ```
795 /// # use rstest::*;
796 /// # fn is_valid(input: &str) -> bool { true }
797 ///
798 /// #[rstest]
799 /// fn should_be_valid(
800 ///     #[values("Jhon", "alice", "My_Name", "Zigy_2001")]
801 ///     input: &str
802 /// ) {
803 ///     assert!(is_valid(input))
804 /// }
805 /// ```
806 ///
807 /// or
808 ///
809 /// ```
810 /// # use rstest::*;
811 /// # fn valid_user(name: &str, age: u8) -> bool { true }
812 ///
813 /// #[rstest]
814 /// fn should_accept_all_corner_cases(
815 ///     #[values("J", "A", "A________________________________________21")]
816 ///     name: &str,
817 ///     #[values(14, 100)]
818 ///     age: u8
819 /// ) {
820 ///     assert!(valid_user(name, age))
821 /// }
822 /// ```
823 /// where `cargo test` output is
824 ///
825 /// ```text
826 /// running 6 tests
827 /// test should_accept_all_corner_cases::name_1::age_1 ... ok
828 /// test should_accept_all_corner_cases::name_3::age_1 ... ok
829 /// test should_accept_all_corner_cases::name_3::age_2 ... ok
830 /// test should_accept_all_corner_cases::name_2::age_1 ... ok
831 /// test should_accept_all_corner_cases::name_2::age_2 ... ok
832 /// test should_accept_all_corner_cases::name_1::age_2 ... ok
833 ///
834 /// test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
835 /// ```
836 ///
837 /// Also value list implements the magic conversion feature: every time the value type
838 /// implements `FromStr` trait you can use a literal string to define it.
839 ///
840 /// ## Use Parametrize definition in more tests
841 ///
842 /// If you need to use a test list for more than one test you can use
843 /// [`rstest_reuse`](https://crates.io/crates/rstest_reuse) crate.
844 /// With this helper crate you can define a template and use it everywhere.
845 ///
846 /// ```
847 /// # use rstest::rstest;
848 /// # use std::net::SocketAddr;
849 /// #[rstest]
850 /// fn given_port(#[values("1.2.3.4:8000", "4.3.2.1:8000", "127.0.0.1:8000")] addr: SocketAddr) {
851 ///     assert_eq(8000, addr.port())
852 /// }
853 /// ```
854 ///
855 /// ```rust,ignore
856 /// use rstest::rstest;
857 /// use rstest_reuse::{self, *};
858 ///
859 /// #[template]
860 /// #[rstest]
861 /// #[case(2, 2)]
862 /// #[case(4/2, 2)]
863 /// fn two_simple_cases(#[case] a: u32, #[case] b: u32) {}
864 ///
865 /// #[apply(two_simple_cases)]
866 /// fn it_works(#[case] a: u32,#[case] b: u32) {
867 ///     assert!(a == b);
868 /// }
869 /// ```
870 ///
871 /// See [`rstest_reuse`](https://crates.io/crates/rstest_reuse) for more dettails.
872 ///
873 /// ## Async
874 ///
875 /// `rstest` provides out of the box `async` support. Just mark your
876 /// test function as `async` and it'll use `#[async-std::test]` to
877 /// annotate it. This feature can be really useful to build async
878 /// parametric tests using a tidy syntax:
879 ///
880 /// ```
881 /// use rstest::*;
882 /// # async fn async_sum(a: u32, b: u32) -> u32 { a + b }
883 ///
884 /// #[rstest]
885 /// #[case(5, 2, 3)]
886 /// #[should_panic]
887 /// #[case(42, 40, 1)]
888 /// async fn my_async_test(#[case] expected: u32, #[case] a: u32, #[case] b: u32) {
889 ///     assert_eq!(expected, async_sum(a, b).await);
890 /// }
891 /// ```
892 ///
893 /// Currently only `async-std` is supported out of the box. But if you need to use
894 /// another runtime that provide it's own test attribute (i.e. `tokio::test` or
895 /// `actix_rt::test`) you can use it in your `async` test like described in
896 /// [Inject Test Attribute](attr.rstest.html#inject-test-attribute).
897 ///
898 /// To use this feature, you need to enable `attributes` in the `async-std`
899 /// features list in your `Cargo.toml`:
900 ///
901 /// ```toml
902 /// async-std = { version = "1.5", features = ["attributes"] }
903 /// ```
904 ///
905 /// If your test input is an async value (fixture or test parameter) you can use `#[future]`
906 /// attribute to remove `impl Future<Output = T>` boilerplate and just use `T`:
907 ///
908 /// ```
909 /// use rstest::*;
910 /// #[fixture]
911 /// async fn base() -> u32 { 42 }
912 ///
913 /// #[rstest]
914 /// #[case(21, async { 2 })]
915 /// #[case(6, async { 7 })]
916 /// async fn my_async_test(#[future] base: u32, #[case] expected: u32, #[future] #[case] div: u32) {
917 ///     assert_eq!(expected, base.await / div.await);
918 /// }
919 /// ```
920 ///
921 /// ## Inject Test Attribute
922 ///
923 /// If you would like to use another `test` attribute for your test you can simply
924 /// indicate it in your test function's attributes. For instance if you want
925 /// to test some async function with use `actix_rt::test` attribute you can just write:
926 ///
927 /// ```
928 /// use rstest::*;
929 /// use actix_rt;
930 /// use std::future::Future;
931 ///
932 /// #[rstest]
933 /// #[case(2, async { 4 })]
934 /// #[case(21, async { 42 })]
935 /// #[actix_rt::test]
936 /// async fn my_async_test(#[case] a: u32, #[case] #[future] result: u32) {
937 ///     assert_eq!(2 * a, result.await);
938 /// }
939 /// ```
940 /// Just the attributes that ends with `test` (last path segment) can be injected:
941 /// in this case the `#[actix_rt::test]` attribute will replace the standard `#[test]`
942 /// attribute.
943 ///
944 /// ## Putting all Together
945 ///
946 /// All these features can be used together with a mixture of fixture variables,
947 /// fixed cases and bunch of values. For instance, you might need two
948 /// test cases which test for panics, one for a logged in user and one for a guest user.
949 ///
950 /// ```rust
951 /// # enum User { Guest, Logged, }
952 /// # impl User { fn logged(_n: &str, _d: &str, _w: &str, _s: &str) -> Self { Self::Logged } }
953 /// # struct Item {}
954 /// # trait Repository { fn find_items(&self, user: &User, query: &str) -> Result<Vec<Item>, String> { Err("Invalid query error".to_owned()) } }
955 /// # #[derive(Default)] struct InMemoryRepository {}
956 /// # impl Repository for InMemoryRepository {}
957 ///
958 /// use rstest::*;
959 ///
960 /// #[fixture]
961 /// fn repository() -> InMemoryRepository {
962 ///     let mut r = InMemoryRepository::default();
963 ///     // fill repository with some data
964 ///     r
965 /// }
966 ///
967 /// #[fixture]
968 /// fn alice() -> User {
969 ///     User::logged("Alice", "2001-10-04", "London", "UK")
970 /// }
971 ///
972 /// #[rstest]
973 /// #[case::authed_user(alice())] // We can use `fixture` also as standard function
974 /// #[case::guest(User::Guest)]   // We can give a name to every case : `guest` in this case
975 /// #[should_panic(expected = "Invalid query error")] // We whould test a panic
976 /// fn should_be_invalid_query_error(
977 ///     repository: impl Repository,
978 ///     #[case] user: User,
979 ///     #[values("     ", "^%$#@!", "....")]
980 ///     query: &str
981 /// ) {
982 ///     repository.find_items(&user, query).unwrap();
983 /// }
984 /// ```
985 ///
986 /// ## Trace Input Arguments
987 ///
988 /// Sometimes can be very helpful to print all test's input arguments. To
989 /// do it you can use the `#[trace]` function attribute that you can apply
990 /// to all cases or just to some of them.
991 ///
992 /// ```
993 /// use rstest::*;
994 ///
995 /// #[fixture]
996 /// fn injected() -> i32 { 42 }
997 ///
998 /// #[rstest]
999 /// #[trace]
1000 /// fn the_test(injected: i32) {
1001 ///     assert_eq!(42, injected)
1002 /// }
1003 /// ```
1004 ///
1005 /// Will print an output like
1006 ///
1007 /// ```bash
1008 /// Testing started at 14.12 ...
1009 /// ------------ TEST ARGUMENTS ------------
1010 /// injected = 42
1011 /// -------------- TEST START --------------
1012 ///
1013 ///
1014 /// Expected :42
1015 /// Actual   :43
1016 /// ```
1017 /// But
1018 /// ```
1019 /// # use rstest::*;
1020 /// #[rstest]
1021 /// #[case(1)]
1022 /// #[trace]
1023 /// #[case(2)]
1024 /// fn the_test(#[case] v: i32) {
1025 ///     assert_eq!(0, v)
1026 /// }
1027 /// ```
1028 /// will trace just `case_2` input arguments.
1029 ///
1030 /// If you want to trace input arguments but skip some of them that don't
1031 /// implement the `Debug` trait, you can also use the
1032 /// `#[notrace]` argument attribute to skip them:
1033 ///
1034 /// ```
1035 /// # use rstest::*;
1036 /// # struct Xyz;
1037 /// # struct NoSense;
1038 /// #[rstest]
1039 /// #[trace]
1040 /// fn the_test(injected: i32, #[notrace] xyz: Xyz, #[notrace] have_no_sense: NoSense) {
1041 ///     assert_eq!(42, injected)
1042 /// }
1043 /// ```
1044 /// # Old _compact_ syntax
1045 ///
1046 /// `rstest` support also a syntax where all options and configuration can be write as
1047 /// `rstest` attribute arguments. This syntax is a little less verbose but make
1048 /// composition harder: for istance try to add some cases to a `rstest_reuse` template
1049 /// is really hard.
1050 ///
1051 /// So we'll continue to maintain the old syntax for a long time but we strongly encourage
1052 /// to switch your test in the new form.
1053 ///
1054 /// Anyway, here we recall this syntax and rewrite the previous example in the _compact_ form.
1055 ///
1056 /// ```text
1057 /// rstest(
1058 ///     arg_1,
1059 ///     ...,
1060 ///     arg_n[,]
1061 ///     [::attribute_1[:: ... [::attribute_k]]]
1062 /// )
1063 /// ```
1064 /// Where:
1065 ///
1066 /// - `arg_i` could be one of the follow
1067 ///   - `ident` that match to one of function arguments for parametrized cases
1068 ///   - `case[::description](v1, ..., vl)` a test case
1069 ///   - `fixture(v1, ..., vl) [as argument_name]` where fixture is the injected
1070 /// fixture and argument_name (default use fixture) is one of function arguments
1071 /// that and `v1, ..., vl` is a partial list of fixture's arguments
1072 ///   - `ident => [v1, ..., vl]` where `ident` is one of function arguments and
1073 /// `v1, ..., vl` is a list of values for ident
1074 /// - `attribute_j` a test attribute like `trace` or `notrace`
1075 ///
1076 /// ## Fixture Arguments
1077 ///
1078 /// ```
1079 /// # struct User(String, u8);
1080 /// # impl User { fn name(&self) -> &str {&self.0} }
1081 /// # use rstest::*;
1082 /// #
1083 /// # #[fixture]
1084 /// # fn user(
1085 /// #     #[default("Alice")] name: impl AsRef<str>,
1086 /// #     #[default(22)] age: u8
1087 /// # ) -> User { User(name.as_ref().to_owned(), age) }
1088 /// #
1089 /// #[rstest(user("Bob"))]
1090 /// fn check_user(user: User) {
1091 ///     assert_eq("Bob", user.name())
1092 /// }
1093 /// ```
1094 ///
1095 /// ## Fixture Rename
1096 /// ```
1097 /// # use rstest::*;
1098 /// #[fixture]
1099 /// fn long_and_boring_descriptive_name() -> i32 { 42 }
1100 ///
1101 /// #[rstest(long_and_boring_descriptive_name as short)]
1102 /// fn the_test(short: i32) {
1103 ///     assert_eq!(42, short)
1104 /// }
1105 /// ```
1106 ///
1107 /// ## Parametrized
1108 ///
1109 /// ```
1110 /// # use rstest::*;
1111 /// #[rstest(input, expected,
1112 ///     case::zero_base_case(0, 0),
1113 ///     case::one_base_case(1, 1),
1114 ///     case(2, 1),
1115 ///     case(3, 2),
1116 ///     #[should_panic]
1117 ///     case(4, 42)
1118 /// )]
1119 /// fn fibonacci_test(input: u32, expected: u32) {
1120 ///     assert_eq!(expected, fibonacci(input))
1121 /// }
1122 ///
1123 /// # fn fibonacci(input: u32) -> u32 {
1124 /// #     match input {
1125 /// #         0 => 0,
1126 /// #         1 => 1,
1127 /// #         n => fibonacci(n - 2) + fibonacci(n - 1)
1128 /// #     }
1129 /// # }
1130 /// ```
1131 ///
1132 /// ## Values Lists
1133 ///
1134 /// ```
1135 /// # use rstest::*;
1136 /// # fn is_valid(input: &str) -> bool { true }
1137 ///
1138 /// #[rstest(
1139 ///     input => ["Jhon", "alice", "My_Name", "Zigy_2001"]
1140 /// )]
1141 /// fn should_be_valid(input: &str) {
1142 ///     assert!(is_valid(input))
1143 /// }
1144 /// ```
1145 ///
1146 /// ## `trace` and `notrace`
1147 ///
1148 /// ```
1149 /// # use rstest::*;
1150 /// # struct Xyz;
1151 /// # struct NoSense;
1152 /// #[rstest(::trace::notrace(xzy, have_no_sense))]
1153 /// fn the_test(injected: i32, xyz: Xyz, have_no_sense: NoSense) {
1154 ///     assert_eq!(42, injected)
1155 /// }
1156 /// ```
1157 ///
1158 #[proc_macro_attribute]
rstest( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream1159 pub fn rstest(
1160     args: proc_macro::TokenStream,
1161     input: proc_macro::TokenStream,
1162 ) -> proc_macro::TokenStream {
1163     let mut test = parse_macro_input!(input as ItemFn);
1164     let mut info = parse_macro_input!(args as RsTestInfo);
1165 
1166     let replace_result = ReplaceFutureAttribute::replace(&mut test);
1167     let extend_result = info.extend_with_function_attrs(&mut test);
1168 
1169     let mut errors = error::rstest(&test, &info);
1170 
1171     if let Err(attrs_errors) = replace_result {
1172         attrs_errors.to_tokens(&mut errors);
1173     }
1174     if let Err(attrs_errors) = extend_result {
1175         attrs_errors.to_tokens(&mut errors);
1176     }
1177 
1178     if errors.is_empty() {
1179         if info.data.has_list_values() {
1180             render::matrix(test, info)
1181         } else if info.data.has_cases() {
1182             render::parametrize(test, info)
1183         } else {
1184             render::single(test, info)
1185         }
1186     } else {
1187         errors
1188     }
1189     .into()
1190 }
1191