Skip to content
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

Mutate proc macro functions #415

Merged
merged 5 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ exclude = [
"testdata/override_dependency",
"testdata/package-fails/",
"testdata/patch_dependency",
"testdata/proc_macro",
"testdata/relative_dependency",
"testdata/replace_dependency",
"testdata/small_well_tested",
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# cargo-mutants changelog

## Unreleased

- New: Mutate `proc_macro` targets and functions.

## 24.9.0

- Fixed: Avoid generating empty string elements in `ENCODED_RUSTFLAGS` when `--cap-lints` is set. In some situations these could cause a compiler error complaining about the empty argument.
Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [Strict lints](lints.md)
- [Generating mutants](mutants.md)
- [Error values](error-values.md)
- [Macros](macros.md)
- [Improving performance](performance.md)
- [Parallelism](parallelism.md)
- [Jobserver](jobserver.md)
Expand Down
5 changes: 5 additions & 0 deletions book/src/macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Mutating code using macros

cargo-mutants will mutate the contents of `#[proc_macro]` functions defined in the current crate, and run tests to see if those mutations are caught.

cargo-mutants does not currently mutate calls to macros, or the expansion of a macro, or the definition of declarative `macro_rules` macros. As a result on code that is mostly produced by macro expansion it may not find many mutation opportunities.
7 changes: 6 additions & 1 deletion src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,12 @@ fn direct_package_sources(
}

fn should_mutate_target(target: &cargo_metadata::Target) -> bool {
target.kind.iter().any(|k| k.ends_with("lib") || k == "bin")
for kind in target.kind.iter() {
if kind == "bin" || kind == "proc-macro" || kind.ends_with("lib") {
return true;
}
}
false
}

/// Return the path of the workspace or package directory enclosing a given directory.
Expand Down
12 changes: 12 additions & 0 deletions testdata/proc_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "cargo-mutants-testdata-proc-macro"
version = "0.0.0"
edition = "2021"
license = "MIT"
publish = false

[lib]
proc-macro = true

[dependencies]
quote = "1.0"
3 changes: 3 additions & 0 deletions testdata/proc_macro/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `testdata/proc_macro`

An example of mutating a proc macro, and catching those mutations from tests.
13 changes: 13 additions & 0 deletions testdata/proc_macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::iter::once;

use proc_macro::{Literal, TokenStream, TokenTree};

/// Count the number of items in a static array.
#[proc_macro]
pub fn static_len(item: TokenStream) -> TokenStream {
let count = item
.into_iter()
.filter(|tt| !matches!(tt, TokenTree::Punct(p) if p.as_char() == ','))
.count();
once(TokenTree::Literal(Literal::usize_unsuffixed(count))).collect()
}
11 changes: 11 additions & 0 deletions testdata/proc_macro/tests/macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cargo_mutants_testdata_proc_macro::static_len;

#[test]
fn static_len() {
assert_eq!(static_len!(2, 3, 4, 5), 4);
}

#[test]
fn static_len_empty() {
assert_eq!(static_len!(), 0);
}
14 changes: 14 additions & 0 deletions tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,20 @@ fn cdylib_tree_is_well_tested() {
}));
}

#[test]
fn proc_macro_tree_is_well_tested() {
let tmp_src_dir = copy_of_testdata("proc_macro");
run()
.arg("mutants")
.args(["--no-times", "--no-shuffle", "-v", "-V"])
.current_dir(tmp_src_dir.path())
.assert()
.success()
.stdout(predicate::str::contains(
"2 mutants tested: 1 caught, 1 unviable",
));
}

#[test]
fn well_tested_tree_finds_no_problems() {
let tmp_src_dir = copy_of_testdata("well_tested");
Expand Down
69 changes: 67 additions & 2 deletions tests/snapshots/list__list_mutants_in_all_trees_as_json.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4768,6 +4768,73 @@ expression: buf
]
```

## testdata/proc_macro

```json
[
{
"file": "src/lib.rs",
"function": {
"function_name": "static_len",
"return_type": "-> TokenStream",
"span": {
"end": {
"column": 2,
"line": 13
},
"start": {
"column": 1,
"line": 5
}
}
},
"genre": "FnValue",
"package": "cargo-mutants-testdata-proc-macro",
"replacement": "Default::default()",
"span": {
"end": {
"column": 73,
"line": 12
},
"start": {
"column": 5,
"line": 8
}
}
},
{
"file": "src/lib.rs",
"function": {
"function_name": "static_len",
"return_type": "-> TokenStream",
"span": {
"end": {
"column": 2,
"line": 13
},
"start": {
"column": 1,
"line": 5
}
}
},
"genre": "UnaryOperator",
"package": "cargo-mutants-testdata-proc-macro",
"replacement": "",
"span": {
"end": {
"column": 23,
"line": 10
},
"start": {
"column": 22,
"line": 10
}
}
}
]
```

## testdata/relative_dependency

```json
Expand Down Expand Up @@ -9611,5 +9678,3 @@ expression: buf
}
]
```


9 changes: 7 additions & 2 deletions tests/snapshots/list__list_mutants_in_all_trees_as_text.snap
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,13 @@ src/lib.rs:7:7: replace % with / in is_even
src/lib.rs:7:7: replace % with + in is_even
```

## testdata/proc_macro

```
src/lib.rs:8:5: replace static_len -> TokenStream with Default::default()
src/lib.rs:10:22: delete ! in static_len
```

## testdata/relative_dependency

```
Expand Down Expand Up @@ -523,5 +530,3 @@ main2/src/main.rs:10:5: replace triple_3 -> i32 with 0
main2/src/main.rs:10:5: replace triple_3 -> i32 with 1
main2/src/main.rs:10:5: replace triple_3 -> i32 with -1
```