From 7437df78b3f1cce85d7b92ed9bb32a71aa4ff010 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Tue, 6 Oct 2026 01:22:56 +0200 Subject: [PATCH] fix: attach profile aliases to a unique name only --- scripts/generate_db.py | 7 ++++- tests/test_db_aliases.py | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/test_db_aliases.py diff --git a/scripts/generate_db.py b/scripts/generate_db.py index 5f5a451e..18cd96d1 100644 --- a/scripts/generate_db.py +++ b/scripts/generate_db.py @@ -402,9 +402,11 @@ def _collect_all_aliases(files: dict) -> dict: """ md5_to_sha1 = {} name_to_sha1 = {} + name_count: dict[str, int] = {} for sha1, entry in files.items(): md5_to_sha1[entry["md5"]] = sha1 name_to_sha1[entry["name"]] = sha1 + name_count[entry["name"]] = name_count.get(entry["name"], 0) + 1 aliases = {} @@ -501,7 +503,10 @@ def _collect_all_aliases(files: dict) -> dict: matched = sha1 elif md5 and md5 in md5_to_sha1: matched = md5_to_sha1[md5] - elif entry_name and entry_name in name_to_sha1: + elif entry_name and name_count.get(entry_name) == 1: + # A name carried by several files names none of them: + # quasi88's disk.rom aliases went to whichever + # disk.rom the scan met last, a Tandy CoCo ROM. matched = name_to_sha1[entry_name] if matched: for alias_name in entry_aliases: diff --git a/tests/test_db_aliases.py b/tests/test_db_aliases.py new file mode 100644 index 00000000..4375446c --- /dev/null +++ b/tests/test_db_aliases.py @@ -0,0 +1,67 @@ +"""A profile's aliases attach to the file its name designates, or to none. + +generate_db matched an alias-carrying entry by name through a dict that +kept the last file of that name. quasi88's disk.rom aliases (N88SUB.ROM, +n88sub.rom) went to a Tandy CoCo disk.rom, and a name lookup for the PC-88 +disk ROM then served the CoCo one. +""" + +from __future__ import annotations + +import os +import sys +import tempfile +import types +import unittest +from pathlib import Path +from unittest import mock + +REPO_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(REPO_ROOT / "scripts")) + + +class _NoCoreInfo: + def fetch_requirements(self): + return [] + + +class AliasesNeedAnUnambiguousName(unittest.TestCase): + def _aliases(self, files: dict) -> dict: + import generate_db + + stub = types.ModuleType("scraper.coreinfo_scraper") + stub.Scraper = _NoCoreInfo + with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp: + previous = os.getcwd() + os.chdir(tmp) + try: + Path("emulators").mkdir() + Path("emulators/x.yml").write_text( + 'files:\n - name: "disk.rom"\n aliases: ["n88sub.rom"]\n' + ) + with mock.patch.dict(sys.modules, {"scraper.coreinfo_scraper": stub}): + return generate_db._collect_all_aliases(files) + finally: + os.chdir(previous) + + @staticmethod + def _file(name: str, path: str, md5: str) -> dict: + return {"name": name, "path": path, "md5": md5} + + def test_homonyms_take_no_alias(self): + files = { + "a": self._file("disk.rom", "bios/NEC/PC-98/disk.rom", "m1"), + "b": self._file("disk.rom", "bios/Tandy/CoCo/disk.rom", "m2"), + } + aliases = self._aliases(files) + named = {a["name"] for entries in aliases.values() for a in entries} + self.assertNotIn("n88sub.rom", named) + + def test_a_unique_name_still_carries_its_aliases(self): + files = {"a": self._file("disk.rom", "bios/NEC/PC-88/disk.rom", "m1")} + aliases = self._aliases(files) + self.assertEqual([a["name"] for a in aliases.get("a", [])], ["n88sub.rom"]) + + +if __name__ == "__main__": + unittest.main()