Skip to content
mutastic

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

Terminal window
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.

Terminal window
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/pricing

Exit 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
EnvironmentMUTASTIC_FORMAT, MUTASTIC_AGENT

--vocabulary=WORDS

plain says caught and missed; classic says killed and survived.

One of plainclassic

Command line--vocabulary=WORDS
EnvironmentMUTASTIC_VOCABULARY

--color=WHEN

Colour: auto uses it on a terminal that wants it.

One of autoalwaysnever

Command line--color=WHEN
EnvironmentNO_COLOR, FORCE_COLOR

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