mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-21 03:09:08 -05:00
Profiles, the wiki, comments, docstrings, command output and schema descriptions carried em-dashes, clause-joining semicolons, unicode arrows, box-drawing banners and check-mark glyphs. Each sentence was rewritten rather than having its character swapped. Hashes, paths, source_ref values and every cited file:line are unchanged, which a comparison of each parsed profile against the previous revision confirms. validate_pr comments now say PASS and FAIL in words, and source_ref values in a profile's structured blocks render as code. test_prose_style fails if any of these comes back, in tracked files or in the generated site.
118 lines
4.8 KiB
Python
118 lines
4.8 KiB
Python
"""A custom pack built from hashes follows the emulator it names, or refuses.
|
|
|
|
`--from-md5 --emulator` accepted any name: an unknown one produced a generic
|
|
pack in the layout of no emulator, rc 0, where `--emulator` alone refuses it.
|
|
With a known one and `--standalone`, a profile without pack_structure kept
|
|
the bare file names under a pack called Standalone.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
import zipfile
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def _pack(*options: str) -> tuple[subprocess.CompletedProcess, list[str]]:
|
|
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as out:
|
|
proc = subprocess.run(
|
|
[sys.executable, "scripts/generate_pack.py", *options, "--offline",
|
|
"--output-dir", out],
|
|
cwd=REPO_ROOT, capture_output=True, text=True, timeout=600, check=False,
|
|
)
|
|
names = []
|
|
for archive in Path(out).glob("*.zip"):
|
|
with zipfile.ZipFile(archive) as zf:
|
|
names.extend(zf.namelist())
|
|
return proc, names
|
|
|
|
|
|
class TheEmulatorContextIsChecked(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
db_path = REPO_ROOT / "database.json"
|
|
if not db_path.exists():
|
|
raise unittest.SkipTest("database.json is not built")
|
|
(REPO_ROOT / "tmp").mkdir(exist_ok=True)
|
|
cls.db = json.loads(db_path.read_text(encoding="utf-8"))
|
|
|
|
def test_an_unknown_emulator_is_refused(self):
|
|
md5 = next(iter(self.db["files"].values()))["md5"]
|
|
proc, names = _pack("--from-md5", md5, "--emulator", "no_such_core")
|
|
self.assertNotEqual(proc.returncode, 0, proc.stdout)
|
|
self.assertIn("not found", proc.stderr)
|
|
self.assertEqual(names, [])
|
|
|
|
|
|
def test_the_standalone_layout_reaches_a_profile_without_structure(self):
|
|
"""BBKEmu has no pack_structure, and its A4980 8.BIN goes to
|
|
system/BBKEmu/A4980/ standalone. The hash pack kept the bare name,
|
|
then, once laid out, sent it to the A4988 folder whose entry shares
|
|
the name."""
|
|
md5 = "ddfc001a6859d63ed46368ea7fe9f20c"
|
|
if not any(record.get("md5") == md5 for record in self.db["files"].values()):
|
|
self.skipTest("the A4980 8.BIN is not collected")
|
|
proc, names = _pack("--from-md5", md5, "--emulator", "bbkemu", "--standalone")
|
|
self.assertEqual(proc.returncode, 0, proc.stderr)
|
|
self.assertEqual(names, ["system/BBKEmu/A4980/8.BIN"])
|
|
|
|
|
|
class SystemAndEmulatorPacksKeepTheirNames(unittest.TestCase):
|
|
"""`--system sega-triforce` and `--emulator triforce` both wrote
|
|
Triforce_BIOS_Pack.zip: whichever ran second replaced the other."""
|
|
|
|
def test_the_two_selections_write_two_files(self):
|
|
import hashlib
|
|
|
|
import yaml
|
|
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
import common
|
|
import generate_db
|
|
import generate_pack as gp
|
|
|
|
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as directory:
|
|
root = Path(directory)
|
|
(root / "bios").mkdir()
|
|
(root / "emulators").mkdir()
|
|
out = root / "dist"
|
|
payload = b"triforce bios"
|
|
(root / "bios" / "segaboot.gcm").write_bytes(payload)
|
|
sha1 = hashlib.sha1(payload).hexdigest()
|
|
files = {sha1: {
|
|
"path": str(root / "bios" / "segaboot.gcm"), "name": "segaboot.gcm",
|
|
"size": len(payload), "sha1": sha1,
|
|
"md5": hashlib.md5(payload).hexdigest(),
|
|
"sha256": hashlib.sha256(payload).hexdigest(), "crc32": "0",
|
|
}}
|
|
db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
|
|
(root / "emulators" / "triforce.yml").write_text(yaml.dump({
|
|
"emulator": "Triforce", "type": "libretro", "cores": ["triforce"],
|
|
"systems": ["sega-triforce"],
|
|
"files": [{"name": "segaboot.gcm", "required": True}],
|
|
}))
|
|
common._emulator_profiles_cache.clear()
|
|
try:
|
|
emulator_pack = gp.generate_emulator_pack(
|
|
["triforce"], str(root / "emulators"), db, str(root / "bios"),
|
|
str(out), offline=True,
|
|
)
|
|
system_pack = gp.generate_system_pack(
|
|
["sega-triforce"], str(root / "emulators"), db,
|
|
str(root / "bios"), str(out), offline=True,
|
|
)
|
|
finally:
|
|
common._emulator_profiles_cache.clear()
|
|
self.assertNotEqual(Path(emulator_pack).name, Path(system_pack).name)
|
|
self.assertTrue(Path(emulator_pack).exists())
|
|
self.assertTrue(Path(system_pack).exists())
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|