frondeus / test-case

Rust procedural macro attribute for adding test cases easily
MIT License
614 stars 39 forks source link

feature request: test_case generators #111

Closed jtmoon79 closed 1 year ago

jtmoon79 commented 1 year ago

tl;dr would be great if some primitive test_case generators were possible, e.g. #[test_case(1; 3; "test cases 1 2 and 3")] (made-up syntax).

Problem

For my project, I have a large static vector DATA with complex entries. DATA length corresponds to a global constant DATA_LEN. Each DATA entry carries it's own built-in test case (only in test builds). Previously, I had created one test case and looped on all entries.

#[test]
fn test_DATA_entries() {
    for entry in DATA.iter() {
         assert(...)
    }
}

But I wanted more granular test cases, one test case for each entry in the DATA. So I added #[test_case] declaration for each

#[test_case(0)]
#[test_case(1)]
// ...
#[test_case(70)]
fn test_DATA_entry(index: usize) {
    let entry = &DATA[&index];
    assert(...)
}

However, _I have to manually update the listing of #[test_case] when DATA changes_.

Solution

It would be great if I could have test_case help me generate the test cases, 0 up to DATA_LEN.

const DATA_LEN: usize = 70;

#[test_case(0; DATA_LEN; "a test case for each entry in DATA")]
fn test_DATA_entry(index: usize) {
    let entry = &DATA[&index];
    assert(...)
}

the code snippet would run 70 unique test cases.

Suggestions

I'm imagining some new formatting like

#[test_case(1; 3; "test cases 1 2 and 3")]

Or perhaps a new test_case library export like

#[test_case_generator(1; 3; "test cases 1 2 and 3")]

Or perhaps it has a start, stop, step that takes closures. The stop closure returns Option<T>. When None the test cases stop else pass T to the test case

#[test_case_generator(1, |x| if x > 3 { None } else { Some(x) }, |x| x + 1; "test cases 1 2 and 3")]
jtmoon79 commented 1 year ago

Similar to #94