-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
I want multiple tests to share a single set of cases #37
Comments
What about to use #[rstest_parametrize(num, string,
case(0, "zero"),
case(1, "one")
]
fn mytest(num: i32, string: &str) {
// ...
} Your proposed syntax is really hard to implement (maybe impossible) if you want that every case generate a single test case and not a single test that run all cases. That's because every procedural macro is evaluated one by one and when compiler call I know that you try to handle a reusable case set and I've thought about it a lot but, sadly, I've not found any good way to do it (see #29) ... Anyway I'll take this issue here in case I found a break... |
Maybe you should try a
This is how I imagine this would work: // this code is generated from the code of the original comment
// this function is untouched
fn mytest(case: (i32, &str) {
// ...
}
// this function is generated by macro
fn _rstest_executes_mytest() {
let mut failures = Vec::<rstest::Error>::new();
for case in cases.iter() {
match std::panic::catch_unwind(|| mytest(case)) {
Err(msg) => failures.push(rstest::Error::Panic(msg)),
Ok(result) => {
// result might a Result, or an Option, or just ()
// we should handle them somehow
},
}
}
if failures.is_empty() {
// tell user that the test passes
} else {
// panic! with an error message here
// the error message should tell the user which case failed
}
} |
Ok, but by this approach you have just a test for all cases. This can be a fallback solution that I don't like to much. Have a test for each case give you follow possibilities:
I really take care of this feature but I would like to preserve one test per case rule if I can. |
In general the pattern would be: lazy_static! {
static ref TEST_CASES = ...; // Some computed set of cases.
}
#[rtest_from(TEST_CASES)]
fn test_case(...) {
...
} This isn't just an alternative syntax, it allows computing a dynamic set of cases. In my use case, each test case is derived from a disk directory containing input files and expected output files. Right now, every time I create a new such test directory, I have to also write a silly: #[test]
fn test_foo() {
run_test_using_directory("foo");
} Admittedly using However, this means that Google search did not locate any way to generate a dynamic list of tests... is it even possible? |
I just want to share my cases with various test and turn the list of cases into a dynamic array/vector if need be. For that reason, I would also appreciate other ways to achieve the same goal without dynamic array/vector. One way to potentially doing this is declaring a share macro in place of array/vector. For example: rstest_define! {
list_name(),
case(0, "zero"),
case(1, "one"),
};
#[list_name]
fn mytest(value: i32, name: &str) {
// ...
} should expand into: #[proc_macro_attribute]
fn list_name(attr: TokenStream, item: TokenStream) -> TokenStream {
// ...
}
#[list_name]
fn mytest(value: i32, name: &str) {
// ...
} |
@orenbenkiki AFAIK no ... I've planned to make a new procedural macro to get test cases by glob at compile time but I haven't investigate it yet. I know that you can do it by Follow some open questions:
Maybe the first one works but for the second one I've no much hope..... Can you file a new issue for that? |
@KSXGitHub The macro idea sounds good!!! Can you try a POC for it? I'm really busy on try to close next release and cannot work on it now... sorry |
What is a "POC"? |
@KSXGitHub Sorry I misunderstood your example: you cannot mix procedural macro and normal code in the same crate. Another way is to write a macro that compose a |
Proof Of Concept |
So if I have a static and immutable vector/array (or a const function that return a vector/array), is it possible for a procedural macro to read number of elements of that vector/array? If such thing is possible, the original code snippet can be expanded into: static cases = [
(0, "zero"),
(1, "one"),
];
fn mytest(case: (i32, &str)) {
// ...
}
// for (0, "zero")
#[rstest]
fn mytest_0() {
mytest(cases[0])
}
// for (1, "one")
#[rstest]
fn mytest_1() {
mytest(cases[1])
}
// end |
Unfortunately no :( To understand better procedural macro run just after lexer step and work just with the AST (Abstract Syntax Tree): resolution is not available yet. What we can try to do is express your cases as a macro definition instead of const/static and use this in an other macro to build a |
@KSXGitHub Ok I wrote an example: macro_rules! cases {
($it:item) => { case(1, "one") , case(2, "two")
$it
};
}
macro_rules! parametrize {
( $( $c:item ),* => $it:item ) => {
#[rstest_parametrize(a, b, $($c),* )]
$it
};
}
parametrize!{cases!{} =>
fn mytest(a, b) {
// ...
}
} I omitted lot details and this approach have lot of limitations but can fit your needs. |
The best that I can do now (and work just with git version) use rstest::*;
macro_rules! cases {
( $it:item ) => {
#[rstest_parametrize(a, b, case(1, "one") , case(2, "two"))]
$it
};
}
cases!{
fn t(a: i32, b: &str) {
assert_eq!(&a.to_string(), b)
}
}
cases!{
fn t2(a: i32, b: &str) {
assert_ne!(&a.to_string(), b)
}
} I don't like it but |
Take a look to #67 on how to do it. |
I don't find any useful information in #67. Why the issue was closed? It's still impossible to implement? #[rstest(
a => (0..10).collect(),
b => (0..10).take(2).collect(),
)]
fn test(a: u64, b: u64) {...} |
Ok, I've pointed the wrong ticket. I would point to #66 instead. But |
Problem
I want multiple tests to share a single set of cases
Suggestion: Use a const vector/array as cases
The text was updated successfully, but these errors were encountered: