anvil_test/datasets.rs
1//! Pest-style parameterized tests via the `dataset!` macro.
2//!
3//! Pest in Laravel-land lets you write:
4//!
5//! ```php
6//! it('squares numbers', function ($n, $sq) {
7//! expect($n * $n)->toBe($sq);
8//! })->with([[1, 1], [2, 4], [3, 9]]);
9//! ```
10//!
11//! Rust's `#[test]` is rigid about test names and arguments, so we generate
12//! a separate `#[tokio::test]` per row. The `dataset!` macro takes a base test
13//! name, a list of named cases, the parameter list, and the test body.
14//!
15//! ```ignore
16//! use anvilforge::assay::*;
17//!
18//! dataset!(squares_numbers, [
19//! one => (1, 1),
20//! two => (2, 4),
21//! three => (3, 9),
22//! negative => (-3, 9),
23//! ], |(n, sq): (i32, i32)| {
24//! expect(n * n).to_be(sq);
25//! });
26//! ```
27//!
28//! The closure parameter is a single tuple pattern + tuple type. Rust's
29//! declarative macros can't cleanly mix the case-level repetition with a
30//! per-arg parameter list, so we destructure once per generated test.
31//!
32//! Each row becomes its own test:
33//!
34//! - `squares_numbers__one`
35//! - `squares_numbers__two`
36//! - `squares_numbers__three`
37//! - `squares_numbers__negative`
38//!
39//! Async variants are supported by using `dataset!(name, [...], async |...| { ... })`.
40
41/// Generate one `#[test]` per row. Each row is `case_name => (arg1, arg2, ...)`.
42/// The closure parameter is a single tuple pattern + tuple type:
43/// `|(n, sq): (i32, i32)|`. For one-arg cases use `|(n,): (i32,)|`.
44#[macro_export]
45macro_rules! dataset {
46 ($base:ident, [ $($case:ident => $args:tt),* $(,)? ], | $pat:tt : $ty:tt | $body:block) => {
47 $(
48 $crate::paste::paste! {
49 #[test]
50 fn [<$base __ $case>]() {
51 let $pat: $ty = $args;
52 $body
53 }
54 }
55 )*
56 };
57}
58
59/// Async variant — generates `#[tokio::test]` per row.
60#[macro_export]
61macro_rules! dataset_async {
62 ($base:ident, [ $($case:ident => $args:tt),* $(,)? ], async | $pat:tt : $ty:tt | $body:block) => {
63 $(
64 $crate::paste::paste! {
65 #[tokio::test]
66 async fn [<$base __ $case>]() {
67 let $pat: $ty = $args;
68 $body
69 }
70 }
71 )*
72 };
73}