mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-11 14:03:23 -05:00
165 lines
7.6 KiB
Python
165 lines
7.6 KiB
Python
"""An export writes what its summary announces, and nothing else.
|
|
|
|
RetroDECK announced 1474 additions and wrote none, counted 161 requirement
|
|
corrections while keeping the platform's prose labels, and wrote one
|
|
system's ATARIOSB.ROM over another's. RetroBat and EmuDeck turned empty or
|
|
partial hash lists into content checks nobody counted, and a size was taken
|
|
from a file other than the one the hash describes.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import unittest
|
|
from collections import OrderedDict
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
from exporter.baseline import NativeFile, NativeSystem, build_native_model # noqa: E402
|
|
from exporter.emudeck_exporter import Exporter as EmuDeck # noqa: E402
|
|
from exporter.retrobat_exporter import Exporter as RetroBat # noqa: E402
|
|
from exporter.retrodeck_exporter import Exporter as RetroDeck # noqa: E402
|
|
|
|
A = "a" * 32
|
|
B = "b" * 32
|
|
C = "c" * 32
|
|
|
|
|
|
class RetroDeckWritesWhatItCounts(unittest.TestCase):
|
|
def test_same_name_in_two_systems_stays_two_entries(self):
|
|
existing = [
|
|
{"filename": "ATARIOSB.ROM", "system": "atari5200", "md5": f"{A},{B}"},
|
|
{"filename": "ATARIOSB.ROM", "system": "atari800", "md5": B},
|
|
]
|
|
ours = [
|
|
OrderedDict(filename="ATARIOSB.ROM", system="atari800", md5=C),
|
|
]
|
|
merged = RetroDeck._merge(existing, ours)
|
|
by_system = {e["system"]: e["md5"] for e in merged}
|
|
self.assertEqual(by_system, {"atari5200": f"{A},{B}", "atari800": C})
|
|
self.assertEqual(len(merged), 2)
|
|
|
|
def test_a_list_of_systems_is_kept(self):
|
|
existing = [{"filename": "neogeo.zip", "system": ["neogeo", "fbneo"], "md5": A}]
|
|
ours = [OrderedDict(filename="neogeo.zip", system="fbneo", md5=B)]
|
|
merged = RetroDeck._merge(existing, ours)
|
|
self.assertEqual(len(merged), 1)
|
|
self.assertEqual(merged[0]["system"], ["neogeo", "fbneo"])
|
|
self.assertEqual(merged[0]["md5"], B)
|
|
|
|
def test_prose_label_is_neither_rewritten_nor_counted(self):
|
|
exporter = RetroDeck()
|
|
prose = NativeFile(
|
|
"x.bin", "bios/x.bin", "psx",
|
|
platform={"required": True, "required_label": "At least one BIOS file required"},
|
|
truth={"required": False},
|
|
)
|
|
plain = NativeFile(
|
|
"y.bin", "bios/y.bin", "psx",
|
|
platform={"required": True, "required_label": "Required"},
|
|
truth={"required": False},
|
|
)
|
|
self.assertFalse(exporter.states(prose, "required"))
|
|
self.assertEqual(RetroDeck._entry(prose)["required"], "At least one BIOS file required")
|
|
self.assertTrue(exporter.states(plain, "required"))
|
|
self.assertEqual(RetroDeck._entry(plain)["required"], "Optional")
|
|
|
|
def test_addition_goes_to_the_system_component(self):
|
|
declared = NativeFile("a.bin", "bios/a.bin", "psx",
|
|
platform={"component": "duckstation", "md5": A})
|
|
added = NativeFile("b.bin", "bios/b.bin", "psx", truth={"md5": B})
|
|
spread = NativeSystem("amiga", files=[
|
|
NativeFile("k1", "bios/k1", "amiga", platform={"component": "retroarch"}),
|
|
NativeFile("k2", "bios/k2", "amiga", platform={"component": "puae"}),
|
|
NativeFile("k3", "bios/k3", "amiga", truth={"md5": C}),
|
|
])
|
|
systems = {"psx": NativeSystem("psx", files=[declared, added]), "amiga": spread}
|
|
manifest = json.dumps({"duckstation": {"name": "DuckStation", "bios": []}})
|
|
produced = RetroDeck().render(
|
|
systems, None, {"duckstation/component_manifest.json": manifest}
|
|
)
|
|
written = json.loads(produced["duckstation/component_manifest.json"])
|
|
names = [e["filename"] for e in written["duckstation"]["bios"]]
|
|
self.assertIn("b.bin", names)
|
|
self.assertFalse(RetroDeck.writable(spread.files[2]))
|
|
|
|
|
|
class HashesTheFormatCannotHold(unittest.TestCase):
|
|
def test_retrobat_fills_only_a_single_accepted_value(self):
|
|
exporter = RetroBat()
|
|
single = NativeFile("s.bin", "s.bin", "nds", platform={"md5": ""},
|
|
truth={"md5": A}, filled=["md5"])
|
|
several = NativeFile("m.bin", "m.bin", "nds", platform={"md5": ""},
|
|
truth={"md5": [A, B]}, filled=["md5"])
|
|
self.assertEqual(RetroBat._md5(single), A)
|
|
self.assertTrue(exporter.states(single, "md5"))
|
|
self.assertEqual(RetroBat._md5(several), "")
|
|
self.assertFalse(exporter.states(several, "md5"))
|
|
|
|
def test_emudeck_never_grows_an_array(self):
|
|
unhashed = NativeFile("scph5501.bin", "scph5501.bin", "psx",
|
|
platform={"md5": ""}, truth={"md5": C}, filled=["md5"])
|
|
extra = NativeFile("scph1001.bin", "scph1001.bin", "psx",
|
|
platform={"md5": A}, truth={"md5": [A, B]})
|
|
corrected = NativeFile("scph7001.bin", "scph7001.bin", "psx",
|
|
platform={"md5": B}, truth={"md5": C},
|
|
corrections=["md5"])
|
|
systems = {"psx": NativeSystem("psx", files=[unhashed, extra, corrected])}
|
|
self.assertEqual(EmuDeck._md5s(systems, "psx"), [A, C])
|
|
self.assertFalse(EmuDeck().states(unhashed, "md5"))
|
|
|
|
|
|
class ModelKeepsOneFileOneEntry(unittest.TestCase):
|
|
def test_size_describes_the_hash_written(self):
|
|
fe = NativeFile("boot.bin", "dc/boot.bin", "dc",
|
|
platform={"size": 2097152, "md5": A}, truth={"size": 480})
|
|
self.assertEqual(fe.size(), 2097152)
|
|
hashed = NativeFile("boot.bin", "dc/boot.bin", "dc",
|
|
platform={"size": 2097152, "md5": A},
|
|
truth={"size": 480, "md5": B})
|
|
self.assertEqual(hashed.size(), 480)
|
|
|
|
def test_second_core_entry_for_a_declared_file_adds_nothing(self):
|
|
scraped = {"systems": {"psx": {"files": [
|
|
{"name": "scph101.bin", "destination": "bios/scph101.bin", "md5": A},
|
|
]}}}
|
|
truth = {"systems": {"psx": {"files": [
|
|
{"name": "scph101.bin", "path": "scph101.bin", "md5": A},
|
|
{"name": "scph101.bin", "path": "scph101.bin", "md5": B},
|
|
]}}}
|
|
systems, report = build_native_model(truth, scraped)
|
|
self.assertEqual(report.files_added, 0)
|
|
self.assertEqual(len(systems["psx"].files), 1)
|
|
|
|
|
|
class OneFileOneIdentity(unittest.TestCase):
|
|
def test_a_contradicting_truth_does_not_borrow_platform_fields(self):
|
|
fe = NativeFile("boot.bin", "dc/boot.bin", "dc",
|
|
platform={"size": 2097152, "md5": A, "sha1": "1" * 40, "crc32": "aaaaaaaa"},
|
|
truth={"size": 480, "crc32": "bbbbbbbb"})
|
|
self.assertEqual(fe.hashes("sha1"), [])
|
|
self.assertEqual(fe.hashes("crc32"), ["bbbbbbbb"])
|
|
self.assertEqual(fe.size(), 480)
|
|
|
|
def test_agreeing_sides_still_merge(self):
|
|
fe = NativeFile("x.bin", "x.bin", "s",
|
|
platform={"md5": A, "sha1": "1" * 40}, truth={"md5": A})
|
|
self.assertEqual(fe.hashes("sha1"), ["1" * 40])
|
|
|
|
def test_a_name_with_another_size_is_another_file(self):
|
|
scraped = {"systems": {"dc": {"files": [
|
|
{"name": "boot.bin", "destination": "dc/boot.bin", "size": 2097152, "md5": A},
|
|
]}}}
|
|
truth = {"systems": {"dc": {"files": [
|
|
{"name": "boot.bin", "path": "fbneo/boot.bin", "size": 480, "crc32": "bbbbbbbb"},
|
|
]}}}
|
|
systems, _report = build_native_model(truth, scraped)
|
|
declared = next(f for f in systems["dc"].files if f.platform is not None)
|
|
self.assertIsNone(declared.truth)
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|