mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-24 04:39:06 -05:00
entry_source took a name or path hit before reading the hashes the entry declares, so the gap report and the site counted as held a file whose only homonym has other bytes: zquestclassic's ending.mid and gameover.mid matched Hydra Castle Labyrinth's. A name or path hit now counts only when its record carries one of the declared hashes, and the declared content anywhere in bios/ comes before a data/ copy. Measured over every profile entry: 254 change, 248 bundled ones (report and site only), three unsourceable SC-55 revisions now read missing, three data hits read bios by hash.
92 lines
4.0 KiB
Python
92 lines
4.0 KiB
Python
"""The gap report reads the collection the way the resolver does.
|
|
|
|
Three ways it called held files missing, or a missing file held: system IDs
|
|
compared verbatim (sega-megacd against sega-mega-cd), no sha256 in the hash
|
|
fallback (rust_dos names its SC-55 ROMs by sha256 alone), and directory names
|
|
indexed as files (BasiliskII's required ROM read as held because cpcemu keeps
|
|
a directory called ROM).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
from cross_reference import ( # noqa: E402
|
|
_build_supplemental_index,
|
|
cross_reference,
|
|
entry_source,
|
|
)
|
|
|
|
|
|
def _index(**over) -> dict:
|
|
base = {
|
|
"by_name": {}, "by_name_lower": {}, "by_path_suffix": {}, "by_md5": {},
|
|
"by_sha256": {}, "by_crc32": {}, "db_files": {}, "data_names": set(),
|
|
}
|
|
base.update(over)
|
|
return base
|
|
|
|
|
|
class GapReportSources(unittest.TestCase):
|
|
def test_a_sha256_alone_finds_the_file(self):
|
|
entry = {"name": "wave1.bin", "sha256": "AB" * 32}
|
|
self.assertEqual(entry_source(entry, _index(by_sha256={"ab" * 32: "s"})), "bios")
|
|
|
|
def test_a_name_never_wins_over_a_declared_hash(self):
|
|
"""zquestclassic pins ending.mid by sha1, the collection holds only
|
|
Hydra Castle Labyrinth's ending.mid: the report called it held."""
|
|
other = "9" * 40
|
|
index = _index(
|
|
by_name={"ending.mid": [other]}, by_name_lower={"ending.mid": "ending.mid"},
|
|
by_path_suffix={"data/midi/ending.mid": [other]},
|
|
db_files={other: {"path": "bios/hcl/ending.mid", "md5": "1" * 32, "size": 9}},
|
|
)
|
|
pinned = {"name": "ending.mid", "sha1": "5" * 40}
|
|
self.assertIsNone(entry_source(pinned, index))
|
|
self.assertIsNone(entry_source({**pinned, "path": "data/midi/ending.mid"}, index))
|
|
self.assertEqual(entry_source({"name": "ending.mid"}, index), "bios")
|
|
self.assertEqual(entry_source({"name": "ending.mid", "sha1": other}, index), "bios")
|
|
self.assertEqual(entry_source({"name": "ending.mid", "md5": "1" * 32}, index), "bios")
|
|
|
|
def test_a_directory_does_not_stand_for_a_file(self):
|
|
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
|
|
(Path(tmp) / "bios" / "cpcemu" / "ROM").mkdir(parents=True)
|
|
names = _build_supplemental_index(str(Path(tmp) / "data"), str(Path(tmp) / "bios"))
|
|
self.assertIsNone(entry_source({"name": "ROM"}, _index(data_names=names)))
|
|
directory = {"name": "ROM", "type": "directory"}
|
|
self.assertEqual(entry_source(directory, _index(data_names=names)), "data")
|
|
|
|
def test_a_system_spelled_otherwise_is_still_declared(self):
|
|
profiles = {"gpgx": {"emulator": "gpgx", "systems": ["sega-megacd"],
|
|
"files": [{"name": "bios_CD_U.bin"}]}}
|
|
declared = {"megacd": {"bios_CD_U.bin"}} # sega-mega-cd, normalized
|
|
db = {"files": {}, "indexes": {}}
|
|
report = cross_reference(profiles, declared, db)
|
|
self.assertEqual(report["gpgx"]["gaps"], 0)
|
|
|
|
def test_any_accepted_version_fills_the_slot(self):
|
|
"""raze accepts ten DUKE3D.GRP, but the report judged the first alone and
|
|
listed the file to acquire while the collection holds the tenth."""
|
|
profiles = {"raze": {"emulator": "Raze", "systems": ["dos"], "files": [
|
|
{"name": "DUKE3D.GRP", "path": "DUKE3D.GRP", "size": 1, "sha1": "a" * 40},
|
|
{"name": "DUKE3D.GRP", "path": "DUKE3D.GRP", "size": 2, "sha1": "b" * 40},
|
|
]}}
|
|
db = {"files": {"b" * 40: {"path": "bios/DUKE3D.GRP", "name": "DUKE3D.GRP"}},
|
|
"indexes": {"by_name": {}, "by_md5": {}, "by_crc32": {}, "by_sha256": {},
|
|
"by_path_suffix": {}}}
|
|
report = cross_reference(profiles, {}, db)
|
|
self.assertEqual(report["raze"]["gaps"], 1)
|
|
self.assertEqual(
|
|
[g["source"] for g in report["raze"]["gap_details"]], ["bios"]
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|