mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 21:43:23 -05:00
228 lines
9.0 KiB
Python
228 lines
9.0 KiB
Python
"""A declaration that conflicts with a packed path is counted by what it resolves to.
|
|
|
|
RetroArch declares SGB1.sfc as a file and SGB1.sfc/<rom> as files inside it.
|
|
The builder ships one shape and counted every conflicting declaration OK,
|
|
resolved or not; verify.py resolves each on its own. A required file absent
|
|
from the collection read as covered in the pack report and as missing in verify.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
import hashlib
|
|
import io
|
|
import re
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
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
|
|
from verify import verify_platform # noqa: E402
|
|
|
|
|
|
class ConflictingDeclarations(unittest.TestCase):
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
self.root = Path(self._tmp.name)
|
|
bios = self.root / "bios" / "Nintendo"
|
|
self.platforms = self.root / "platforms"
|
|
self.emulators = self.root / "emulators"
|
|
for directory in (bios, self.platforms, self.emulators):
|
|
directory.mkdir(parents=True)
|
|
payload = b"super game boy"
|
|
(bios / "SGB1.sfc").write_bytes(payload)
|
|
sha1 = hashlib.sha1(payload).hexdigest()
|
|
files = {
|
|
sha1: {
|
|
"path": str(bios / "SGB1.sfc"), "name": "SGB1.sfc",
|
|
"size": len(payload), "sha1": sha1,
|
|
"md5": hashlib.md5(payload).hexdigest(),
|
|
"sha256": hashlib.sha256(payload).hexdigest(), "crc32": "00000001",
|
|
}
|
|
}
|
|
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
|
platform = {
|
|
"platform": "Conflict",
|
|
"verification_mode": "existence",
|
|
"base_destination": "system",
|
|
"cores": [],
|
|
"systems": {
|
|
"nintendo-sgb": {"files": [
|
|
{"name": "SGB1.sfc", "destination": "SGB1.sfc", "required": True},
|
|
{"name": "nothere.rom", "destination": "SGB1.sfc/nothere.rom",
|
|
"required": True},
|
|
]},
|
|
},
|
|
}
|
|
(self.platforms / "conflict.yml").write_text(yaml.dump(platform))
|
|
(self.platforms / "_registry.yml").write_text(
|
|
yaml.dump({"platforms": {"conflict": {"status": "active"}}})
|
|
)
|
|
common._platform_config_cache.clear()
|
|
common._emulator_profiles_cache.clear()
|
|
|
|
def tearDown(self):
|
|
common._platform_config_cache.clear()
|
|
self._tmp.cleanup()
|
|
|
|
def test_the_pack_and_verify_count_alike(self):
|
|
out = self.root / "dist"
|
|
out.mkdir()
|
|
report = io.StringIO()
|
|
with contextlib.redirect_stdout(report):
|
|
builder.generate_pack(
|
|
"conflict", str(self.platforms), self.db, str(self.root / "bios"),
|
|
str(out), emulators_dir=str(self.emulators), emu_profiles={},
|
|
offline=True,
|
|
)
|
|
packed = re.search(r"(\d+)/(\d+) files OK", report.getvalue())
|
|
self.assertIsNotNone(packed, report.getvalue())
|
|
|
|
config = common.load_platform_config("conflict", str(self.platforms))
|
|
verified = verify_platform(config, self.db, str(self.emulators))
|
|
counts = verified["status_counts"]
|
|
self.assertEqual(counts.get("missing"), 1)
|
|
self.assertEqual(
|
|
(int(packed.group(1)), int(packed.group(2))),
|
|
(counts.get("ok", 0), verified["total_files"]),
|
|
)
|
|
|
|
|
|
class AnExtraDoesNotPassAHashCheck(unittest.TestCase):
|
|
"""A md5 platform declares scph1001.bin with a hash the collection lacks;
|
|
a core declares our dump at the same path. The builder ships the core's
|
|
file and called the declaration OK, while the frontend, which hashes the
|
|
file, rejects it and verify reports it untested."""
|
|
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
self.root = Path(self._tmp.name)
|
|
bios = self.root / "bios" / "Sony"
|
|
self.platforms = self.root / "platforms"
|
|
self.emulators = self.root / "emulators"
|
|
for directory in (bios, self.platforms, self.emulators):
|
|
directory.mkdir(parents=True)
|
|
payload = b"our psx dump"
|
|
(bios / "psx-us.bin").write_bytes(payload)
|
|
sha1 = hashlib.sha1(payload).hexdigest()
|
|
md5 = hashlib.md5(payload).hexdigest()
|
|
files = {
|
|
sha1: {
|
|
"path": str(bios / "psx-us.bin"), "name": "psx-us.bin",
|
|
"size": len(payload), "sha1": sha1, "md5": md5,
|
|
"sha256": hashlib.sha256(payload).hexdigest(), "crc32": "00000002",
|
|
}
|
|
}
|
|
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
|
platform = {
|
|
"platform": "Hashed",
|
|
"verification_mode": "md5",
|
|
"cores": ["fxcore"],
|
|
"systems": {"sony-playstation": {"files": [
|
|
{"name": "scph1001.bin", "destination": "scph1001.bin",
|
|
"md5": "0123456789abcdef0123456789abcdef", "required": True},
|
|
]}},
|
|
}
|
|
(self.platforms / "hashed.yml").write_text(yaml.dump(platform))
|
|
(self.platforms / "_registry.yml").write_text(
|
|
yaml.dump({"platforms": {"hashed": {"status": "active"}}})
|
|
)
|
|
profile = {
|
|
"emulator": "FX", "type": "libretro", "cores": ["fxcore"],
|
|
"systems": ["sony-playstation"],
|
|
"files": [{"name": "psx-us.bin", "path": "scph1001.bin", "md5": md5,
|
|
"required": True}],
|
|
}
|
|
(self.emulators / "fxcore.yml").write_text(yaml.dump(profile))
|
|
common._platform_config_cache.clear()
|
|
common._emulator_profiles_cache.clear()
|
|
|
|
def tearDown(self):
|
|
common._platform_config_cache.clear()
|
|
common._emulator_profiles_cache.clear()
|
|
self._tmp.cleanup()
|
|
|
|
def test_the_declaration_stays_failed(self):
|
|
out = self.root / "dist"
|
|
out.mkdir()
|
|
report = io.StringIO()
|
|
with contextlib.redirect_stdout(report):
|
|
builder.generate_pack(
|
|
"hashed", str(self.platforms), self.db, str(self.root / "bios"),
|
|
str(out), emulators_dir=str(self.emulators), offline=True,
|
|
)
|
|
packed = re.search(r"(\d+)/(\d+) files OK", report.getvalue())
|
|
self.assertIsNotNone(packed, report.getvalue())
|
|
config = common.load_platform_config("hashed", str(self.platforms))
|
|
verified = verify_platform(config, self.db, str(self.emulators))
|
|
self.assertEqual(verified["status_counts"].get("ok", 0), 0)
|
|
self.assertEqual(int(packed.group(1)), 0, report.getvalue())
|
|
|
|
|
|
|
|
class TheEmulatorPackShipsWhatTheCoreAccepts(unittest.TestCase):
|
|
"""BasiliskII wants a 512 KB to 1 MB ROM. The only ROM held was 128 KB:
|
|
the emulator pack shipped it silently and verify --emulator announced
|
|
1/1 OK above the line saying the core would refuse it."""
|
|
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
self.root = Path(self._tmp.name)
|
|
bios = self.root / "bios" / "Apple"
|
|
self.emulators = self.root / "emulators"
|
|
for directory in (bios, self.emulators):
|
|
directory.mkdir(parents=True)
|
|
payload = b"r" * 131072
|
|
(bios / "ROM").write_bytes(payload)
|
|
sha1 = hashlib.sha1(payload).hexdigest()
|
|
files = {sha1: {
|
|
"path": str(bios / "ROM"), "name": "ROM", "size": len(payload),
|
|
"sha1": sha1, "md5": hashlib.md5(payload).hexdigest(),
|
|
"sha256": hashlib.sha256(payload).hexdigest(), "crc32": "00000003",
|
|
}}
|
|
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
|
profile = {
|
|
"emulator": "Mac", "type": "libretro", "cores": ["mac"],
|
|
"systems": ["apple-macintosh"],
|
|
"files": [{"name": "ROM", "required": True, "min_size": 524288,
|
|
"max_size": 1048576, "validation": ["size"]}],
|
|
}
|
|
(self.emulators / "mac.yml").write_text(yaml.dump(profile))
|
|
common._emulator_profiles_cache.clear()
|
|
|
|
def tearDown(self):
|
|
common._emulator_profiles_cache.clear()
|
|
self._tmp.cleanup()
|
|
|
|
def test_the_refused_rom_is_named_not_shipped(self):
|
|
import zipfile
|
|
|
|
out = self.root / "dist"
|
|
out.mkdir()
|
|
report = io.StringIO()
|
|
with contextlib.redirect_stdout(report):
|
|
zip_path = builder.generate_emulator_pack(
|
|
["mac"], str(self.emulators), self.db, str(self.root / "bios"),
|
|
str(out), offline=True,
|
|
)
|
|
self.assertIn("REFUSED: ROM", report.getvalue())
|
|
with zipfile.ZipFile(zip_path) as archive:
|
|
self.assertNotIn("ROM", archive.namelist())
|
|
|
|
def test_verify_does_not_call_it_ok(self):
|
|
from verify import Severity, verify_emulator
|
|
|
|
result = verify_emulator(["mac"], str(self.emulators), self.db)
|
|
self.assertEqual(result["severity_counts"][Severity.OK], 0)
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|