mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
tests/__init__.py keeps a run offline, its scratch under tmp/ and its installer cache its own, but only discover -s tests -t . imported it. discover tests ran with RETROBIOS_OFFLINE unset, scratch on the /tmp tmpfs and the user's real installer cache, the setting in which e2e fixtures had written into the shared .cache/large. Every test module now imports the package first, and a test fails on a module that does not. test_verify_listing.py took its line with the previous commit.
277 lines
11 KiB
Python
277 lines
11 KiB
Python
"""A hashless platform entry takes no file filed under another maker.
|
|
|
|
AmberELEC's nec-pc-88 declares DISK.ROM with an empty md5. QUASI88 reads that
|
|
name as n88sub.rom, the 2 KB PC-88 disk ROM (libretro.c:1085), but the name
|
|
step served the 16 KB MSX disk ROM, the only primary called DISK.ROM. The
|
|
quasi88 alias could not point the name at the PC-88 file, since by_name
|
|
refuses an alias a primary already carries. by_shadowed_alias keeps it, and
|
|
the resolver reads it only once the system's own maker folder is all that
|
|
remains.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tests # noqa: F401 offline, scratch under tmp/, the suite's own cache
|
|
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
import common # noqa: E402
|
|
import generate_db # noqa: E402
|
|
import generate_pack as builder # noqa: E402
|
|
import generate_site # noqa: E402
|
|
from verify import verify_platform # noqa: E402
|
|
|
|
MSX_DISK = b"M" * 16384
|
|
PC88_DISK = b"N" * 2048
|
|
|
|
QUASI88 = """\
|
|
emulator: QUASI88
|
|
type: libretro
|
|
systems: [nec-pc-88]
|
|
cores: [quasi88]
|
|
files:
|
|
- name: n88sub.rom
|
|
path: quasi88/n88sub.rom
|
|
required: false
|
|
aliases: [N88SUB.ROM, DISK.ROM]
|
|
"""
|
|
|
|
PLATFORM = {
|
|
"platform": "Handheld",
|
|
"version": "1",
|
|
"verification_mode": "md5",
|
|
"base_destination": "",
|
|
"cores": ["quasi88"],
|
|
"systems": {
|
|
"nec-pc-88": {
|
|
"files": [
|
|
{"name": "DISK.ROM", "destination": "bios/quasi88/DISK.ROM",
|
|
"required": True},
|
|
],
|
|
},
|
|
"microsoft-msx": {
|
|
"files": [
|
|
{"name": "DISK.ROM", "destination": "bios/Machines/DISK.ROM",
|
|
"required": True},
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
class _Collection(unittest.TestCase):
|
|
def setUp(self):
|
|
(REPO_ROOT / "tmp").mkdir(exist_ok=True)
|
|
self._tmp = tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp")
|
|
self._cwd = os.getcwd()
|
|
os.chdir(self._tmp.name)
|
|
for relative, payload in (
|
|
("bios/Microsoft/MSX/DISK.ROM", MSX_DISK),
|
|
("bios/NEC/PC-88/n88sub.rom", PC88_DISK),
|
|
):
|
|
Path(relative).parent.mkdir(parents=True, exist_ok=True)
|
|
Path(relative).write_bytes(payload)
|
|
Path("emulators").mkdir()
|
|
Path("platforms").mkdir()
|
|
Path("emulators/quasi88.yml").write_text(QUASI88)
|
|
Path("platforms/handheld.yml").write_text(yaml.dump(PLATFORM))
|
|
Path("platforms/_registry.yml").write_text(
|
|
yaml.dump({"platforms": {"handheld": {"config": "handheld.yml"}}})
|
|
)
|
|
subprocess.run(
|
|
[sys.executable, str(REPO_ROOT / "scripts/generate_db.py"), "--force",
|
|
"--bios-dir", "bios", "--output", "database.json"],
|
|
check=True, capture_output=True,
|
|
)
|
|
self.db = common.load_database("database.json")
|
|
common._platform_config_cache.clear()
|
|
common._emulator_profiles_cache.clear()
|
|
self.config = common.load_platform_config("handheld", "platforms")
|
|
self.profiles = common.load_emulator_profiles("emulators")
|
|
|
|
def tearDown(self):
|
|
common._platform_config_cache.clear()
|
|
common._emulator_profiles_cache.clear()
|
|
os.chdir(self._cwd)
|
|
self._tmp.cleanup()
|
|
|
|
def _entry(self, system: str) -> dict:
|
|
return self.config["systems"][system]["files"][0]
|
|
|
|
def _manifest(self) -> dict:
|
|
return builder.generate_manifest(
|
|
"handheld", "platforms", self.db, "bios", "platforms/_registry.yml",
|
|
emulators_dir="emulators", emu_profiles=self.profiles, offline=True,
|
|
)
|
|
|
|
|
|
class ShadowedAliasIndex(_Collection):
|
|
def test_the_alias_a_primary_carries_is_kept_apart(self):
|
|
sha1 = hashlib.sha1(PC88_DISK).hexdigest()
|
|
indexes = self.db["indexes"]
|
|
self.assertEqual(indexes["by_shadowed_alias"]["DISK.ROM"], [sha1])
|
|
self.assertNotIn(sha1, indexes["by_name"]["DISK.ROM"])
|
|
|
|
def test_an_entry_with_no_single_content_designates_nothing(self):
|
|
shadowed = [("a.rom", set(), ["B.ROM"]), ("c.rom", {"1" * 40}, ["B.ROM"])]
|
|
by_name = {"a.rom": ["2" * 40, "3" * 40], "B.ROM": ["4" * 40]}
|
|
self.assertEqual(
|
|
generate_db.shadowed_alias_index(shadowed, by_name), {"B.ROM": ["1" * 40]}
|
|
)
|
|
|
|
|
|
class DiskRomGoesToThePc88File(_Collection):
|
|
def test_the_entry_knows_its_system(self):
|
|
self.assertEqual(self._entry("nec-pc-88")["platform_system"], "nec-pc-88")
|
|
|
|
def test_resolution(self):
|
|
entry = self._entry("nec-pc-88")
|
|
path, status = common.resolve_local_file(
|
|
entry, self.db, dest_hint=entry["destination"]
|
|
)
|
|
self.assertEqual((path, status), ("bios/NEC/PC-88/n88sub.rom", "name_exact"))
|
|
|
|
def test_the_msx_system_keeps_the_msx_file(self):
|
|
entry = self._entry("microsoft-msx")
|
|
path, _status = common.resolve_local_file(
|
|
entry, self.db, dest_hint=entry["destination"]
|
|
)
|
|
self.assertEqual(path, "bios/Microsoft/MSX/DISK.ROM")
|
|
|
|
def test_a_declared_hash_still_decides(self):
|
|
entry = {**self._entry("nec-pc-88"), "md5": hashlib.md5(MSX_DISK).hexdigest()}
|
|
path, status = common.resolve_local_file(entry, self.db)
|
|
self.assertEqual((path, status), ("bios/Microsoft/MSX/DISK.ROM", "md5_exact"))
|
|
|
|
def test_an_emulator_entry_is_not_narrowed(self):
|
|
entry = {**self._entry("nec-pc-88"), "source_profile": "msx-emu"}
|
|
path, _status = common.resolve_local_file(entry, self.db)
|
|
self.assertEqual(path, "bios/Microsoft/MSX/DISK.ROM")
|
|
|
|
def test_no_pc88_copy_leaves_it_missing_not_mismatched(self):
|
|
Path("bios/NEC/PC-88/n88sub.rom").unlink()
|
|
entry = self._entry("nec-pc-88")
|
|
self.assertEqual(
|
|
common.resolve_local_file(entry, self.db, dest_hint=entry["destination"]),
|
|
(None, "not_found"),
|
|
)
|
|
|
|
def test_verify(self):
|
|
report = verify_platform(self.config, self.db, "emulators", self.profiles)
|
|
paths = {d["name"]: set() for d in report["details"]}
|
|
for d in report["details"]:
|
|
paths[d["name"]].add(d.get("path"))
|
|
self.assertEqual(
|
|
paths["DISK.ROM"],
|
|
{"bios/NEC/PC-88/n88sub.rom", "bios/Microsoft/MSX/DISK.ROM"},
|
|
)
|
|
|
|
def test_pack(self):
|
|
zip_path = builder.generate_pack(
|
|
"handheld", "platforms", self.db, "bios", "out",
|
|
emulators_dir="emulators", emu_profiles=self.profiles, offline=True,
|
|
)
|
|
with zipfile.ZipFile(zip_path) as zf:
|
|
self.assertEqual(zf.read("bios/quasi88/DISK.ROM"), PC88_DISK)
|
|
self.assertEqual(zf.read("bios/Machines/DISK.ROM"), MSX_DISK)
|
|
|
|
def test_the_manifest_changes_only_that_row(self):
|
|
manifest = self._manifest()
|
|
original = (common.load_platform_config, common.system_makers)
|
|
|
|
def untagged(*args, **kwargs):
|
|
config = original[0](*args, **kwargs)
|
|
for system in config["systems"].values():
|
|
for f in system.get("files") or []:
|
|
f.pop("platform_system", None)
|
|
return config
|
|
|
|
common._platform_config_cache.clear()
|
|
builder.load_platform_config = common.load_platform_config = untagged
|
|
common.system_makers = lambda *args: frozenset()
|
|
try:
|
|
before = self._manifest()
|
|
finally:
|
|
builder.load_platform_config = common.load_platform_config = original[0]
|
|
common.system_makers = original[1]
|
|
common._platform_config_cache.clear()
|
|
rows = {f["dest"]: f for f in manifest["files"]}
|
|
old_rows = {f["dest"]: f for f in before["files"]}
|
|
self.assertEqual(rows["bios/quasi88/DISK.ROM"]["size"], len(PC88_DISK))
|
|
self.assertEqual(old_rows["bios/quasi88/DISK.ROM"]["size"], len(MSX_DISK))
|
|
del rows["bios/quasi88/DISK.ROM"], old_rows["bios/quasi88/DISK.ROM"]
|
|
self.assertEqual(rows, old_rows)
|
|
moved = len(MSX_DISK) - len(PC88_DISK)
|
|
for key in ("total_size", "pack_size"):
|
|
self.assertEqual(before[key] - manifest[key], moved)
|
|
changed = {"files", "total_size", "pack_size", "generated"}
|
|
self.assertEqual(
|
|
json.dumps({k: v for k, v in manifest.items() if k not in changed}, sort_keys=True),
|
|
json.dumps({k: v for k, v in before.items() if k not in changed}, sort_keys=True),
|
|
)
|
|
|
|
|
|
class SiteSharesTheMakerTest(unittest.TestCase):
|
|
def test_one_copy(self):
|
|
self.assertIs(generate_site.names_manufacturer, common.names_manufacturer)
|
|
self.assertIs(generate_site.BUCKET_FOLDERS, common.BUCKET_FOLDERS)
|
|
|
|
|
|
class NoHashlessNameMatchCrossesMakers(unittest.TestCase):
|
|
"""Every registered platform: a name match never lands on another maker."""
|
|
|
|
def test_registry(self):
|
|
self.addCleanup(os.chdir, os.getcwd())
|
|
os.chdir(REPO_ROOT)
|
|
db_path = REPO_ROOT / "database.json"
|
|
if not db_path.exists():
|
|
self.skipTest("database.json not built")
|
|
db = common.load_database(str(db_path))
|
|
registry = common.load_data_dir_registry("platforms")
|
|
folders = {
|
|
parts[1]
|
|
for entry in db["files"].values()
|
|
if len(parts := entry["path"].split("/")) >= 3 and parts[0] == "bios"
|
|
} - common.BUCKET_FOLDERS
|
|
crossings = []
|
|
for platform in common.list_registered_platforms("platforms"):
|
|
config = common.load_platform_config(platform, "platforms")
|
|
for sys_id, system in config.get("systems", {}).items():
|
|
makers = {f for f in folders if common.names_manufacturer(sys_id, f)}
|
|
if not makers:
|
|
continue
|
|
for entry in system.get("files") or []:
|
|
if any(entry.get(k) for k in ("sha1", "md5", "sha256", "crc32")):
|
|
continue
|
|
path, status = common.resolve_local_file(
|
|
entry, db, dest_hint=entry.get("destination", ""),
|
|
data_dir_registry=registry,
|
|
)
|
|
parts = (path or "").split("/")
|
|
if (
|
|
status.startswith("name")
|
|
and len(parts) >= 3
|
|
and parts[0] == "bios"
|
|
and parts[1] not in common.BUCKET_FOLDERS
|
|
and parts[1] not in makers
|
|
):
|
|
crossings.append(f"{platform} {sys_id} {entry.get('name')}: {path}")
|
|
self.assertEqual(crossings, [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|