Expand description
This is a small library that enables section-style testing in Rust. Section-style testing makes writing many similar test cases easy, natural, and concise.
Each top-level section test is run repeatedly, once for every unique section inside the test. This is more expressive and natural than fixtures because it lets you use local variables from parent scopes inside a section and because you can nest sections to an arbitrary depth.
Here’s an example:
#[macro_use]
extern crate section_testing;
enable_sections! {
#[test]
fn example_test() {
let mut v: Vec<i32> = vec![];
fn check_123(v: &mut Vec<i32>) {
assert_eq!(*v, vec![1, 2, 3]);
if section!("reverse") {
v.reverse();
assert_eq!(*v, vec![3, 2, 1]);
}
if section!("pop+remove+insert+push") {
let three = v.pop().unwrap();
let one = v.remove(0);
v.insert(0, three);
v.push(one);
assert_eq!(*v, vec![3, 2, 1]);
}
}
if section!("push") {
v.push(1);
v.push(2);
v.push(3);
check_123(&mut v);
}
if section!("insert") {
v.insert(0, 3);
v.insert(0, 1);
v.insert(1, 2);
check_123(&mut v);
}
}
}
The enable_sections!
macro modifies the test functions inside of it so
that they run repeatedly until all sections have been visited. The
section!
macro returns a bool
for whether or not that section should be
run this iteration. This example test will check the following combinations:
push
push, reverse
push, pop+remove+insert+push
insert
insert, reverse
insert, pop+remove+insert+push
When a test fails, the enclosing sections will be printed to stderr. Here’s
what happens if we comment out v.push(one);
in the example above:
running 1 test
thread 'example_test' panicked at 'assertion failed: `(left == right)`
left: `[3, 2]`,
right: `[3, 2, 1]`', src/main.rs:30:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- the failure was inside these sections ----
0) "push" at src/main.rs:34
1) "pop+remove+insert+push" at src/main.rs:25
test example_test ... FAILED
Note that like all tests in Rust, a section-style test will stop on the
first failure. This means you will only be able to see the first combination
that failed instead of being able to see all failed combinations. The above
example would have also failed for the combination insert, pop+remove+insert+push
if the other combination hadn’t failed first. This
is because Rust’s built-in test runner has no API for adding new tests at
runtime.