Files
libretro/tests/test_extra_identity.py
T

151 lines
6.8 KiB
Python

"""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
from packextras import _collect_emulator_extras # noqa: E402
from verify import find_undeclared_files # 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):
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)
class UnsourceableIsNoCopy(unittest.TestCase):
"""The second pass copies a covered file to another core's path by name.
zc210 ships its own default.sf2; dosbox-staging reads a default.sf2 that
the operating system links to its SoundFont, which no collection holds.
The name was enough to give dosbox-staging a slot, recorded as missing
while zc210 was in the pack and absent once it was not, so a pack built
for a target disagreed with the installer narrowing the full list.
"""
def test_an_unsourceable_entry_gets_no_copy(self):
profiles = {
"zc210": {"emulator": "ZC", "type": "libretro", "systems": ["zc"],
"files": [{"name": "default.sf2", "path": "zc210/sf2/default.sf2"}]},
"dosbox-staging": {
"emulator": "DOSBox Staging", "type": "libretro", "systems": ["dos"],
"files": [{"name": "default.sf2", "path": "soundfonts/default.sf2",
"required": False, "unsourceable": "the system's own link"}],
},
}
config = {"cores": ["zc210", "dosbox-staging"], "systems": {}}
db = {
"files": {"s1": {"name": "default.sf2", "path": "bios/ZC/default.sf2",
"size": 10, "sha1": "s1", "md5": "m1", "crc32": "c1"}},
"indexes": {"by_name": {"default.sf2": ["s1"]}, "by_md5": {"m1": "s1"},
"by_crc32": {"c1": "s1"},
"by_path_suffix": {"zc210/sf2/default.sf2": ["s1"]}},
}
extras = _collect_emulator_extras(config, "emulators", db, set(), "", profiles)
self.assertEqual(
[(e["source_profile"], e["destination"]) for e in extras],
[("zc210", "zc210/sf2/default.sf2")],
)
class BareNameIsADestination(unittest.TestCase):
"""geargrafx reads syscard1.pce at the root of the system directory;
Recalbox declares it only under pcenginecd/. The declaration settles the
core's need on the promise that the builder copies the file to the
core's path, and the second pass skipped every entry with no path."""
def test_a_root_copy_of_a_file_declared_in_a_subdirectory(self):
profiles = {"geargrafx": {
"emulator": "Geargrafx", "type": "libretro", "systems": ["pce"],
"files": [{"name": "syscard1.pce"}],
}}
config = {"cores": ["geargrafx"], "systems": {"pcenginecd": {"files": [
{"name": "syscard1.pce", "destination": "pcenginecd/syscard1.pce"}]}}}
db = {
"files": {"s1": {"name": "syscard1.pce", "path": "bios/NEC/syscard1.pce",
"size": 10, "sha1": "s1", "md5": "m1", "crc32": "c1"}},
"indexes": {"by_name": {"syscard1.pce": ["s1"]}, "by_md5": {"m1": "s1"},
"by_crc32": {"c1": "s1"}, "by_path_suffix": {}},
}
extras = _collect_emulator_extras(
config, "emulators", db, {"pcenginecd/syscard1.pce"}, "", profiles
)
self.assertIn("syscard1.pce", [e["destination"] for e in extras])
class ArchiveMembersStayInside(unittest.TestCase):
"""fbneo reads msx.rom inside msx.zip. Once the second pass copied bare
names, it wrote that member loose at the root as soon as another core's
msx.rom covered the name, and 000-lo.lo landed beside neogeo.zip."""
def test_no_loose_copy_of_a_member(self):
profiles = {
"zesarux": {"emulator": "ZEsarUX", "type": "libretro", "systems": ["msx"],
"files": [{"name": "msx.rom"}]},
"fbneo": {"emulator": "FBNeo", "type": "libretro", "systems": ["msx"],
"files": [{"name": "msx.rom", "archive": "msx.zip"}]},
}
config = {"cores": ["zesarux", "fbneo"], "systems": {}}
db = {
"files": {"s1": {"name": "msx.rom", "path": "bios/MSX/msx.rom",
"size": 10, "sha1": "s1", "md5": "m1", "crc32": "c1"}},
"indexes": {"by_name": {"msx.rom": ["s1"]}, "by_md5": {"m1": "s1"},
"by_crc32": {"c1": "s1"}, "by_path_suffix": {}},
}
extras = _collect_emulator_extras(config, "emulators", db, set(), "", profiles)
loose = [e for e in extras if e["destination"] == "msx.rom"]
self.assertEqual([e["source_profile"] for e in loose], ["zesarux"])
if __name__ == "__main__":
unittest.main()