Mutation-test the lines this branch changed.
mix mob.mutate # lines changed vs origin/master
mix mob.mutate --file lib/foo.ex # every mutable line in one file
mix mob.mutate --base HEAD~3 # against a different base
mix mob.mutate --jsonA green suite says the tests ran, not that they guard anything. This changes the production code one line at a time and reports the changes nothing noticed.
Options
--file PATH— mutate this file instead of the branch diff; repeatable--base REF— diff base (default:origin/master)--test-command— how to run the suite (default:mix test). Narrow itwhen the full suite is slow: every mutant runs it once.--max N— stop after N mutants--json— machine-readable result on stdout, progress on stderr
Running it on this task
It reports most of run/1 as surviving, and that is accurate rather than a
bug in either. This repo's convention is that a Mix task stays a thin
unstubbed I/O wrapper and the decisions get extracted and tested — so the
parts with a testable kernel (source_file?/1, summary/4,
dirty_message/2, and everything in MobDev.Mutate) are guarded, and the
orchestration that only sequences them is not. The tool measures what the
suite guards; it does not know what you decided not to guard.
Exit status
Non-zero when any mutation survived, so this can gate a change the way a failing test does.
What it does to your working tree
It rewrites real source files in place and restores them from memory after each mutant. An interrupted run leaves the last mutant on disk — Ctrl-C, a closed terminal and an OOM kill all skip the restore, and no amount of in-process care changes that.
So the run refuses to start unless the files it would touch are clean in git.
That way git checkout -- <file> is always a complete recovery, which is the
only guarantee that survives being killed outright. An earlier version of
this text claimed a snapshot restored the tree "even if the run is
interrupted"; there was no snapshot, the claim was false, and it talked the
reader out of the one habit that would have saved them.
Summary
Functions
The refusal for a tree that is not safe to mutate, or nil.
Functions
@spec dirty_message(String.t(), non_neg_integer()) :: String.t() | nil
The refusal for a tree that is not safe to mutate, or nil.
Pure, and tested, because it is the only thing standing between an
interrupted run and someone's uncommitted work. A git status that fails is
as disqualifying as one that reports changes: if we cannot tell whether
recovery is possible, we must not proceed as though it is.