Skip to content

Mutation testing: git plumbing helper survivors #36

Description

@leynos

Context

Mutation-testing run against main (b850e2fec11b1966d2b73670ae56b5eff195284e), mutmut 3.6.0, local run 2026-07-10: 1025 mutants, 151 killed, 235 survived, 639 no-tests. All mutants target hooks/post-turn-quality-stop-hook.py.

This issue covers the git/make plumbing helpers: 102 survivors across repo_root, has_uncommitted_changes, get_upstream_ref, has_unpushed_commits, get_make_targets, and compush_check.

Surviving mutants

  • hooks/post-turn-quality-stop-hook.py:208 — every token of ["git", "rev-parse", "--show-toplevel"] mutates freely in repo_root (x_repo_root__mutmut_611); likewise the returncode check, error-string composition, and empty-output message (mutmut_1223).
  • hooks/post-turn-quality-stop-hook.py:482-493 — all argv tokens of git diff --quiet, git diff --cached --quiet, and git ls-files --others --exclude-standard in has_uncommitted_changes (x_has_uncommitted_changes__mutmut_143, 32 survivors), including run(args, None) argument-wiring mutants and the ' '.join(args) error format.
  • hooks/post-turn-quality-stop-hook.py:513-518 — the full git rev-parse --abbrev-ref --symbolic-full-name @{u} argv and error literals in get_upstream_ref (x_get_upstream_ref__mutmut_625, 16 survivors).
  • hooks/post-turn-quality-stop-hook.py:537-549 — the git rev-list --count argv in has_unpushed_commits (x_has_unpushed_commits__mutmut_217), and notably int(ahead) > 0> 1 (x_has_unpushed_commits__mutmut_21, line 549).
  • hooks/post-turn-quality-stop-hook.py:641-652 — the make -qp --no-print-directory argv, the returncode == 2 sentinel, and error composition in get_make_targets (x_get_make_targets__mutmut_222, 18 survivors).
  • hooks/post-turn-quality-stop-hook.py:1090-1106compush_check call wiring (has_uncommitted_changes(None), has_unpushed_commits(None, upstream) and permutations) and the upstream-label literal "origin (upstream not configured)" wrapped as XX…XX (x_compush_check__mutmut_5, 8, 2427).

Analysis

The test suite (hooks/test_post_turn_quality_stop_hook.py) patches hook.run wholesale and never asserts the argument vectors passed to it, so any mutation of a command list, of the run(args, repo) wiring, or of git-failure messages is invisible. Error-message tests use substring assertions ("fatal: bad" in err), so literal mutations that preserve the substring also survive — the XX…XX wrapping of the compush upstream label survives precisely because the test asserts in rather than equality. The > 0> 1 boundary survives because tests use ahead-counts 2 and 0, never 1.

Suggested tests

  1. In each mocked-run test, assert mock_run.call_args_list against the exact argv and repo argument (kills the ~85 argv and wiring mutants).
  2. Add a has_unpushed_commits case with rev-list output "1" asserting True (kills the > 1 boundary mutant).
  3. Assert exact error messages (or == on the blocked-payload reason) for repo_root, get_upstream_ref, get_make_targets, and the compush fallback label (kills the literal-mutation survivors).
  4. Optionally, one integration test driving repo_root/has_uncommitted_changes against a real temporary git repository as a belt-and-braces check.

Full worklist: triage worklist.md (rollout Stage A artefact); dataset SHA b850e2f.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions