From e5420a9dbaa95981db53efaf26aea8dc9ab5c0eb Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 6 Oct 2026 09:39:07 +0200 Subject: [PATCH] fix: keep platform hashes the truth does not contradict --- scripts/exporter/baseline.py | 16 +++++++++++----- tests/test_export_counts.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/scripts/exporter/baseline.py b/scripts/exporter/baseline.py index 5bad4103..42415f93 100644 --- a/scripts/exporter/baseline.py +++ b/scripts/exporter/baseline.py @@ -61,9 +61,11 @@ class NativeFile: """Which side's content fields describe the file: one side, or both. Mixing them field by field wrote the truth's size and crc beside the - platform's sha1, a record no file satisfies. Both sides are merged - only where they agree on some hash; where they contradict, the truth - decides alone; where the truth declares none, the platform does. + platform's sha1, a record no file satisfies. The truth decides alone + only on a contradiction: a hash both sides declare without a value in + common, or two declared sizes. Different fields prove nothing: the + truth's crc32 beside Batocera's md5 for bios7.bin is one dump, and + reading it as a contradiction emptied the md5 the frontend checks. """ truth = {f: set(_hash_values(self.truth or {}, f)) for f in HASH_FIELDS} plat = {f: set(_hash_values(self.platform or {}, f)) for f in HASH_FIELDS} @@ -71,9 +73,13 @@ class NativeFile: return "platform" if not any(plat.values()): return "truth" - if any(truth[f] & plat[f] for f in HASH_FIELDS): + shared = [f for f in HASH_FIELDS if truth[f] and plat[f]] + if any(truth[f] & plat[f] for f in shared): return "both" - return "truth" + t_size = (self.truth or {}).get("size") + p_size = (self.platform or {}).get("size") + sizes_differ = isinstance(t_size, int) and isinstance(p_size, int) and t_size != p_size + return "truth" if shared or sizes_differ else "both" def hashes(self, field_name: str) -> list[str]: """Accepted values for a hash, truth first when it has an opinion. diff --git a/tests/test_export_counts.py b/tests/test_export_counts.py index 72e99cec..75792d1e 100644 --- a/tests/test_export_counts.py +++ b/tests/test_export_counts.py @@ -155,6 +155,18 @@ class OneFileOneIdentity(unittest.TestCase): self.assertEqual(fe.hashes("crc32"), ["bbbbbbbb"]) self.assertEqual(fe.size(), 480) + def test_different_fields_are_not_a_contradiction(self): + """bios7.bin: the truth's crc32 beside Batocera's md5 is one dump.""" + fe = NativeFile("bios7.bin", "bios/bios7.bin", "nds", + platform={"md5": A}, truth={"crc32": "1280f0d5"}) + self.assertEqual(fe.hashes("md5"), [A]) + self.assertEqual(fe.hashes("crc32"), ["1280f0d5"]) + + def test_different_sizes_still_contradict(self): + fe = NativeFile("boot.bin", "dc/boot.bin", "dc", + platform={"size": 2097152, "md5": A}, truth={"size": 480, "crc32": "bbbbbbbb"}) + self.assertEqual(fe.hashes("md5"), []) + def test_agreeing_sides_still_merge(self): fe = NativeFile("x.bin", "x.bin", "s", platform={"md5": A, "sha1": "1" * 40}, truth={"md5": A})