Skip to content

Commit

Permalink
Mutate tuples into the product of element types
Browse files Browse the repository at this point in the history
  • Loading branch information
sourcefrog committed Sep 15, 2023
1 parent 6723877 commit cd64f27
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 1 deletion.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
- Mutate functions returning `&[T]` and `&mut [T]` to return leaked vecs
of values.

- Mutate `(A, B, C, ...)` into the product of all replacements for
`a, b, c, ...`

## 23.9.0

- Fixed a bug causing an assertion failure when cargo-mutants was run from a
Expand Down
1 change: 1 addition & 0 deletions book/src/mutants.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ More mutation genres and patterns will be added in future releases.
| `&[T]`, `&mut [T]`| Leaked empty and one-element vecs |
| `&T` | `&...` (all replacements for T) |
| `HttpResponse` | `HttpResponse::Ok().finish` |
| `(A, B, ...)` | `(a, b, ...)` for the product of all replacements of A, B, ... |
| (any other) | `Default::default()` |

`...` in the mutation patterns indicates that the type is recursively mutated.
Expand Down
37 changes: 36 additions & 1 deletion src/fnvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,17 @@ fn type_replacements(type_: &Type, error_exprs: &[Expr]) -> impl Iterator<Item =
},
Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {
vec![quote! { () }]
// TODO: Also recurse into non-empty tuples.
}
Type::Tuple(TypeTuple { elems, .. }) => {
// Generate the cartesian product of replacements of every type within the tuple.
elems
.iter()
.map(|elem| type_replacements(elem, error_exprs).collect_vec())
.multi_cartesian_product()
.map(|reps| {
quote! { ( #( #reps ),* ) }
})
.collect_vec()
}
Type::Never(_) => {
vec![]
Expand Down Expand Up @@ -544,6 +554,31 @@ mod test {
);
}

#[test]
fn tuple_combinations() {
check_replacements(
parse_quote! { -> (bool, usize) },
&[],
&["(true, 0)", "(true, 1)", "(false, 0)", "(false, 1)"],
)
}

#[test]
fn tuple_combination_longer() {
check_replacements(
parse_quote! { -> (bool, Option<String>) },
&[],
&[
"(true, None)",
"(true, Some(String::new()))",
r#"(true, Some("xyzzy".into()))"#,
"(false, None)",
"(false, Some(String::new()))",
r#"(false, Some("xyzzy".into()))"#,
],
)
}

fn check_replacements(return_type: ReturnType, error_exprs: &[Expr], expected: &[&str]) {
assert_eq!(
return_type_replacements(&return_type, error_exprs)
Expand Down

0 comments on commit cd64f27

Please sign in to comment.