|
| list[str] | _pytest_argv (Path tests) |
| tuple[int|None, float] | _run_tests (Path tests, Path cwd, int timeout, Path pycache_dir) |
| float | _verify_baseline (Path tests, Path cwd, int timeout, Path pycache_dir) |
| RunReport | run_mutants (*, str|Path target, str|Path tests, int timeout=DEFAULT_TIMEOUT_SECONDS, str|Path|None root=None, Sequence[str]|None mutant_ids=None, Callable[[str], None]|None on_progress=None) |
| list[Mutant] | _select (list[Mutant] mutants, Sequence[str]|None mutant_ids) |
| list[MutantOutcome] | _run_each (Iterable[Mutant] mutants, Path target, Path tests, Path repo_root, str relpath, int timeout, Path cache_dir, Callable[[str], None] report_progress) |
| str | _classify (int|None returncode) |
Purpose
-------
Run a test command once per mutant and classify each outcome honestly.
Responsibilities
----------------
- Prove the tests are green on the pristine target before judging any mutant.
- Execute the given test path in a subprocess with a per-mutant timeout.
- Classify each mutant as killed, survived, or timeout, never conflating them.
- Stream per-mutant progress so a long run is never silent.
Diagnostics
-----------
Domain: OCT-MUTATION
Levels:
L2 - lifecycle
L3 - per-mutant execution details
L4 - deep tracing
Contracts
---------
- A timeout is its own class and is never counted as a kill.
- The pristine baseline must pass; without it every mutant would look killed,
so a red or empty baseline is a named refusal rather than a 100% kill rate.
- Each subprocess gets a fresh bytecode-cache directory, so no run can be
decided by a stale ``.pyc`` from the previous mutant.
- Runtime is mutant count times one test run; the caller is told the count
before the loop starts.
Dependencies
------------
- oct.mutation.engine (enumeration and mutant identity)
- oct.mutation.sandbox (target refusal, apply, and restore)
- subprocess (per-mutant pytest execution)