Rust edition
mutastic run
Mutate the package and run its tests against each mutant. dir is the package's directory, here unless given; in a workspace, a member's. The run passes when the score reaches the threshold, or with --fail-on-new when every mutant no test catches is in the baseline. A full run, one without --only, writes report files, and offers the commands to work on each missed mutant. Its progress goes to stderr, so stdout holds only the result. --shard runs one share of the mutants, for splitting a run across CI jobs, and --from-shards puts the shares back together as the whole run.
Usage
mutastic run [dir] [options]Inside a package, cargo mutastic run runs the same command, with the same options.
Output
On the pricing fixture, where one mutant gets past the tests. This is mutastic's own output, written from the CLI and checked against it on every build.
Missed ────────────────────────────────────────────────────────────
❯ src/lib.rs 1 missed in 1 function
✗ MISSED no test checks discount() at total == 100 ┌─ src/lib.rs:26 │ 25 │ pub fn discount(&self, total: u32) -> u32 { 26 │ if total >= 100 { │ ^^ >= changed to > 27 │ return total / 10; │ = mutant - if total >= 100 { + if total > 100 { = note: every test calls discount() away from the boundary inputs seen: 50, 250 (none is 100) covered by tests::small_orders_pay_full_price, pricing::big_orders_get_ten_percent_off (all 2 covering tests still pass) = help: test discount() with total = 100 and assert the result
// in mod tests #[test] fn discount_at_the_total_edge() { assert_eq!(Pricing::new().discount(100), 10); // today 10 · with this mutant 0 } check today's value is the one you intend: the test pins what the code does now
done when mutastic verify mb2f8ae57 fixtures/pricing passes reproduce mutastic run --only=mb2f8ae57 fixtures/pricing or ignore mutastic ignore mb2f8ae57 --reason="<why>" fixtures/pricing
Files 0 clean | 1 with misses (1) Mutants ✓ 10 caught · ✗ 1 missed (11) Worst at Pricing::discount() 1 ✗ Build one build of every mutant, 2 rounds (check and build) Test runs 13 (33 without coverage selection) Start at 18:23:57 Duration 493ms (setup 460ms, coverage 2ms, mutants 16ms) Tests 3 on rustc 1.99.1 · 4 workers Reports target/mutastic/mutation.json · target/mutastic/mutation.html Score 90.9% threshold 80
PASS 1 missed, above the threshold. Next: mutastic verify <id> fixtures/pricing · mutastic run --only=<id> fixtures/pricing · mutastic explain <id> fixtures/pricingExit status
0 when the score reaches the threshold, 1 when it doesn't; with --fail-on-new, 0 when every mutant no test catches is in the baseline, 1 when one isn't. Any command exits 2 when mutastic couldn't run: see exit codes.
Options
--threshold=N
The score a run must reach to pass; 80 unless set.
| Command line | --threshold=N |
|---|
--fail-on-new
Pass when every mutant no test catches is in .mutastic/baseline.yaml, and fail on one that isn't, whatever the score: the threshold isn't applied. For a package whose score can't reach it yet; mutastic baseline writes the file.
| Command line | --fail-on-new |
|---|
--since[=REF]
Mutate only the lines changed since the merge-base of HEAD and REF, uncommitted and new files included; the default branch without one.
| Command line | --since[=REF] |
|---|
--only=ID
Run one mutant, or several split by commas, whatever --operators says.
| Command line | --only=ID |
|---|
--workers=N
How many mutants run side by side; half the cores, from 1 to 4, unless set.
| Command line | --workers=N |
|---|
--no-suggestions
Don't look for a test that catches each missed mutant, which runs the missed mutant's function outside the tests.
| Command line | --no-suggestions |
|---|
--operators=OPERATORS
Which operators run: a set (defaults, stronger or extended), or operator ids split by commas, in place of mutastic.yaml's operators; defaults unless set.
| Command line | --operators=OPERATORS |
|---|
--unsafe=MODE
Which unsafe code is mutated: skip leaves unsafe code and the functions holding an unsafe block alone, enclosing mutates those functions too, all unsafe code as well; skip unless set.
One of skipenclosingall
| Command line | --unsafe=MODE |
|---|
--report=KIND[:PATH]
A report file a full run writes: json (mutation.json), html (mutation.html) or sarif (mutation.sarif), in target/mutastic unless a path is given, or none; json and html unless set.
One of jsonhtmlsarifnone
| Command line | --report=KIND[:PATH] |
|---|
--shard=N/M
Run only the Nth of M shares of the mutants, to split one run across machines. It keeps its results in shares/N-of-M in target/mutastic for --from-shards.
| Command line | --shard=N/M |
|---|
--from-shards=DIR
Run no mutants: put together the results every share of a split run kept, found anywhere in DIR, as the whole run, with its reports and threshold.
| Command line | --from-shards=DIR |
|---|
--format=FORMAT
How the result is shown; full on a terminal, concise elsewhere, agent for coding agents; explain takes full and jsonl.
One of fullbriefconcisegroupedagentjsonl
| Command line | --format=FORMAT |
|---|---|
| Environment | MUTASTIC_FORMAT, MUTASTIC_AGENT |
--vocabulary=WORDS
plain says caught and missed; classic says killed and survived.
One of plainclassic
| Command line | --vocabulary=WORDS |
|---|---|
| Environment | MUTASTIC_VOCABULARY |
--color=WHEN
Colour: auto uses it on a terminal that wants it.
One of autoalwaysnever
| Command line | --color=WHEN |
|---|---|
| Environment | NO_COLOR, FORCE_COLOR |
--hyperlinks=WHEN
File locations as links a terminal can open: auto uses them on a terminal.
One of autoalwaysnever
| Command line | --hyperlinks=WHEN |
|---|
--progress=STYLE
Progress on stderr: a bar on a terminal, counter lines in logs, none for agents.
One of autobarcounternone
| Command line | --progress=STYLE |
|---|
--edition=EDITION
Which edition runs; unless set, the build file in dir, or the nearest above it: Cargo.toml for rust, pom.xml, build.gradle or settings.gradle for java.
One of rustjava
| Command line | --edition=EDITION |
|---|