Renders mutation results for the human report.
Diffs are patched against the original source via Sourceror.patch_string at the site's recorded range, so untouched source stays byte-identical and a survivor reads as a precise source-range change. A replacement is parenthesized where its position would otherwise reread it (!(a == b) → (a == b) beside a |>, a -1 for the 0.75 of -0.75), on the assumption that binary operators are spaced as mix format writes them: in unformatted a-0, a -1 replacement is patched as a--1.
The mutation score and tallies in the report come from Mutare.Score, which also implements the CI gates; this module only renders.
Summary
Functions
A -/+ diff of the lines touched by the mutation.
One line for a harness-errored mutant, including a compact diagnostic.
Header line for a surviving mutant, e.g.
lib/x.ex:42 [relational, in-place] SURVIVED.
One line for an ignored mutant, e.g.
lib/x.ex:42 [arithmetic] IGNORED — off-by-one is intentional.
Apply a single mutation to the original source string.
Render the whole report from results and a %{file => original_source} map.
Renders the human report with the same arity as machine reporters.
One-line tally, e.g. mutation score: 66.7% (2 killed, 1 survived, 3 total).
Full diff block (header + diff) for one survivor.
Functions
@spec diff(Mutare.Site.t(), String.t()) :: String.t()
A -/+ diff of the lines touched by the mutation.
The diff is line-based within the site's source range. Changed lines are shown as deletions and insertions; unchanged lines inside a multi-line fragment are shown as context. This keeps multi-line replacements aligned when a mutation adds or removes a line in the middle of the fragment.
@spec harness_error(Mutare.Result.t()) :: String.t()
One line for a harness-errored mutant, including a compact diagnostic.
@spec header(Mutare.Site.t()) :: String.t()
Header line for a surviving mutant, e.g.
lib/x.ex:42 [relational, in-place] SURVIVED.
A mutation with a note appends it as a trailing — note, matching the ignored
mutant reason format.
@spec ignored(Mutare.Site.t()) :: String.t()
One line for an ignored mutant, e.g.
lib/x.ex:42 [arithmetic] IGNORED — off-by-one is intentional.
The trailing — reason is present only when the directive carried one, so a
bare # mutare:ignore reads as … IGNORED with nothing after it.
@spec patch(Mutare.Site.t(), String.t()) :: String.t()
Apply a single mutation to the original source string.
@spec render([Mutare.Result.t()], %{optional(String.t()) => String.t()}) :: String.t()
Render the whole report from results and a %{file => original_source} map.
@spec render([Mutare.Result.t()], %{optional(String.t()) => String.t()}, keyword()) :: String.t()
Renders the human report with the same arity as machine reporters.
opts is ignored; score gating is handled by the caller.
@spec summary([Mutare.Result.t()]) :: String.t()
One-line tally, e.g. mutation score: 66.7% (2 killed, 1 survived, 3 total).
iex> Mutare.Report.summary([
...> %Mutare.Result{status: :killed},
...> %Mutare.Result{status: :survived}
...> ])
"mutation score: 50.0% (1 killed, 1 survived, 2 total)"
@spec survivor(Mutare.Site.t(), String.t()) :: String.t()
Full diff block (header + diff) for one survivor.