diff --git a/scripts/check_coverage.py b/scripts/check_coverage.py index bf2ff56c4..1792c710f 100644 --- a/scripts/check_coverage.py +++ b/scripts/check_coverage.py @@ -37,45 +37,6 @@ def load_totals(path: Path) -> Mapping[str, Any]: return merged -def load_union_branch_totals(files: Sequence[object]) -> Mapping[str, int | float]: - """Merge LLVM branch outcomes by source coordinate across test binaries.""" - - outcomes: dict[tuple[str, int, int, int, int], list[int]] = {} - for file_record in files: - if not isinstance(file_record, Mapping): - raise ValueError("coverage file record must be an object") - filename = file_record.get("filename") - if "branches" not in file_record: - raise ValueError("coverage file record must contain branches") - branches = file_record["branches"] - if not isinstance(filename, str) or not filename: - raise ValueError("coverage file record must contain a filename") - if not isinstance(branches, list): - raise ValueError("coverage branches must be a list") - for branch in branches: - if not isinstance(branch, list) or len(branch) < 6: - raise ValueError("coverage branch record is malformed") - coordinates = branch[:4] - counts = branch[4:6] - if not all( - isinstance(value, int) and not isinstance(value, bool) and value >= 0 - for value in coordinates - ): - raise ValueError("coverage branch coordinates are invalid") - if not all( - isinstance(value, int) and not isinstance(value, bool) and value >= 0 - for value in counts - ): - raise ValueError("coverage branch counts are invalid") - key = (filename, *coordinates) - outcome = outcomes.setdefault(key, [0, 0]) - outcome[0] += counts[0] - outcome[1] += counts[1] - count = len(outcomes) * 2 - covered = sum(outcome > 0 for counts in outcomes.values() for outcome in counts) - return {"count": count, "covered": covered} - - def _parse_branch_record(record: object) -> tuple[tuple[int, int, int, int], int, int]: """Return ``(site, true_count, false_count)`` from one LLVM branch tuple. diff --git a/tests/quality/test_check_coverage.py b/tests/quality/test_check_coverage.py index e9eb46d8b..f20471f53 100644 --- a/tests/quality/test_check_coverage.py +++ b/tests/quality/test_check_coverage.py @@ -790,6 +790,48 @@ def test_multiline_scanner_ignores_comments_char_literals_and_raw_strings(self) + def test_union_branch_totals_merge_counts_across_binaries(self) -> None: + """Valid records sum per coordinate across duplicate instrumented copies.""" + + files = [ + { + "filename": "src/lib.rs", + "branches": [ + [10, 1, 5, 6, 3, 0], + [20, 2, 7, 8, 0, 4], + ], + }, + { + "filename": "src/lib.rs", + "branches": [ + [10, 1, 5, 6, 1, 2], + ], + }, + ] + self.assertEqual( + coverage_contract.load_union_branch_totals(files), + {"count": 4, "covered": 3}, + ) + + def test_blank_history_comma_scan_exhaustion(self) -> None: + """Blank-only preceding lines exhaust the reverse scan and stay unproven.""" + + lines = ["", " ", " ,"] + self.assertFalse( + coverage_contract._is_structural_comma_continuation(lines, 3, ",") + ) + + def test_char_literal_with_escaped_backslash_keeps_scanner_exact(self) -> None: + """An escaped-backslash char literal cannot flip the multiline verdict.""" + + lines = [ + "const slash: char = '\\\\';", + 'static tail: &str = "open', + ' tail";', + ] + self.assertTrue(coverage_contract._line_in_multiline_string(lines, 3)) + self.assertFalse(coverage_contract._line_in_multiline_string(lines, 2)) + def test_multiline_string_empty_lines_returns_false(self) -> None: """An empty source produces no multiline-string continuations."""