diff --git a/bios/Sony/PlayStation 2/.variants/ROM2.BIN.5d5ab431 b/bios/Galaksija/ROM2.BIN similarity index 100% rename from bios/Sony/PlayStation 2/.variants/ROM2.BIN.5d5ab431 rename to bios/Galaksija/ROM2.BIN diff --git a/scripts/common.py b/scripts/common.py index 17d52709..ef8ade3b 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -1298,6 +1298,16 @@ def runs_standalone( ) +# What identifies a profile entry's content, carried unchanged wherever the +# entry travels (cross-reference report, core extras, second-pass copies). +# Each copy once kept its own subset: np2kai's bios.rom lost min_size and +# validation on the way and resolved to an IBM PCjr ROM of the same name. +PROFILE_IDENTITY_FIELDS = ( + "sha1", "md5", "sha256", "crc32", "size", "min_size", "max_size", + "validation", "aliases", "unsourceable", +) + + def upstream_profile_index( profiles: dict[str, dict], include_aliases: bool = False ) -> dict[str, set[str]]: diff --git a/scripts/packextras.py b/scripts/packextras.py index 239d9a7d..7b284434 100644 --- a/scripts/packextras.py +++ b/scripts/packextras.py @@ -6,6 +6,7 @@ this module builds so the report and the pack withdraw the same files.""" from __future__ import annotations +from common import PROFILE_IDENTITY_FIELDS from common import expand_platform_declared_names from common import load_emulator_profiles from common import resolution_is_hash_exact @@ -442,7 +443,7 @@ def _collect_emulator_extras( # validation block; dropping those fields here would let a same-named # but different payload enter a generated pack. expected = u.get("expected") or {} - for identity in ("sha1", "md5", "sha256", "crc32", "size"): + for identity in PROFILE_IDENTITY_FIELDS: declared = u.get(identity) if declared in (None, "", []): declared = expected.get(identity) @@ -527,7 +528,7 @@ def _collect_emulator_extras( # The same identity the first pass carries: without it the copy # resolves on its name alone and a same-named file of another # game fills the slot the profile marks as not held. - for identity in ("sha1", "md5", "sha256", "crc32", "size", "unsourceable"): + for identity in PROFILE_IDENTITY_FIELDS: if f.get(identity) not in (None, "", []): extra[identity] = f[identity] extras.append(extra) diff --git a/scripts/verify.py b/scripts/verify.py index ea1a369c..d4da377c 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -34,6 +34,7 @@ import slots sys.path.insert(0, os.path.dirname(__file__)) from common import ( + PROFILE_IDENTITY_FIELDS, build_target_cores_cache, build_zip_contents_index, check_inside_zip, @@ -602,6 +603,11 @@ def find_undeclared_files( "checks": sorted(checks) if checks else [], "source_ref": f.get("source_ref"), "expected": _build_expected(f, checks), + **{ + field: f.get(field) + for field in PROFILE_IDENTITY_FIELDS + if f.get(field) not in (None, "", []) + }, "sha1": f.get("sha1"), "md5": f.get("md5"), } diff --git a/tests/test_extra_identity.py b/tests/test_extra_identity.py new file mode 100644 index 00000000..95b2a1eb --- /dev/null +++ b/tests/test_extra_identity.py @@ -0,0 +1,67 @@ +"""A core extra keeps every field that identifies its content. + +Each hop kept its own subset: min_size and validation were lost, so +np2kai's bios.rom (98304 bytes minimum, size checked) resolved by name to an +IBM PCjr ROM and shipped in four packs, and dosbox's SC-55 ROMs to a +Galaksija ROM and a PS2 ROM2.BIN. +""" + +from __future__ import annotations + +import sys +import unittest +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +from common import PROFILE_IDENTITY_FIELDS # noqa: E402 + +ENTRY = { + "name": "bios.rom", + "path": "np2kai/bios.rom", + "min_size": 98304, + "validation": ["size"], + "aliases": ["BIOS.ROM"], + "crc32": "12345678", +} + + +class IdentityTravels(unittest.TestCase): + def test_report_and_extra_keep_every_identity_field(self): + from packextras import _collect_emulator_extras + from verify import find_undeclared_files + + profile = { + "emulator": "NP2kai", + "type": "libretro", + "systems": ["nec-pc-98"], + "files": [dict(ENTRY)], + } + config = {"cores": ["np2kai"], "systems": {}} + db = { + "files": {"s1": {"name": "bios.rom", "path": "bios/NEC/PC-98/bios.rom", + "size": 100000, "sha1": "s1", "md5": "m1", "crc32": "12345678"}}, + "indexes": {"by_name": {"bios.rom": ["s1"]}, "by_md5": {"m1": "s1"}, + "by_crc32": {"12345678": "s1"}}, + } + report = find_undeclared_files(config, "emulators", db, emu_profiles={"np2kai": profile}) + extras = _collect_emulator_extras( + config, "emulators", db, set(), "", {"np2kai": profile}, include_all=True + ) + for label, item in (("report", report[0]), ("extra", extras[0])): + for field in ("min_size", "validation", "aliases", "crc32"): + with self.subTest(where=label, field=field): + self.assertEqual(item.get(field), ENTRY[field]) + + def test_every_hop_reads_the_shared_list(self): + for name in ("packextras.py", "verify.py"): + source = (REPO_ROOT / "scripts" / name).read_text(encoding="utf-8") + with self.subTest(module=name): + self.assertIn("PROFILE_IDENTITY_FIELDS", source) + self.assertNotIn('("sha1", "md5", "sha256", "crc32", "size"', source) + self.assertIn("validation", PROFILE_IDENTITY_FIELDS) + + +if __name__ == "__main__": + unittest.main()