From b5821a7d375a49f720a6c9f94a5f976178d9a3d6 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Thu, 12 Sep 2024 10:02:52 -0400 Subject: [PATCH 1/4] Mutate proc-macro crates Probably fixes https://github.com/sourcefrog/cargo-mutants/issues/406 but still needs tests --- src/workspace.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/workspace.rs b/src/workspace.rs index f1f69a90..b5e6ee10 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -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. From ce01987c18de78c7e4f71e54969b9370a42cd226 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Sat, 14 Sep 2024 10:57:11 -0400 Subject: [PATCH 2/4] Test case for mutating proc macro --- Cargo.toml | 1 + testdata/proc_macro/Cargo.toml | 12 ++++ testdata/proc_macro/README.md | 3 + testdata/proc_macro/src/lib.rs | 13 ++++ testdata/proc_macro/tests/macro.rs | 11 +++ ...st__list_mutants_in_all_trees_as_json.snap | 69 ++++++++++++++++++- ...st__list_mutants_in_all_trees_as_text.snap | 9 ++- 7 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 testdata/proc_macro/Cargo.toml create mode 100644 testdata/proc_macro/README.md create mode 100644 testdata/proc_macro/src/lib.rs create mode 100644 testdata/proc_macro/tests/macro.rs diff --git a/Cargo.toml b/Cargo.toml index 72c064df..0602f52c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", diff --git a/testdata/proc_macro/Cargo.toml b/testdata/proc_macro/Cargo.toml new file mode 100644 index 00000000..11175ff3 --- /dev/null +++ b/testdata/proc_macro/Cargo.toml @@ -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" diff --git a/testdata/proc_macro/README.md b/testdata/proc_macro/README.md new file mode 100644 index 00000000..9bdc0e25 --- /dev/null +++ b/testdata/proc_macro/README.md @@ -0,0 +1,3 @@ +# `testdata/proc_macro` + +An example of mutating a proc macro, and catching those mutations from tests. diff --git a/testdata/proc_macro/src/lib.rs b/testdata/proc_macro/src/lib.rs new file mode 100644 index 00000000..598dac4f --- /dev/null +++ b/testdata/proc_macro/src/lib.rs @@ -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() +} diff --git a/testdata/proc_macro/tests/macro.rs b/testdata/proc_macro/tests/macro.rs new file mode 100644 index 00000000..5deeadb1 --- /dev/null +++ b/testdata/proc_macro/tests/macro.rs @@ -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); +} diff --git a/tests/snapshots/list__list_mutants_in_all_trees_as_json.snap b/tests/snapshots/list__list_mutants_in_all_trees_as_json.snap index bac0a094..ebe6acbe 100644 --- a/tests/snapshots/list__list_mutants_in_all_trees_as_json.snap +++ b/tests/snapshots/list__list_mutants_in_all_trees_as_json.snap @@ -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 @@ -9611,5 +9678,3 @@ expression: buf } ] ``` - - diff --git a/tests/snapshots/list__list_mutants_in_all_trees_as_text.snap b/tests/snapshots/list__list_mutants_in_all_trees_as_text.snap index 2e8c9923..59ed8b8c 100644 --- a/tests/snapshots/list__list_mutants_in_all_trees_as_text.snap +++ b/tests/snapshots/list__list_mutants_in_all_trees_as_text.snap @@ -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 ``` @@ -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 ``` - - From 6a11ad9a3289bc371076ac5c87c91ca149a2b07d Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Mon, 30 Sep 2024 08:32:05 -0700 Subject: [PATCH 3/4] Test proc_macro tree --- tests/main.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/main.rs b/tests/main.rs index c73ce782..0d881b46 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -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"); From 1a7c70df685ddc943922256c0b49aa9b14322d73 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Mon, 30 Sep 2024 08:47:52 -0700 Subject: [PATCH 4/4] Docs about proc_macros --- NEWS.md | 2 ++ book/src/SUMMARY.md | 1 + book/src/macros.md | 5 +++++ 3 files changed, 8 insertions(+) create mode 100644 book/src/macros.md diff --git a/NEWS.md b/NEWS.md index 2362d8ec..44f4c7e6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ ## Unreleased +- New: Mutate `proc_macro` targets and functions. + - 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. - New: `--profile` option allows selecting a Cargo profile. In particular, it's recommended that you can use `--profile=mutants` and configure a custom profile in your `Cargo.toml` to optimize the build for mutants, by turning off debug symbols. diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 2dd284f0..70adbab1 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -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) diff --git a/book/src/macros.md b/book/src/macros.md new file mode 100644 index 00000000..48b328b5 --- /dev/null +++ b/book/src/macros.md @@ -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.