diff --git a/scripts/common.py b/scripts/common.py index 40c48330..d9e0f7fd 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -1651,11 +1651,41 @@ def filter_systems_by_target( norm_key = _norm_sid(sid) norm_plat_system_cores.setdefault(norm_key, set()).add(name) + # A platform can file a system under an id no profile uses: Batocera's + # enterprise-64-128 is ep128emu's enterprise-64 and enterprise-128, and + # only CLK, off most targets, carries the joined id. The destinations a + # system declares name the cores that read its files. A bare name proves + # nothing (bios.bin belongs to many systems), so only a path counts. + dest_cores: dict[str, set[str]] = {} + for name, p in profiles.items(): + if p.get("type") == "alias": + continue + for f in p.get("files", []): + for key in ("path", "standalone_path"): + dest = f.get(key) + if not isinstance(dest, str): + continue + if dest.endswith("/"): + dest += f.get("name", "") + dest = sanitize_pack_path(dest).lower() + if "/" in dest: + dest_cores.setdefault(dest, set()).add(name) + filtered = {} for sys_id, sys_data in systems.items(): norm_key = _norm_sid(sys_id) - all_cores = norm_system_cores.get(norm_key, set()) + file_cores = { + core + for fe in sys_data.get("files", []) + for core in dest_cores.get( + sanitize_pack_path(fe.get("destination") or fe.get("name", "")).lower(), + (), + ) + } + all_cores = norm_system_cores.get(norm_key, set()) | file_cores plat_cores_here = norm_plat_system_cores.get(norm_key, set()) + if platform_cores is not None: + plat_cores_here = plat_cores_here | (file_cores & set(platform_cores)) if not all_cores and not plat_cores_here: # No profile maps to this system -keep it diff --git a/tests/test_target_systems.py b/tests/test_target_systems.py new file mode 100644 index 00000000..82343448 --- /dev/null +++ b/tests/test_target_systems.py @@ -0,0 +1,71 @@ +"""A target keeps a system whose files an on-target core reads. + +Batocera files the Enterprise under enterprise-64-128. ep128emu, the core +that reads ep128emu/roms/exos21.rom, declares enterprise-64 and +enterprise-128; only CLK carries the joined id. With a target that has +ep128emu and not CLK, the system was dropped from the report while the +builder still shipped its ROMs as ep128emu extras. +""" + +from __future__ import annotations + +import sys +import unittest +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(REPO_ROOT / "scripts")) + +from common import filter_systems_by_target # noqa: E402 + +PROFILES = { + "ep128emu_core": { + "type": "libretro", + "systems": ["enterprise-64", "enterprise-128"], + "files": [{"name": "exos21.rom", "path": "ep128emu/roms/exos21.rom"}], + }, + "clk": { + "type": "standalone", + "systems": ["enterprise-64-128"], + "files": [{"name": "exos10.bin", "path": "Enterprise/exos10.bin"}], + }, + "generic": { + "type": "libretro", + "systems": ["other"], + "files": [{"name": "bios.bin", "path": "bios.bin"}], + }, +} + + +def systems(*files: str) -> dict: + return {"enterprise-64-128": {"files": [ + {"name": f.rsplit("/", 1)[-1], "destination": f} for f in files + ]}} + + +class TargetSystems(unittest.TestCase): + def kept(self, declared: dict) -> list[str]: + return sorted(filter_systems_by_target( + declared, PROFILES, {"ep128emu_core"}, + platform_cores={"ep128emu_core", "clk"}, + )) + + def test_a_core_reading_the_system_destination_keeps_it(self): + self.assertEqual(self.kept(systems("ep128emu/roms/exos21.rom")), ["enterprise-64-128"]) + + def test_without_that_evidence_the_off_target_core_drops_it(self): + self.assertEqual(self.kept(systems("Enterprise/exos10.bin")), []) + + def test_a_bare_name_is_no_evidence(self): + declared = {"enterprise-64-128": {"files": [{"name": "bios.bin"}]}} + self.assertEqual( + sorted(filter_systems_by_target( + declared, PROFILES, {"generic"}, + platform_cores={"generic", "clk"}, + )), + [], + ) + + +if __name__ == "__main__": + unittest.main()