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