la10736 / rstest

Fixture-based test framework for Rust
Apache License 2.0
1.2k stars 43 forks source link

Automatically test all variants of an enum #264

Open jaques-sam opened 4 months ago

jaques-sam commented 4 months ago

Typically you would do something like:

#[derive(Debug, PartialEq)]
enum Fruit {
    Apple,
    Banana,
    Orange,
}

#[rstest]
#[case(Fruit::Apple)]
#[case(Fruit::Banana)]
fn test_enum_values(#[case] fruit: Fruit) {
    // Test logic here
    assert_ne!(fruit, Fruit::Orange);
}

Is there a nice way of simply giving the enum type only so that all variants are tested (or that none of the variants are forgotten)? The logic above won't give an indication about that. Or otherwise, if it's not easily doable, it could be a feature request.

la10736 commented 4 months ago

No, I should say sadly that there isn't any way to do it today and is not simple to implement it.

rstest procedural macro cannot know the enum definition because is processed on the early stage immediately after the parsing stage and just the AST of the item that's processed is know (in this case the function): the type resolution is a later stage.

Anyway we can think a sub-optimal convoluted approach like the one used in rstest_reuse where an enum annotation generate a macro definition that we can use to generate a #[value] annotation in the signature: example

#[derive(Debug, PartialEq)]
#[rstest::enumerates]
enum Fruit {
    Apple,
    Banana,
    Orange,
}

#[rstest::enumerates(fruit)]
#[rstest]
fn test_enum_values(fruit: Fruit) {
}

That should expand the rstest in

#[rstest]
fn test_enum_values(#[values(Fruit::Apple, Fruit::Banana, Fruit::Orange)] fruit: Fruit) {
}

The sad thing here is that (maybe) I cannot move it the argument annotation but I should annotate that rstest function to be sure to process it before the rstest one.

  1. Maybe I like it... Even if it's not optimal
  2. Should works.... but I'm not sure
  3. I've not time to implement it :cry: in middle term