Count multi-line statement sites as covered from their start line; skip TypeScript type positions

This commit is contained in:
Robert C. Martin
2026-10-21 14:33:45 -05:00
parent c57f03879a
commit a5a0cb803b
7 changed files with 109 additions and 3 deletions
+9
View File
@@ -921,3 +921,12 @@ def test_snapshots_keep_other_files_empty_directories_and_odd_records(tmp_path):
assert not (base / "empty").exists()
assert (full / "keep.edn").is_file()
_remove_empty_dirs(tmp_path / "missing-metrics")
def test_scan_counts_a_site_inside_a_covered_multi_line_statement(tmp_path):
path = tmp_path / "src" / "demo.py"
path.parent.mkdir()
path.write_text("def add(a, b):\n return (a\n + b)\n", encoding="utf-8")
scanned = scan_file(path, tmp_path, covered_lines={2}, ignore_coverage=False, lines=None)
assert "uncovered" not in scanned
assert "+ -> -" in scanned
+23
View File
@@ -113,6 +113,29 @@ def test_uncovered_sites_are_not_executed(tmp_path):
assert result.forms[0].sites == 4
def test_a_site_inside_a_covered_multi_line_statement_is_run(tmp_path):
# LCOV marks only the line a statement starts on.
path = tmp_path / "src" / "demo.py"
path.parent.mkdir()
path.write_text("def add(a, b):\n return (a\n + b)\n", encoding="utf-8")
runner = FakeRunner()
result = mutate_file(
path,
tmp_path,
runner=runner,
covered_lines={2},
ignore_coverage=False,
mutate_all=True,
lines=None,
test_command="fake",
timeout_factor=10,
mutation_warning=50,
baselines={},
)
assert result.forms[0].uncovered == 0
assert result.forms[0].killed == 1
def test_a_failed_baseline_does_not_rewrite_metrics(tmp_path):
path = tmp_path / "src" / "demo.py"
path.parent.mkdir()
+31
View File
@@ -203,3 +203,34 @@ def test_a_deep_expression_is_walked(tmp_path):
assert discover_raw(python, "python", "app.py")
go = f"package p\nfunc place() int {{ return {expr} }}\n"
assert discover_raw(go, "go", "app.go")
def test_typescript_types_are_not_mutation_sites(tmp_path):
source = """type Flag = { on: true };
interface Box { open: false }
export function check(n: number): { ok: true } | { ok: false; used?: true } {
const seen: Promise<{ done: false }> | null = null;
return { ok: n > 0 };
}
"""
sites = _sites(tmp_path, "src/demo/check.ts", source)
described = {(site.line, site.original, site.mutant) for site in sites}
assert described == {(5, ">", ">="), (5, "0", "1")}
def test_a_site_remembers_where_its_statement_starts(tmp_path):
source = """export function save(db: Db, now: number) {
db
.prepare("x")
.bind(now + 1)
.run();
return {
ok: true,
};
}
"""
sites = _sites(tmp_path, "src/demo/save.ts", source)
anchors = {(site.line, site.original, site.anchor_line) for site in sites}
assert (4, "+", 2) in anchors
assert (4, "1", 2) in anchors
assert (7, "true", 6) in anchors