mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-24 12:49:03 -05:00
The install manifest marks each game data file "category": "game_data": a platform entry only game data profile entries read, or a core file its profile declares game data. Firmware carries no category. Every manifest says "categorized": true so the installer can refuse an older list. generate_pack.py --no-game-data cuts those files from the platform list and the core profiles before the build, names each one with the cores that read it as game data, and tags the pack _NoGameData through _narrowings. verify.py and the pack check take the same cut, so --verify-packs and the report describe the pack the builder wrote. Modes without a platform (--emulator, --system alone, --from-md5) and --all-variants refuse it.
195 lines
7.8 KiB
Python
195 lines
7.8 KiB
Python
"""verify.py lists what generate_pack.py lists for the same request."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def _run(*argv: str) -> subprocess.CompletedProcess:
|
|
return subprocess.run(
|
|
[sys.executable, *argv], capture_output=True, check=False, text=True, cwd=REPO_ROOT, timeout=300
|
|
)
|
|
|
|
|
|
class ListingsAgree(unittest.TestCase):
|
|
def test_list_systems_honours_platform(self):
|
|
verify = _run("scripts/verify.py", "--list-systems", "--platform", "bizhawk")
|
|
pack = _run("scripts/generate_pack.py", "--list-systems", "--platform", "bizhawk")
|
|
self.assertEqual(verify.returncode, 0)
|
|
self.assertEqual(verify.stdout, pack.stdout)
|
|
|
|
def test_listing_refuses_a_narrowing_flag(self):
|
|
result = _run("scripts/verify.py", "--list-emulators", "--region", "us")
|
|
self.assertNotEqual(result.returncode, 0)
|
|
|
|
|
|
class VerifyRefusesWhatAModeDoesNotRead(unittest.TestCase):
|
|
"""The mode x flag matrix generate_pack has, for verify.
|
|
|
|
--list-emulators --standalone printed the full list, --list-systems --json
|
|
printed columns, --platform --include-archived covered nothing more: each
|
|
with rc 0, each letting the caller believe the flag applied.
|
|
"""
|
|
|
|
MATRIX = (
|
|
(("--list-emulators",), "--standalone"),
|
|
(("--list-systems",), "--json"),
|
|
(("--list-targets", "--platform", "retroarch"), "--include-archived"),
|
|
(("--platform", "retroarch"), "--include-archived"),
|
|
(("--emulator", "handy"), "--include-archived"),
|
|
(("--platform", "retroarch"), "--standalone"),
|
|
# Game data is categorized against a platform's list and its cores.
|
|
(("--emulator", "handy"), "--no-game-data"),
|
|
(("--system", "atari-lynx"), "--no-game-data"),
|
|
(("--list-systems",), "--no-game-data"),
|
|
)
|
|
|
|
def test_each_combination_is_refused(self):
|
|
for mode, flag in self.MATRIX:
|
|
with self.subTest(mode=mode, flag=flag):
|
|
result = _run("scripts/verify.py", *mode, flag)
|
|
self.assertEqual(result.returncode, 2, result.stdout[-300:])
|
|
self.assertIn(flag, result.stderr)
|
|
|
|
def test_emulator_mode_reads_the_given_platforms_dir(self):
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import verify # noqa: PLC0415
|
|
|
|
seen: list[str] = []
|
|
|
|
def registry(path: str) -> dict:
|
|
seen.append(str(path))
|
|
return {}
|
|
|
|
db = {"files": {}, "indexes": {"by_name": {}, "by_md5": {}}}
|
|
with mock.patch.object(verify, "load_data_dir_registry", registry):
|
|
verify.verify_emulator(
|
|
["handy"], str(REPO_ROOT / "emulators"), db, platforms_dir="elsewhere"
|
|
)
|
|
self.assertEqual(seen, ["elsewhere"])
|
|
|
|
|
|
class VerifyAppliesWhatItAccepts(unittest.TestCase):
|
|
"""--verbose under --json was accepted in every mode and changed nothing;
|
|
the refusal matrix above could not see it, since nothing was refused."""
|
|
|
|
def test_verbose_changes_the_json_in_every_mode(self):
|
|
for mode in (("--platform", "bizhawk"), ("--emulator", "handy"),
|
|
("--system", "atari-lynx")):
|
|
with self.subTest(mode=mode):
|
|
plain = _run("scripts/verify.py", *mode, "--json")
|
|
verbose = _run("scripts/verify.py", *mode, "--json", "--verbose")
|
|
self.assertEqual((plain.returncode, verbose.returncode), (0, 0))
|
|
self.assertNotEqual(plain.stdout, verbose.stdout)
|
|
|
|
|
|
class EmulatorPackReadsThePlatformsDir(unittest.TestCase):
|
|
def test_the_registry_comes_from_the_given_dir(self):
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import generate_pack # noqa: PLC0415
|
|
|
|
seen: list[str] = []
|
|
|
|
def registry(path: str) -> dict:
|
|
seen.append(str(path))
|
|
return {}
|
|
|
|
db = {"files": {}, "indexes": {"by_name": {}, "by_md5": {}}}
|
|
out = REPO_ROOT / "tmp" / "emupack-registry"
|
|
with mock.patch.object(generate_pack, "load_data_dir_registry", registry):
|
|
generate_pack.generate_emulator_pack(
|
|
["handy"], str(REPO_ROOT / "emulators"), db, "bios", str(out),
|
|
zip_contents={}, platforms_dir="elsewhere",
|
|
)
|
|
for leftover in out.glob("*"):
|
|
leftover.unlink()
|
|
if out.exists():
|
|
out.rmdir()
|
|
self.assertEqual(seen, ["elsewhere"])
|
|
|
|
|
|
|
|
class CoreArchivesAreCounted(unittest.TestCase):
|
|
def test_a_missing_required_bios_zip_is_printed(self):
|
|
import contextlib # noqa: PLC0415
|
|
import io # noqa: PLC0415
|
|
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import verify # noqa: PLC0415
|
|
|
|
result = {"undeclared_files": [
|
|
{"name": "neogeo.zip", "category": "bios_zip", "required": True,
|
|
"in_repo": False, "emulator": "fbneo"},
|
|
]}
|
|
out = io.StringIO()
|
|
with contextlib.redirect_stdout(out):
|
|
verify._print_undeclared_section(result, verbose=False)
|
|
self.assertIn("1 required missing", out.getvalue())
|
|
self.assertIn("neogeo.zip", out.getvalue())
|
|
|
|
|
|
class ExistenceReportsWhatThePackReports(unittest.TestCase):
|
|
def test_a_contradicted_hash_is_a_discrepancy(self):
|
|
"""30 RetroArch entries printed DISCREPANCY in the pack, nothing in verify."""
|
|
import tempfile # noqa: PLC0415
|
|
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import verify # noqa: PLC0415
|
|
|
|
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
|
|
path = Path(tmp) / "aes.zip"
|
|
path.write_bytes(b"local dump")
|
|
entry = {"name": "aes.zip", "md5": "9d2ff2333e23910cf56f7f785609d36a"}
|
|
result = verify.verify_entry_existence(
|
|
entry, str(path), resolve_status="hash_mismatch", platform_display="RetroArch"
|
|
)
|
|
self.assertEqual(result["status"], verify.Status.OK)
|
|
self.assertIn("declared hash 9d2ff233", result["discrepancy"])
|
|
|
|
|
|
class TheDestinationsFlagNeedsAPack(unittest.TestCase):
|
|
"""--destinations describes a platform's full pack: another mode refuses it."""
|
|
|
|
def test_refused_outside_platform_modes(self):
|
|
for mode in (("--emulator", "handy"), ("--platform", "retroarch", "--region", "us")):
|
|
with self.subTest(mode=mode):
|
|
result = _run("scripts/verify.py", *mode, "--destinations", "tmp/never.json")
|
|
self.assertEqual(result.returncode, 2, result.stdout[-300:])
|
|
self.assertIn("--destinations", result.stderr)
|
|
|
|
|
|
class EveryGapCountedIsNamed(unittest.TestCase):
|
|
"""verify --platform batocera --verbose counted 3 optional core files and
|
|
427 game data files missing and named none of them."""
|
|
|
|
def test_verbose_names_them_and_the_summary_says_how(self):
|
|
import contextlib
|
|
import io
|
|
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import verify # noqa: PLC0415
|
|
|
|
result = {"undeclared_files": [
|
|
{"name": "opt.rom", "emulator": "core", "required": False, "in_repo": False},
|
|
{"name": "level.dat", "emulator": "engine", "required": True, "in_repo": False,
|
|
"category": "game_data"},
|
|
]}
|
|
with contextlib.redirect_stdout(io.StringIO()) as quiet:
|
|
verify._print_undeclared_section(result, verbose=False)
|
|
self.assertIn("1 optional missing (--verbose lists them)", quiet.getvalue())
|
|
self.assertIn("1 missing (--verbose lists them)", quiet.getvalue())
|
|
with contextlib.redirect_stdout(io.StringIO()) as verbose:
|
|
verify._print_undeclared_section(result, verbose=True)
|
|
self.assertIn("MISSING (optional): core needs opt.rom", verbose.getvalue())
|
|
self.assertIn("MISSING (game data): engine needs level.dat", verbose.getvalue())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|