oct
Loading...
Searching...
No Matches
report.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oct/mutation/report.py
4
5"""
6Purpose
7-------
8Render mutation results for humans without editorialising the numbers.
9
10Responsibilities
11----------------
12- Render the enumeration-only listing used by ``--list``.
13- Render totals, the kill rate, and one description per surviving mutant.
14- Name the mutants that timed out, which no test run judged either way.
15
16Diagnostics
17-----------
18Domain: OCT-MUTATION
19Levels:
20 L2 - lifecycle
21 L3 - rendering details
22 L4 - deep tracing
23
24Contracts
25---------
26- Output is ASCII only, so a cp1252 console cannot turn a report into a crash.
27- v1 is report-only: the rendered text states no verdict and no threshold.
28- A survivor is described by its id, its source line, and its before/after form.
29
30Dependencies
31------------
32- oct.mutation.engine (mutant records)
33- oct.mutation.runner (run results)
34"""
35
36# OCT-LINT: disable-file=dbg_usage reason="Pure string rendering with no runtime lifecycle"
37# OCT-LINT: disable-file=dbg_import reason="Pure string rendering has no diagnostic dependency"
38
39from __future__ import annotations
40
41from typing import Sequence
42
43from oct.mutation.engine import Mutant
44from oct.mutation.runner import STATUS_TIMEOUT, MutantOutcome, RunReport
45
46
47def render_list(mutants: Sequence[Mutant], target: str) -> str:
48 """Render the enumeration produced by ``--list``, which runs nothing."""
49 lines = [f"{len(mutants)} mutant(s) in {target}; nothing was run."]
50 lines.extend(
51 f" {mutant.mutant_id} line {mutant.lineno}: "
52 f"{mutant.before} -> {mutant.after}"
53 for mutant in mutants
54 )
55 return "\n".join(lines)
56
57
58def render_human(report: RunReport) -> str:
59 """Render totals, the kill rate, survivors, and any unjudged timeouts."""
60 lines = [
61 f"Mutation report for {report.target}",
62 f" tests: {report.tests}",
63 f" timeout: {report.timeout_seconds}s per mutant",
64 f" mutants: {report.total}"
65 f" killed {report.killed}"
66 f" survived {report.survived}"
67 f" timeout {report.timed_out}",
68 f" kill rate: {_format_rate(report.kill_rate)}"
69 " (report-only: v1 applies no threshold and gates nothing)",
70 "",
71 ]
72 lines.extend(_render_survivors(report.survivors))
73 timeouts = [item for item in report.outcomes if item.status == STATUS_TIMEOUT]
74 if timeouts:
75 lines.append("")
76 lines.extend(_render_timeouts(timeouts))
77 return "\n".join(lines)
78
79
80def _render_survivors(survivors: Sequence[MutantOutcome]) -> list[str]:
81 """Render one description per surviving mutant, or say there were none."""
82 if not survivors:
83 return ["Survivors: none."]
84 lines = [f"Survivors ({len(survivors)}) - the tests did not notice these:"]
85 for outcome in survivors:
86 mutant = outcome.mutant
87 lines.append(f" {mutant.mutant_id}")
88 lines.append(f" line {mutant.lineno}: {mutant.line_text}")
89 lines.append(f" - {mutant.before}")
90 lines.append(f" + {mutant.after}")
91 return lines
92
93
94def _render_timeouts(timeouts: Sequence[MutantOutcome]) -> list[str]:
95 """Render the mutants that exceeded the timeout and were never judged."""
96 lines = [
97 f"Timed out ({len(timeouts)}) - neither killed nor survived; "
98 "raise --timeout to judge these:"
99 ]
100 lines.extend(
101 f" {outcome.mutant.mutant_id} line {outcome.mutant.lineno}: "
102 f"{outcome.mutant.before} -> {outcome.mutant.after}"
103 for outcome in timeouts
104 )
105 return lines
106
107
108def _format_rate(rate: float | None) -> str:
109 """Render the kill rate as a percentage, or ``n/a`` when nothing ran."""
110 if rate is None:
111 return "n/a"
112 return f"{rate * 100:.1f}%"
list[str] _render_survivors(Sequence[MutantOutcome] survivors)
Definition report.py:80
str render_list(Sequence[Mutant] mutants, str target)
Definition report.py:47
str render_human(RunReport report)
Definition report.py:58
str _format_rate(float|None rate)
Definition report.py:108
list[str] _render_timeouts(Sequence[MutantOutcome] timeouts)
Definition report.py:94