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

feat: Skip calls to named function/methods #444

Merged
merged 16 commits into from
Nov 18, 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
105 changes: 101 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ serde_json = "1.0.117"
similar = "2.1"
strum = { version = "0.26", features = ["derive"] }
tempfile = "3.8"
test-log = { version = "0.2.16", features = [ "trace" ] }
time = "0.3"
toml = "0.8"
tracing = "0.1.40"
Expand Down
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# cargo-mutants changelog

## Unreleased

- Changed: The arguments of calls to functions or methods named `with_capacity` are not mutated by default. This can be turned off with `--skip-calls-defaults=false` on the command line or `skip_calls_defaults = false` in `.cargo/mutants.toml`.

- New: `--skip-calls=NAME,NAME` on the command line or `skip_calls = [NAMES..]` in `.cargo/mutants.toml` allows configuring other functions whose calls should never be mutated.

## 24.11.0

- New: `--test-workspace` and `--test-package` arguments and config options support projects whose tests live in a different package.
Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [The `mutants.out` directory](mutants-out.md)
- [Skipping untestable code](skip.md)
- [Skipping functions with an attribute](attrs.md)
- [Skipping function calls](skip_calls.md)
- [Filtering files](skip_files.md)
- [Filtering functions and mutants](filter_mutants.md)
- [Controlling cargo-mutants](controlling.md)
Expand Down
37 changes: 37 additions & 0 deletions book/src/skip_calls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Skipping function calls

Using the `--skip-calls` argument and config key you can tell cargo-mutants not to mutate the arguments to calls to specific named functions and methods.

For example:

```sh
cargo mutants --skip-calls=skip_this,and_this
```

or in `.cargo/mutants.toml`

```toml
skip_calls = ["skip_this", "and_this"]
```

The command line arguments are added to the values specified in the configuration.

The names given in the option and argument are matched against the final component of the path in each call, disregarding any type parameters. For example, the default value of `with_capacity` will match `std::vec::Vec::<String>::with_capacity(10)`.

This is separate from [skipping mutation of the body of a function](attrs.md), and only affects the generation of mutants within the call expression, typically in its arguments.

By default, calls to functions called `with_capacity` are not mutated. The defaults can be turned off using `--skip-calls-defaults=false`.

## `with_capacity`

The motivating example for this feature is Rust's `with_capacity` function on `Vec` and other collections, which preallocates capacity for a slight performance gain.

```rust
let mut v = Vec::with_capacity(4 * n);
```

cargo-mutants normally mutates expressions in function calls, and in this case it will try mutating the capacity expression to `4 / n` etc.

These mutations would change the program behavior. Assuming the original calculation is correct the mutation then the mutation will likely be wrong.

However, many authors may feel that preallocating the estimated memory needs is worth doing but not worth specifically writing tests or assertions for, and so they would like to skip generating mutants in any calls to these functions.
6 changes: 6 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ pub struct Config {
pub minimum_test_timeout: Option<f64>,
/// Cargo profile.
pub profile: Option<String>,
/// Skip calls to functions or methods with these names.
///
/// This is combined with values from the --skip-calls argument.
pub skip_calls: Vec<String>,
/// Use built-in defaults for `skip_calls` in addition to any explicit values.
pub skip_calls_defaults: Option<bool>,
/// Run tests from these packages for all mutants.
pub test_package: Vec<String>,
/// Choice of test tool: cargo or nextest.
Expand Down
4 changes: 1 addition & 3 deletions src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ pub fn list_mutants(mutants: &[Mutant], options: &Options) -> String {
// TODO: Do we need to check this? Could the console library strip them if they're not
// supported?
let colors = options.colors.active_stdout();
// let mut out = String::with_capacity(200 * mutants.len());
// TODO: Use with_capacity when we can have mutants skip it (#315
let mut out = String::new();
let mut out = String::with_capacity(200 * mutants.len());
for mutant in mutants {
if colors {
out.push_str(&mutant.to_styled_string(options.show_line_col));
Expand Down
17 changes: 17 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,23 @@ pub struct Args {
#[arg(long, help_heading = "Execution")]
shard: Option<Shard>,

/// Skip calls to functions and methods named in this list.
///
/// The list may contain comma-separated names and may be repeated.
///
/// If a qualified path is given in the source then this matches only the final component,
/// and it ignores type parameters.
///
/// This value is combined with the names from the config `skip_calls` key.
#[arg(long, help_heading = "Filters")]
skip_calls: Vec<String>,

/// Use built-in defaults for `skip_calls`, in addition to any explicit values.
///
/// The default is `with_capacity`.
#[arg(long)]
skip_calls_defaults: Option<bool>,

/// Run tests from these packages for all mutants.
#[arg(long, help_heading = "Tests")]
test_package: Vec<String>,
Expand Down
Loading