From fd16764e0c8d9102bd1b326124365d8489bdfc3a Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:06:32 +0200 Subject: [PATCH] fix: keep the gap report readable --- scripts/cross_reference.py | 23 +++++++++++++++++------ tests/test_audit_regressions.py | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/scripts/cross_reference.py b/scripts/cross_reference.py index ac576d4f..2967cfde 100644 --- a/scripts/cross_reference.py +++ b/scripts/cross_reference.py @@ -668,10 +668,15 @@ def cross_reference( return report -def print_report(report: dict) -> None: - """Print a human-readable gap analysis report.""" +def print_report(report: dict, scope: str = "all emulators") -> None: + """Print a human-readable gap analysis report. + + `scope` names what the totals cover: under --platform, the emulators + that platform runs, not all of them. + """ print("Emulator vs Platform Gap Analysis") print("=" * 60) + print("* marks a file the emulator requires") total_gaps = 0 totals: dict[str, int] = {"bios": 0, "data": 0, "large_file": 0, "missing": 0} @@ -688,7 +693,8 @@ def print_report(report: dict) -> None: parts.append(f"{count} {key}") status = ", ".join(parts) if parts else "OK" - print(f"\n{data['emulator']} ({', '.join(data['systems'])})") + systems = ", ".join(data["systems"]) + print(f"\n{data['emulator']}" + (f" ({systems})" if systems else "")) print( f" {data['total_files']} files in profile, " f"{data['platform_covered']} declared by platforms, " @@ -699,7 +705,9 @@ def print_report(report: dict) -> None: for g in data["gap_details"]: req = "*" if g["required"] else " " src = g.get("source", "missing").upper() - note = f" -- {g['note']}" if g["note"] else "" + # One line per file: a note spanning lines fell to column 0 + # between entries and read as an emulator heading. + note = f": {' '.join(str(g['note']).split())}" if g["note"] else "" archive_info = "" if g.get("archive"): fc = g.get("archive_file_count", 0) @@ -712,7 +720,7 @@ def print_report(report: dict) -> None: totals[key] += data.get(f"gap_{key}", 0) print(f"\n{'=' * 60}") - print(f"Total: {total_gaps} undeclared files across all emulators") + print(f"Total: {total_gaps} undeclared files across {scope}") available = totals["bios"] + totals["data"] + totals["large_file"] print(f" {available} available (bios: {totals['bios']}, data: {totals['data']}, " f"large_file: {totals['large_file']})") @@ -772,7 +780,10 @@ def main(): if args.json: print(json.dumps(report, indent=2)) else: - print_report(report) + print_report( + report, + f"the emulators {args.platform} runs" if args.platform else "all emulators", + ) if __name__ == "__main__": diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index 8ab4d96f..1861a92a 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -3544,5 +3544,30 @@ class VerifyPacksSaysWhatItExcluded(unittest.TestCase): self.assertNotRegex(body, r"result\[\d\]") + +class TheGapReportKeepsItsShape(unittest.TestCase): + """Multi-line notes fell to column 0 and read as emulator headings, a + profile without systems printed `Abuse ()`, `*` had no legend, and + --platform totals said "across all emulators".""" + + def test_layout(self): + from scripts.cross_reference import print_report + + report = {"abuse": { + "emulator": "Abuse", "systems": [], "gaps": 1, "total_files": 1, + "platform_covered": 0, "gap_missing": 1, + "gap_details": [{"name": "a.spe", "required": True, "source": "missing", + "note": "first line\nsecond line"}], + }} + out = io.StringIO() + with contextlib.redirect_stdout(out): + print_report(report, "the emulators batocera runs") + text = out.getvalue() + self.assertIn("* marks a file the emulator requires", text) + self.assertIn("\nAbuse\n", text) + self.assertIn("a.spe [MISSING]: first line second line", text) + self.assertIn("across the emulators batocera runs", text) + + if __name__ == "__main__": unittest.main()