mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-21 11:19:11 -05:00
The five native libraries the reprofile added, and the assets and libraries whose copies dated from 1.8.2-open, now come from the official build of 752b93a (release continuous, CI run 39297510978, signing certificate de1bd54d as on 1.8.2). Assets match the repository blobs byte for byte. The profile carries their hashes, and the bundled-identity table now records each fall exactly.
147 lines
4.5 KiB
Python
147 lines
4.5 KiB
Python
"""A bundled file is identified by its bytes, not its name.
|
|
|
|
ZEsarUX ships ace.rom and a patched alternate_roms/ace.rom, Azahar a default
|
|
keys.txt, ARMSX2 an OpenGL and a Vulkan cas.glsl. Declared without a hash,
|
|
each resolved by its bare name to whatever shared it: the patched ROM at the
|
|
original's slot, the Wii U disc keys at the 3DS key slot, the OpenGL shader
|
|
at the Vulkan one. An entry with a hash resolves by content first.
|
|
|
|
512 bundled entries still carry neither a hash nor `unsourceable:`. The
|
|
count per profile may only fall, and the table records each fall: a new
|
|
entry is written with the hash of the file the emulator ships.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
from common import load_database, resolve_local_file # noqa: E402
|
|
|
|
UNIDENTIFIED = {
|
|
"abuse": 3,
|
|
"aethersx2": 1,
|
|
"altirra": 2,
|
|
"arcadeflashweb": 8,
|
|
"armsx2": 58,
|
|
"ax360e": 2,
|
|
"bluemsx": 14,
|
|
"c64-emu": 8,
|
|
"cdogs": 16,
|
|
"citra-mmj": 9,
|
|
"drastic": 10,
|
|
"eka2l1": 89,
|
|
"emucorev": 1,
|
|
"emucorex": 23,
|
|
"epsxe": 2,
|
|
"fpse": 7,
|
|
"fpse-ng": 7,
|
|
"future-pinball": 18,
|
|
"future-pinball-fploader": 52,
|
|
"gba-emu": 1,
|
|
"hakux": 1,
|
|
"hcl": 3,
|
|
"hurrican": 1,
|
|
"idtech4a++": 1,
|
|
"ikemen": 32,
|
|
"ines": 2,
|
|
"jl-mod": 22,
|
|
"kemulator": 4,
|
|
"mastergear": 2,
|
|
"mfme": 58,
|
|
"msx-emu": 9,
|
|
"my-boy": 1,
|
|
"neo-emu": 3,
|
|
"nethersx2": 2,
|
|
"nethersx2-turnip": 2,
|
|
"nethersx2-turnip-classic": 2,
|
|
"nuance": 1,
|
|
"pcee2": 1,
|
|
"pcsx2": 1,
|
|
"project64": 9,
|
|
"sixtyforce": 5,
|
|
"skyline": 9,
|
|
"ssf": 1,
|
|
"supermodel-dojo": 4,
|
|
"x1-box": 1,
|
|
"xendroid": 1,
|
|
"xm6pro68k": 2,
|
|
"yaps2": 1,
|
|
}
|
|
|
|
|
|
def _unidentified() -> dict[str, int]:
|
|
counts: dict[str, int] = {}
|
|
for path in sorted((REPO_ROOT / "emulators").glob("*.yml")):
|
|
document = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
for entry in document.get("files") or []:
|
|
if not isinstance(entry, dict) or not entry.get("bundled"):
|
|
continue
|
|
if entry.get("unsourceable") or entry.get("type") == "directory":
|
|
continue
|
|
if any(entry.get(key) for key in ("sha1", "md5", "sha256", "crc32")):
|
|
continue
|
|
counts[path.stem] = counts.get(path.stem, 0) + 1
|
|
return counts
|
|
|
|
|
|
class BundledFilesCarryTheirIdentity(unittest.TestCase):
|
|
def test_no_profile_adds_an_unidentified_bundled_file(self):
|
|
grown = {
|
|
name: (count, UNIDENTIFIED.get(name, 0))
|
|
for name, count in _unidentified().items()
|
|
if count > UNIDENTIFIED.get(name, 0)
|
|
}
|
|
self.assertEqual(grown, {}, "bundled entries need the shipped file's hash")
|
|
|
|
def test_the_table_records_every_fall(self):
|
|
# A baseline above the real count lets that profile grow back unseen:
|
|
# j2me-loader kept 14 after its 18 bundled files were all identified.
|
|
self.assertEqual(_unidentified(), UNIDENTIFIED)
|
|
|
|
|
|
class TheFixedEntriesGetTheirOwnBytes(unittest.TestCase):
|
|
CASES = (
|
|
("azahar", "sysdata/keys.txt"),
|
|
("azaharplus", "sysdata/keys.txt"),
|
|
("zesarux", "ace.rom"),
|
|
("zesarux", "alternate_roms/ace.rom"),
|
|
("zesarux", "coleco.rom"),
|
|
("zesarux", "trdos.rom"),
|
|
("armsx2", "pcsx2/resources/shaders/vulkan/cas.glsl"),
|
|
)
|
|
|
|
def test_each_resolves_to_the_declared_hash(self):
|
|
db_path = REPO_ROOT / "database.json"
|
|
if not db_path.exists():
|
|
self.skipTest("database.json is not built")
|
|
db = load_database(str(db_path))
|
|
for profile, destination in self.CASES:
|
|
with self.subTest(profile=profile, destination=destination):
|
|
document = yaml.safe_load(
|
|
(REPO_ROOT / "emulators" / f"{profile}.yml").read_text(encoding="utf-8")
|
|
)
|
|
entry = next(
|
|
e for e in document["files"]
|
|
if (e.get("path") or e["name"]) == destination
|
|
)
|
|
local, _status = resolve_local_file(
|
|
{**entry, "source_profile": profile}, db, dest_hint=destination
|
|
)
|
|
self.assertIsNotNone(local)
|
|
self.assertEqual(
|
|
hashlib.sha1((REPO_ROOT / local).read_bytes()).hexdigest(),
|
|
entry["sha1"],
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|