#[test_case("value" => "expected_result" ; "comment")] fn tested_function(s: &str) -> &str { todo!() }
Matrix Example:
#[test_matrix( ["maybe", "works"], 1..=10 ==> "expected result" )] fn tested_function(a: &str, b: u16) { todo!() }
#[test_case("value" => "expected_result" ; "comment")] fn tested_function(s: &str) -> &str { todo!() }
Matrix Example:
#[test_matrix( ["maybe", "works"], 1..=10 ==> "expected result" )] fn tested_function(a: &str, b: u16) { todo!() }
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
Test matrix attribute can be defined as: | ||
|
||
``` | ||
#[test_matrix( | ||
(argument_inputs),+ | ||
(=> modifiers output_matcher)? | ||
)] | ||
``` | ||
|
||
_Test case comment/description is explicitly not allowed for `test_matrix`_ | ||
|
||
# Inputs | ||
The number of inputs mutch match the number of tested function arguments. Each | ||
input can be one or more possible values for the argument. | ||
|
||
## Input Syntax | ||
|
||
### List of values | ||
A list in **array** (`[x, y, ...]`) or **tuple** (`(x, y, ...)`) syntax. The | ||
values can be any valid [expression](https://doc.rust-lang.org/reference/expressions.html). | ||
This includes string (`"value"`) and numeric (`42` or `42usize`) literals, | ||
constants (`FORTY_TWO`), function calls (`sqrt(FORTY_TWO)`), arithmetic | ||
(`FORTY_TWO / 2`) and many other possibilities. | ||
|
||
<details> | ||
|
||
<summary>Common Errors</summary> | ||
|
||
#### Literal values | ||
|
||
Literal values must be all of the same type. Mixed lists will generate an macro usage error: | ||
|
||
```sh | ||
error: All literal values must be of the same type | ||
--> src/lib.rs:5:13 | ||
| | ||
5 | ["one", 1, true,] | ||
| ^ | ||
``` | ||
|
||
#### Expressions | ||
|
||
Other kinds of expressions must return the same type as the test function | ||
argument. A mismatch between expression return type and function argument type | ||
will generate a compiler error pointing to the macro argument as well as the | ||
test function: | ||
|
||
```sh | ||
error[E0308]: mismatched types | ||
--> src/lib.rs:33:15 | ||
| | ||
33 | #[test_matrix(USIZE_CONST)] | ||
| --------------^^^^^^^^^^^-- | ||
| | | | ||
| | expected `i8`, found `usize` | ||
| arguments to this function are incorrect | ||
| | ||
note: function defined here | ||
--> src/lib.rs:34:4 | ||
| | ||
34 | fn wrong_argument_type(x: i8) { | ||
| ^^^^^^^^^^^^^^^^^^^ ----- | ||
help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | ||
| | ||
33 | #[test_matrix(USIZE_CONST.try_into().unwrap())] | ||
| ++++++++++++++++++++ | ||
``` | ||
</details> | ||
### Range | ||
A bounded numeric [range expression](https://doc.rust-lang.org/reference/expressions/range-expr.html) | ||
(e.g. `0..100` or `1..=99`), which will generate argument values for all | ||
integers in the range. Unbounded ranges (e.g. `..100`, `..=99`, or `1..`) are not | ||
allowed, as they would generate an infinite number of test cases. | ||
<details> | ||
<summary>Common Errors</summary> | ||
#### Unbounded range | ||
A provided range must have a beginning and end. | ||
```sh | ||
error: Unbounded ranges are not supported | ||
--> src/lib.rs:18:16 | ||
| | ||
18 | #[test_matrix(1..)] | ||
| ^ | ||
``` | ||
#### Non-literal range bound | ||
Values must be integer literals. A macro error will be generated for non-literal expressions: | ||
```sh | ||
error: Range bounds can only be an integer literal | ||
--> src/lib.rs:13:18 | ||
| | ||
13 | #[test_matrix(1..END)] | ||
| ^^^ | ||
``` | ||
</details> | ||
### Expression (Single Value) | ||
A single expression, which can be used to keep one argument constant while | ||
varying the other test function arguments using a list or range. Expressions | ||
must return a type that is the same as the function argument in that position. | ||
**Note:** Expressions that return `Vec`, `array`, or `tuple` will pass that | ||
type to the test function. The list entries are not expanded into separate test | ||
cases as with the [literal list syntax](#list-of-values) above. | ||
# Output | ||
`test_matrix` uses the [same validation mechanism](Syntax#output) as `test_case`. The validation will be applied to every test case generated by the matrix, regardless of input. See the [`test_case` **Output** documentation](Syntax#output) for details. | ||
# Multiple Matrices | ||
It is possible to use the `test_matrix` macro multiple times on a test function to test separate matrices, perhaps under different configurations: | ||
```rust | ||
const CONFIG_BIG: Config { ... }; | ||
const CONFIG_LITTLE: Config { ... }; | ||
#[test_matrix( | ||
CONFIG_BIG, | ||
[1000, 10000, 100000], | ||
["alpha", "beta"] | ||
)] | ||
#[test_matrix( | ||
CONFIG_LITTLE, | ||
[1, 10, 100], | ||
["alpha", "beta"] | ||
)] | ||
fn test_function(config: Config, n: u64, sector: &str) { | ||
todo!() | ||
} | ||
``` | ||
It is also possible to combine the `test_matrix` macro with the `test_case` | ||
macro to test a matrix of values and add some specific edge cases: | ||
```rust | ||
#[test_matrix( | ||
0..100, | ||
[2, 3, 4] | ||
)] | ||
#[test_case(0, 0 => panics ; "panics on all zeroes")] | ||
fn test_function(x: u64, y: u64) { | ||
todo!() | ||
} | ||
``` | ||
The order of `test_case` and `test_matrix` is not significant; the same set | ||
of test cases will be generated. |