diff --git a/scripts/verify.py b/scripts/verify.py index 5f909d155..27149e23e 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -3121,6 +3121,13 @@ def _overall_summary(group_results: list[tuple[dict, list[str]]]) -> str: named = [f"{name} {count}" for name, count in counts.items() if count] return f" ({', '.join(named)})" if named else "" + def on(groups: tuple[str, ...]) -> str: + """The platforms a file is missing on, by the shorter side.""" + if len(group_results) < 2 or len(groups) * 2 <= len(group_results): + return ", ".join(groups) + others = [" / ".join(g) for _, g in group_results if " / ".join(g) not in groups] + return "every platform" + (f" but {', '.join(others)}" if others else "") + parts = [] for severity, label in ((Severity.CRITICAL, "critical"), (Severity.WARNING, "warning"), (Severity.INFO, "info")): @@ -3139,18 +3146,26 @@ def _overall_summary(group_results: list[tuple[dict, list[str]]]) -> str: parts.append(f"{total} {'discrepancy' if total == 1 else 'discrepancies'}{where(counts)}") lines = [f"{platforms} platforms: {', '.join(parts)}"] - missing = { - " / ".join(group): sorted({ + # Grouped by file, not by platform: sfiii2a.zip missing everywhere was + # counted and printed once per platform, 24 files for 10 distinct ones. + holders: dict[str, list[str]] = {} + for r, group in group_results: + for name in sorted({ u["name"] for u in _core_required_missing(_split_undeclared( r.get("undeclared_files", []))[1]) - }) - for r, group in group_results - } - total = sum(len(names) for names in missing.values()) - if total: - detail = "; ".join(f"{group}: {', '.join(names)}" - for group, names in missing.items() if names) - lines.append(f"{total} core file(s) a core cannot run without are missing ({detail})") + }): + holders.setdefault(name, []).append(" / ".join(group)) + if holders: + by_platforms: dict[tuple[str, ...], list[str]] = {} + for name, groups in sorted(holders.items()): + by_platforms.setdefault(tuple(groups), []).append(name) + detail = "; ".join( + f"{', '.join(names)} ({on(groups)})" + for groups, names in sorted(by_platforms.items(), + key=lambda item: (-len(item[0]), item[1])) + ) + lines.append(f"{len(holders)} core file(s) a core cannot run without are " + f"missing: {detail}") for category, label in _NOT_FIRMWARE.items(): counts = { " / ".join(group): len((r.get("missing_not_firmware") or {}).get(category, [])) diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index 6d97d07d7..e5a26871f 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -5070,9 +5070,34 @@ class VerifyAllSummaryNamesWhatIsWrong(unittest.TestCase): [(clean, ["RetroArch"]), (warned, ["RetroDECK"]), (core_miss, ["ROCKNIX"])] ) self.assertIn("1 warning (RetroDECK 1)", summary) - self.assertIn("ROCKNIX: n64.psh", summary) + self.assertIn("n64.psh (ROCKNIX)", summary) self.assertIn("0 critical,", summary) + def test_a_file_missing_on_several_platforms_is_counted_once(self): + """sfiii2a.zip missing on 15 platforms read '24 core file(s)' for 10 + distinct files, the name printed 15 times on one line.""" + sys.path.insert(0, str(ROOT / "scripts")) + import verify + + def missing(*names: str) -> dict: + return {"severity_counts": {}, "undeclared_files": [ + {"name": name, "required": True, "in_repo": False, + "category": "bios", "in_pack": True} for name in names + ]} + + summary = verify._overall_summary([ + (missing("sfiii2a.zip"), ["Batocera"]), + (missing("sfiii2a.zip", "ROM"), ["RetroPie"]), + (missing("sfiii2a.zip"), ["RomM"]), + (missing(), ["MinUI"]), + ]) + self.assertIn( + "2 core file(s) a core cannot run without are missing: " + "sfiii2a.zip (every platform but MinUI); ROM (RetroPie)", + summary, + ) + self.assertEqual(summary.count("sfiii2a.zip"), 1) + class OneOutputFormPerRun(unittest.TestCase):