fix: a refused regional file wins no slot

emulator_region_drops counted as held any file that resolved. A regional
dump whose md5 the core's own check refuses won its region, the fallback
was withdrawn, and the emulator pack then refused the winner: no BIOS for
the system, and verify --emulator, reading the same drops, did not see
it. Held now means what the builder ships, as _ships decides on the
platform side.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 05:19:51 +02:00
1 parent 38af19091d
commit 1c2360926b
2 files changed
+85 -4

No files matched your search

+27 -4
View File
@@ -1296,11 +1296,12 @@ def emulator_region_drops(
"""
import region as region_mod
from packpaths import _resolve_destination
from validation import filter_files_by_mode
from validation import _build_validation_index, filter_files_by_mode
region_index = region_mod.build_region_index(dict(selected))
region_groups: dict[str, list[tuple[str, str]]] = {}
held: set[str] | None = set() if db is not None else None
validation_index = _build_validation_index(dict(selected)) if db is not None else {}
for emu_name, profile in sorted(selected):
# Decided over what the pack keeps, as on the platform side: an
# optional winner removed afterwards left its slot empty.
@@ -1312,13 +1313,35 @@ def emulator_region_drops(
region_groups.setdefault(group_id, []).append(
(dest, fe.get("name", ""))
)
if held is not None and resolve_local_file(
dict(fe, source_profile=emu_name), db, dest_hint=dest
)[0]:
if held is not None and _emulator_ships(
fe, emu_name, profile, db, dest, validation_index
):
held.add(dest)
return region_mod.resolve_region_drops(region_groups, region_index, regions, held)
def _emulator_ships(
file_entry: dict, emu_name: str, profile: dict, db: dict, dest: str,
validation_index: dict,
) -> bool:
"""Whether the emulator pack ships this entry: held, and not refused by
the core's own check, the test _ships applies on the platform side.
"""
from validation import validated_choice, with_archive_members
local, _status = resolve_local_file(
{**with_archive_members(file_entry, profile.get("files", [])),
"source_profile": emu_name},
db, dest_hint=dest,
)
if not local:
return False
_chosen, disagreement = validated_choice(
file_entry, local, db, validation_index, "bios", None, emulators={emu_name},
)
return disagreement is None
def _emulator_region_group(
emu_name: str, profile: dict, file_entry: dict, dest: str
) -> str:
+58
View File
@@ -1113,5 +1113,63 @@ class NoMarketStopsAtAustralia(unittest.TestCase):
self.assertEqual(tagged, [])
class ARefusedRegionalFileHoldsNoSlot(unittest.TestCase):
"""rg_us.bin is held but its md5 contradicts the one the core checks, so
the emulator pack refuses it. Counted held, it won the region and the
Japanese BIOS was withdrawn: --emulator --region us shipped no BIOS for
the system, and verify, reading the same drops, did not see it."""
def test_the_fallback_stays_in_pack_and_report(self):
import hashlib
import shutil
import tempfile
import zipfile
import yaml
from generate_pack import generate_emulator_pack
from verify import verify_emulator
common._emulator_profiles_cache.clear()
repo = Path(__file__).resolve().parents[1]
(repo / "tmp").mkdir(exist_ok=True)
root = Path(tempfile.mkdtemp(dir=repo / "tmp"))
self.addCleanup(shutil.rmtree, root, True)
previous = os.getcwd()
os.chdir(root)
self.addCleanup(os.chdir, previous)
files, by_name = {}, {}
for name, data in (("rg_us.bin", b"NOT THE US DUMP"), ("rg_jp.bin", b"JP DUMP")):
path = Path("bios") / name
path.parent.mkdir(exist_ok=True)
path.write_bytes(data)
sha1 = hashlib.sha1(data).hexdigest()
files[sha1] = {"path": str(path), "name": name, "size": len(data),
"md5": hashlib.md5(data).hexdigest()}
by_name[name] = [sha1]
db = {"files": files, "indexes": {"by_name": by_name, "by_md5": {},
"by_crc32": {}, "by_path_suffix": {}}}
Path("emulators").mkdir()
Path("emulators/rgemu.yml").write_text(yaml.safe_dump({
"emulator": "RgEmu", "type": "libretro", "systems": ["sys"],
"files": [
{"name": "rg_us.bin", "region": ["north-america"], "required": True,
"md5": hashlib.md5(b"THE US DUMP").hexdigest(), "validation": ["md5"]},
{"name": "rg_jp.bin", "region": ["japan"], "required": True},
],
}))
with contextlib.redirect_stdout(io.StringIO()):
zip_path = generate_emulator_pack(
["rgemu"], "emulators", db, "bios", "out", regions=["north-america"],
offline=True, platforms_dir="platforms",
)
with zipfile.ZipFile(zip_path) as zf:
self.assertIn("rg_jp.bin", zf.namelist())
report = verify_emulator(
["rgemu"], "emulators", db, regions=["north-america"], platforms_dir="platforms",
)
self.assertIn("rg_jp.bin", report["pack_destinations"])
if __name__ == "__main__":
unittest.main()