"""Unit tests for quality-depth gate helpers.""" from __future__ import annotations import json from pathlib import Path from types import SimpleNamespace from scripts import check_mutation_score from scripts import check_mutation_targets from scripts import run_repeat_gate def test_mutation_score_accepts_exact_floor_and_rejects_regression(): stats = {"killed": 70, "total": 100, "check_was_interrupted_by_user": 0} assert check_mutation_score.validate_mutation_stats(stats, minimum=70) == [] assert check_mutation_score.validate_mutation_stats(stats, minimum=70.01) == [ "mutation score 70.00% (70/100) is below the 70.01% floor", ] def test_mutation_score_validator_default_matches_immutable_policy_floor(): parser = check_mutation_score._parser() assert check_mutation_score.DEFAULT_MUTATION_SCORE_MINIMUM == 85.0 assert parser.parse_args(["stats.json"]).minimum == 85.0 def test_mutation_score_rejects_malformed_and_interrupted_runs(): assert check_mutation_score.validate_mutation_stats( {"killed": True, "total": 1}, minimum=70, ) == ["mutation statistics require a non-negative integer 'killed'"] assert check_mutation_score.validate_mutation_stats( {"killed": 1, "total": 1, "check_was_interrupted_by_user": 1}, minimum=70, ) == ["mutation run was interrupted"] def test_mutation_target_guard_invalidates_stale_copied_targets(tmp_path): pyproject = tmp_path / "pyproject.toml" pyproject.write_text( """ [tool.mutmut] only_mutate = [ "obliteratus/config.py", "obliteratus/analysis/whitened_svd.py", ] required_mutation_targets = [ "obliteratus/analysis/whitened_svd.py", ] """.lstrip(), encoding="utf-8", ) for target in ( "obliteratus/config.py", "obliteratus/analysis/whitened_svd.py", ): source = tmp_path / target source.parent.mkdir(parents=True, exist_ok=True) source.write_text("pass\n", encoding="utf-8") valid_meta = tmp_path / "mutants/obliteratus/config.py.meta" valid_meta.parent.mkdir(parents=True, exist_ok=True) valid_meta.write_text('{"exit_code_by_key": {"obliteratus.config.x__mutmut_1": null}}') stale_copy = tmp_path / "mutants/obliteratus/analysis/whitened_svd.py" stale_copy.parent.mkdir(parents=True, exist_ok=True) stale_copy.write_text("pass\n", encoding="utf-8") stale = check_mutation_targets.prepare_required_targets(pyproject) assert stale == [Path("obliteratus/analysis/whitened_svd.py")] assert not stale_copy.exists() assert check_mutation_targets.validate_required_targets(pyproject) == [ "configured mutation target produced zero mutants: obliteratus/analysis/whitened_svd.py", ] def test_mutation_target_guard_passes_when_each_exact_target_has_mutants(tmp_path): pyproject = tmp_path / "pyproject.toml" pyproject.write_text( """ [tool.mutmut] only_mutate = [ "obliteratus/analysis/*.py", "obliteratus/analysis/numerical_contracts.py", ] required_mutation_targets = [ "obliteratus/analysis/numerical_contracts.py", ] """.lstrip(), encoding="utf-8", ) source = tmp_path / "obliteratus/analysis/numerical_contracts.py" source.parent.mkdir(parents=True, exist_ok=True) source.write_text("pass\n", encoding="utf-8") meta = tmp_path / "mutants/obliteratus/analysis/numerical_contracts.py.meta" meta.parent.mkdir(parents=True, exist_ok=True) meta.write_text( '{"exit_code_by_key": {"obliteratus.analysis.numerical_contracts.x__mutmut_1": null}}', encoding="utf-8", ) assert check_mutation_targets.validate_required_targets(pyproject) == [] def test_repeat_orders_are_distinct_and_deterministic(): paths = ["a", "b", "c", "d"] assert run_repeat_gate.test_orders(paths) == [ ["a", "b", "c", "d"], ["d", "c", "b", "a"], ["a", "c", "b", "d"], ] def test_repeat_gate_records_each_pass(monkeypatch, tmp_path): calls = [] def fake_run(command, **kwargs): calls.append((command, kwargs["env"]["PYTHONHASHSEED"])) return SimpleNamespace(returncode=0, stdout="2 passed\n", stderr="") monkeypatch.setattr(run_repeat_gate.subprocess, "run", fake_run) monkeypatch.setattr( run_repeat_gate, "junit_snapshot", lambda _path: {"tests": 2, "failed_nodeids": [], "skipped_nodeids": []}, ) output = tmp_path / "repeat.json" assert run_repeat_gate.run_repeat_gate( ["first.py", "second.py"], output=output, python="python-fixture", ) == 0 evidence = json.loads(output.read_text()) assert evidence["status"] == "passed" assert [entry["python_hash_seed"] for entry in evidence["passes"]] == [ "0", "1", "8675309", ] assert calls[0][0] == [ "python-fixture", "-m", "pytest", "--no-cov", "-q", f"--junitxml={tmp_path / 'repeat-pass-1.xml'}", "first.py", "second.py", ] def test_repeat_gate_completes_all_passes_and_preserves_failure_output(monkeypatch, tmp_path): def fake_run(*_args, **_kwargs): return SimpleNamespace(returncode=3, stdout="failed output", stderr="failure detail") monkeypatch.setattr(run_repeat_gate.subprocess, "run", fake_run) monkeypatch.setattr( run_repeat_gate, "junit_snapshot", lambda _path: { "tests": 1, "failed_nodeids": ["tests.test_example::test_failure"], "skipped_nodeids": [], }, ) output = tmp_path / "repeat.json" assert run_repeat_gate.run_repeat_gate(["test.py"], output=output) == 3 evidence = json.loads(output.read_text()) assert evidence["status"] == "failed" assert len(evidence["passes"]) == 3 assert evidence["passes"][0]["stderr"] == "failure detail" assert evidence["consistent_failures"] == [{ "nodeid": "tests.test_example::test_failure", "occurrences": 3, }] def test_repeat_gate_identifies_intermittent_failures(monkeypatch, tmp_path): results = iter([ SimpleNamespace(returncode=1, stdout="failed", stderr=""), SimpleNamespace(returncode=0, stdout="passed", stderr=""), SimpleNamespace(returncode=1, stdout="failed", stderr=""), ]) snapshots = iter([ {"tests": 1, "failed_nodeids": ["tests.test_example::test_flake"], "skipped_nodeids": []}, {"tests": 1, "failed_nodeids": [], "skipped_nodeids": []}, {"tests": 1, "failed_nodeids": ["tests.test_example::test_flake"], "skipped_nodeids": []}, ]) monkeypatch.setattr(run_repeat_gate.subprocess, "run", lambda *_args, **_kwargs: next(results)) monkeypatch.setattr(run_repeat_gate, "junit_snapshot", lambda _path: next(snapshots)) output = tmp_path / "repeat.json" assert run_repeat_gate.run_repeat_gate(["test.py"], output=output) == 1 evidence = json.loads(output.read_text()) assert evidence["flake_candidates"] == [{ "nodeid": "tests.test_example::test_flake", "occurrences": 2, }]