fix: hold the consumer guards on fixtures

The Dolphin-MMJR codehandler.bin and armsx2's game_controller_db.txt left
the collection, and the two guards that read them skipped on every run.
Both now build the trees they need, and the guards still reading the
repository fail instead of skipping when their data is gone.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 09:55:50 +02:00
1 parent 78bf456bb2
commit ed610c7bf3
2 files changed
+107 -36

No files matched your search

+50 -24
View File
@@ -87,34 +87,60 @@ class ReadersFollowTheDataTrees(unittest.TestCase):
"""Dolphin names codehandler.bin without a hash. The pack takes it from
data/dolphin-sys, and the site credited Dolphin and Triforce with the
Dolphin-MMJR copy, another revision, because the consumers resolved
without the data trees. Reads the repository."""
without the data trees."""
def test_dolphin_does_not_read_the_mmjr_copy(self):
def setUp(self):
import os
from common import load_database, load_emulator_profiles
self._previous = os.getcwd()
self._tree = tempfile.TemporaryDirectory()
root = Path(self._tree.name)
fork = root / "bios" / "Other" / "dolphin-mmjr" / "codehandler.bin"
fork.parent.mkdir(parents=True)
fork.write_bytes(b"dolphin-mmjr codehandler")
own = root / "data" / "dolphin-sys" / "codehandler.bin"
own.parent.mkdir(parents=True)
own.write_bytes(b"dolphin codehandler")
self.fork_sha1 = hashlib.sha1(fork.read_bytes()).hexdigest()
self.db = {
"files": {self.fork_sha1: {
"name": "codehandler.bin", "sha1": self.fork_sha1,
"path": "bios/Other/dolphin-mmjr/codehandler.bin",
"md5": hashlib.md5(fork.read_bytes()).hexdigest(),
"size": fork.stat().st_size,
}},
"indexes": {
"by_name": {"codehandler.bin": [self.fork_sha1]},
"by_md5": {}, "by_path_suffix": {},
},
}
self.registry = {"dolphin-sys": {"local_cache": str(own.parent)}}
self.profiles = {"dolphin": {"type": "standalone + libretro", "files": [
{"name": "codehandler.bin", "path": None, "mode": "libretro"},
]}}
os.chdir(root)
if not (REPO_ROOT / "database.json").is_file() or not (
REPO_ROOT / "data" / "dolphin-sys" / "codehandler.bin"
).is_file():
self.skipTest("database.json or data/dolphin-sys is absent")
previous = os.getcwd()
os.chdir(REPO_ROOT)
try:
db = load_database("database.json")
profiles = load_emulator_profiles("emulators")
consumers = FileConsumers(db)
consumers.add_emulators({"dolphin": profiles["dolphin"]})
finally:
os.chdir(previous)
mmjr = next(
(sha1 for sha1, entry in db["files"].items()
if entry["path"] == "bios/Other/dolphin-mmjr/codehandler.bin"),
None,
)
if mmjr is None:
self.skipTest("the Dolphin-MMJR copy is not collected")
self.assertNotIn("dolphin", consumers.emulators.get(mmjr, set()))
def tearDown(self):
import os
from common import forget_data_dir_index
os.chdir(self._previous)
forget_data_dir_index()
self._tree.cleanup()
def _readers(self, registry: dict) -> set[str]:
consumers = FileConsumers(self.db, data_dir_registry=registry)
consumers.add_emulators(self.profiles)
return consumers.emulators.get(self.fork_sha1, set())
def test_dolphin_does_not_read_the_mmjr_copy(self):
self.assertNotIn("dolphin", self._readers(self.registry))
def test_without_the_data_trees_the_name_step_takes_the_fork_copy(self):
"""The case above has to reach the data trees to pass: resolved
without them, the name alone hands Dolphin the fork's copy."""
self.assertIn("dolphin", self._readers({}))
def tearDownModule():
+57 -12
View File
@@ -9,7 +9,10 @@ armsx2's pack ships without a reader, and MAME's neogeo.zip without MAME.
from __future__ import annotations
import hashlib
import os
import sys
import tempfile
import unittest
from pathlib import Path
@@ -30,7 +33,7 @@ class ReadersNameTheOwner(unittest.TestCase):
def setUpClass(cls):
db_path = REPO_ROOT / "database.json"
if not db_path.exists():
raise unittest.SkipTest("database.json is not built")
raise AssertionError("database.json is committed and missing")
cls.db = load_database(str(db_path))
cls.profiles = load_emulator_profiles(str(REPO_ROOT / "emulators"))
cls.sha1_by_path = {r["path"]: s for s, r in cls.db["files"].items()}
@@ -40,15 +43,9 @@ class ReadersNameTheOwner(unittest.TestCase):
self.db, build_zip_contents_index(self.db)
)
consumers.add_emulators(self.profiles)
for path, owner in (
("bios/Other/armsx2/game_controller_db.txt", "armsx2"),
("bios/Arcade/MAME/neogeo.zip", "mame"),
):
with self.subTest(path=path):
sha1 = self.sha1_by_path.get(path)
if sha1 is None:
self.skipTest(f"{path} is not collected")
self.assertIn(owner, consumers.emulators.get(sha1, set()))
sha1 = self.sha1_by_path.get("bios/Arcade/MAME/neogeo.zip")
self.assertIsNotNone(sha1, "MAME's neogeo.zip is not collected")
self.assertIn("mame", consumers.emulators.get(sha1, set()))
def test_slot_claims_resolve_the_owners_tree(self):
claims = slots.profile_claims({"pcem": self.profiles["pcem"]}, self.db)
@@ -57,12 +54,60 @@ class ReadersNameTheOwner(unittest.TestCase):
}
# pcem declares ide_xt.bin and the collection holds it: an unclaimed
# file here is a claiming defect, not missing data.
if not any(e.get("path", "").endswith("/ide_xt.bin") for e in self.db["files"].values()):
self.skipTest("ide_xt.bin is not collected")
self.assertTrue(
any(e.get("path", "").endswith("/ide_xt.bin")
for e in self.db["files"].values()),
"ide_xt.bin is not collected",
)
local = held.get("ide_xt.bin")
self.assertIsNotNone(local, "pcem's ide_xt.bin is not claimed")
self.assertTrue(local.startswith("bios/Other/pcem/"), local)
class EachForkReadsItsOwnCopy(unittest.TestCase):
"""Two emulators ship a file under one name in their own trees. Without
the owner, the site credited aethersx2's game_controller_db.txt to
armsx2 and left the copy armsx2's pack ships without a reader."""
NAME = "game_controller_db.txt"
def setUp(self):
self._previous = os.getcwd()
self._tree = tempfile.TemporaryDirectory()
root = Path(self._tree.name)
files: dict[str, dict] = {}
self.sha1_of: dict[str, str] = {}
for owner in ("aethersx2", "armsx2"):
rel = f"bios/Other/{owner}/{self.NAME}"
payload = f"{owner} mappings".encode()
(root / rel).parent.mkdir(parents=True)
(root / rel).write_bytes(payload)
sha1 = hashlib.sha1(payload).hexdigest()
files[sha1] = {
"name": self.NAME, "sha1": sha1, "path": rel,
"md5": hashlib.md5(payload).hexdigest(), "size": len(payload),
}
self.sha1_of[owner] = sha1
self.db = {"files": files, "indexes": {
"by_name": {self.NAME: sorted(files)},
"by_md5": {}, "by_path_suffix": {},
}}
os.chdir(root)
def tearDown(self):
os.chdir(self._previous)
self._tree.cleanup()
def test_the_site_credits_each_owner_with_its_copy(self):
consumers = cross_reference.FileConsumers(self.db, data_dir_registry={})
consumers.add_emulators({
owner: {"type": "standalone", "files": [{"name": self.NAME}]}
for owner in self.sha1_of
})
for owner, sha1 in self.sha1_of.items():
with self.subTest(owner=owner):
self.assertEqual(consumers.emulators.get(sha1), {owner})
if __name__ == "__main__":
unittest.main()