Rust Mutation Testing Extension
This extension provides rust_mutation_test, a rule that mutation-tests a
rust_library by compiling and running tests against automatically-mutated
source variants.
Primary API docs are in defs.bzl and generated site docs
(rust_mutation.md in the rules_rust docs book).
Overview
rust_mutation_test:
- Reads crate metadata from the target
rust_library. - Builds rustc arguments via rules_rust's canonical compile wiring
(
collect_inputs+construct_arguments). - Enumerates mutants with
cargo-mutantsJSON output. - Stages crate sources and compile-time input files.
- Runs a baseline compile+test.
- Runs compile+test for each mutant.
- Reports mutants as
CAUGHTorSURVIVED.
Status meanings:
CAUGHT: mutant fails to compile or tests fail.SURVIVED: mutant compiles and tests pass.- Baseline/infrastructure failures fail the Bazel test immediately.
Current behavior:
- By default, any survived mutant fails the Bazel target.
- Set
allow_survivors = Trueto report survivors without failing the target. - If mutation generation produces zero mutants, the Bazel target succeeds and
prints
No mutations generated..
Setup
Bzlmod
bazel_dep(name = "rules_rust_mutants", version = "{SEE_RELEASE_NOTES}")
WORKSPACE
load("@rules_rust_mutants//:repositories.bzl", "rust_mutation_dependencies")
rust_mutation_dependencies()
Usage
load("@rules_rust//rust:defs.bzl", "rust_library")
load("@rules_rust_mutants//:defs.bzl", "rust_mutation_test")
rust_library(
name = "my_lib",
srcs = ["lib.rs"],
edition = "2021",
)
rust_mutation_test(
name = "my_lib_mutation_test",
crate = ":my_lib",
)
Run:
bazel test //:my_lib_mutation_test --test_output=all
cargo-mutants Compatibility
Mutation enumeration uses
cargo mutants --list --json --diff --Zmutate-file ....
Configuration
mutants_config = "path/to/mutants.toml" is forwarded as
cargo mutants --config <path>.
allow_survivors = True changes survivor handling:
- Default (
False): if any mutant survives, the Bazel test fails. True: survivors are still reported, but the Bazel test exits successfully.
Tooling Model
- This extension builds a hermetic
cargo-mutantsbinary from source. cargo-mutantsinternally invokes Cargo; the runner provides Cargo from the active Rust toolchain.- Rustc params are generated by a dedicated writer action that materializes canonical rustc flags into a runfiles-compatible params file consumed by the runtime runner.
Output Example
Running baseline compile+test...
Generated 5 mutants
mutant_0_src/lib.rs_binop - CAUGHT
mutant_1_src/lib.rs_binop - SURVIVED
Mutation Testing Summary
========================
Total: 5 Caught: 4 (80%) Survived: 1 (20%)
For survivors, a unified diff is printed for each surviving mutant.
Local Development
- Run extension-local tests from this repository root.
- Useful targets:
//:clippy//private:runner_unit_test//test:all
rules_rust_mutants
Mutation testing for Rust crates built with rules_rust.
rust_mutation_test enumerates source-level mutations for a rust_library,
compiles each mutant with the same rustc configuration as rust_test, and
runs the crate's inline #[cfg(test)] tests against each mutant.
Rules
Setup
Bzlmod
Add the following to your MODULE.bazel file:
bazel_dep(name = "rules_rust_mutants", version = "{SEE_RELEASE_NOTES}")
WORKSPACE
If you're using WORKSPACE, load repositories with:
load("@rules_rust_mutants//:repositories.bzl", "rust_mutation_dependencies")
rust_mutation_dependencies()
Usage
load("@rules_rust_mutants//:defs.bzl", "rust_mutation_test")
load("@rules_rust//rust:defs.bzl", "rust_library")
rust_library(
name = "my_lib",
srcs = ["lib.rs"],
edition = "2021",
)
rust_mutation_test(
name = "my_lib_mutation_test",
crate = ":my_lib",
)
Run with:
bazel test //:my_lib_mutation_test --test_output=all
Behavior Notes
- Mutation generation uses
cargo-mutantsJSON output. - Mutation enumeration uses
cargo mutants --list --json --diff --Zmutate-file .... - Rustc params are generated from rules_rust's canonical argument-construction
pipeline (
collect_inputs+construct_arguments). mutants_configis forwarded ascargo mutants --config <path>.- By default, survived mutants fail the Bazel test target.
allow_survivors = Truereports survivors without failing.- If mutation generation produces zero mutants, the Bazel target succeeds and
prints
No mutations generated..
Tooling
- A hermetic
cargo-mutantsbinary is built from source by this extension. - A Cargo binary from the active Rust toolchain is used for
cargo-mutantsinternals.
Rules
rust_mutation_test
load("@rules_rust_mutants//:defs.bzl", "rust_mutation_test")
rust_mutation_test(name, allow_survivors, crate, exclude_re, mutants_config, rustc_flags)
Mutation testing for a Rust library crate.
rust_mutation_test:
- Enumerates source-level mutants with
cargo-mutants. - Builds rustc params from rules_rust's canonical argument construction
pipeline (
collect_inputs + construct_arguments). - Runs baseline and per-mutant compile+test cycles against inline
#[cfg(test)]tests from the crate. - Fails if any mutant survives (unless
allow_survivors = True). - Succeeds and prints
No mutations generated.when enumeration yields zero mutants.
Mutation enumeration mode:
- Uses
cargo mutants --list --json --diff --Zmutate-file ....
Example:
load("@rules_rust_mutants//:defs.bzl", "rust_mutation_test")
rust_library(
name = "my_lib",
srcs = ["lib.rs"],
)
rust_mutation_test(
name = "my_lib_mutation_test",
crate = ":my_lib",
)
Run with: bazel test //:my_lib_mutation_test --test_output=all
ATTRIBUTES
| Name | Description | Type | Mandatory | Default |
|---|---|---|---|---|
| name | A unique name for this target. | Name | required | |
| allow_survivors | If True, survived mutants are reported but do not fail the test. Default is False (survivors fail). | Boolean | optional | False |
| crate | The rust_library crate to mutation-test. The crate's inline #[cfg(test)] tests are compiled and run against each mutation. | Label | required | |
| exclude_re | Regular expression patterns to exclude mutants. Each pattern is forwarded as cargo mutants --exclude-re <pattern>. | List of strings | optional | [] |
| mutants_config | Optional cargo-mutants configuration file. It is forwarded as cargo mutants --config <path>. If all mutants are filtered out, the target succeeds and reports no mutants. | Label | optional | None |
| rustc_flags | Additional flags passed through to rustc when compiling the baseline and mutant test binaries. | List of strings | optional | [] |