mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
feat: read required from romload for MAME sets
A set whose every ROM is NO_DUMP or ROM_OPTIONAL only warns in handle_missing_file, so the machine runs without it. The parser now keeps undumped and optional ROMs for that decision, the merge and the release profiles write required false for such sets, and the text patcher rewrites the required line it used to leave. A curated false over a set with dumped ROMs is kept, except over no contents, which is what an undumped set leaves once a later release dumps it. pSxMAME builds mamedev/mame itself at 0.133 and left the current refresh, which would have moved it onto 0.289 refs. Release profiles keep their citations double-quoted on regeneration.
This commit is contained in:
1 parent
2870c72ccb
commit
d60fe814ed
5 files changed
+272
-19
No files matched your search
@@ -170,6 +170,85 @@ class TestMameMerge(unittest.TestCase):
|
||||
self.assertEqual(entry["system"], "snk-neogeo-mvs")
|
||||
self.assertFalse(entry["required"])
|
||||
|
||||
def test_merge_sets_required_false_for_a_set_the_machine_runs_without(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"].append({
|
||||
"name": "mac2bios.zip", "required": True, "category": "bios_zip",
|
||||
"note": "kept",
|
||||
})
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["mac2bios"] = {
|
||||
"source_file": "src/mame/seta/macs.cpp", "source_line": 776,
|
||||
"roms": [], "required": False,
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
|
||||
diff = compute_diff(profile_path, hashes_path, mode="mame")
|
||||
self.assertIn("mac2bios", diff["updated"])
|
||||
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "mac2bios.zip")
|
||||
self.assertFalse(entry["required"])
|
||||
self.assertEqual(entry["note"], "kept")
|
||||
|
||||
def test_written_profile_carries_the_settled_required(self) -> None:
|
||||
"""The text patcher rewrote contents and source_ref but left required."""
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"] = {"mac2bios": {
|
||||
"source_file": "src/mame/seta/macs.cpp", "source_line": 776,
|
||||
"roms": [], "required": False,
|
||||
}}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = str(p / "mame.yml")
|
||||
Path(profile_path).write_text(
|
||||
'emulator: MAME\ncore_version: "0.289"\nfiles:\n'
|
||||
" - name: mac2bios.zip\n required: true\n category: bios_zip\n"
|
||||
' source_ref: "upstream src/mame/seta/macs.cpp:776"\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
merge_mame_profile(profile_path, hashes_path, write=True)
|
||||
written = yaml.safe_load(Path(profile_path).read_text(encoding="utf-8"))
|
||||
entry = next(f for f in written["files"] if f["name"] == "mac2bios.zip")
|
||||
self.assertIs(entry["required"], False)
|
||||
|
||||
def test_merge_keeps_a_curated_false_over_a_fatal_set(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"][0]["required"] = False
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["neogeo"]["required"] = True
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "neogeo.zip")
|
||||
self.assertFalse(entry["required"])
|
||||
|
||||
def test_merge_restores_required_once_an_undumped_set_is_dumped(self) -> None:
|
||||
profile = _make_mame_profile()
|
||||
profile["files"].append({
|
||||
"name": "recel.zip", "required": False, "category": "bios_zip",
|
||||
"contents": [],
|
||||
})
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["recel"] = {
|
||||
"source_file": "src/mame/pinball/recel.cpp", "source_line": 546,
|
||||
"roms": [{"name": "a2361.b1", "size": 1024, "crc32": "eeb8f3f0"}],
|
||||
"required": True,
|
||||
}
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
p = Path(td)
|
||||
profile_path = _write_yaml(p / "mame.yml", profile)
|
||||
hashes_path = _write_json(p / "hashes.json", hashes)
|
||||
result = merge_mame_profile(profile_path, hashes_path)
|
||||
entry = next(f for f in result["files"] if f["name"] == "recel.zip")
|
||||
self.assertTrue(entry["required"])
|
||||
|
||||
def test_merge_adds_new_bios_set(self) -> None:
|
||||
hashes = _make_mame_hashes()
|
||||
hashes["bios_sets"]["pgm"] = {
|
||||
@@ -405,6 +484,30 @@ class AReleaseProfileDescribesItsOwnRelease(unittest.TestCase):
|
||||
self.assertNotIn("system", files["newset.zip"])
|
||||
self.assertEqual(files["neogeo.zip"]["source_ref"], "upstream src/mame/neogeo/neogeo.cpp:10")
|
||||
|
||||
def test_a_set_the_release_runs_without_is_not_required(self):
|
||||
"""recel is undumped at 0.258: the current profile's true does not apply."""
|
||||
from scripts.scraper.mame_hash_scraper import release_profile
|
||||
|
||||
bios_sets = {
|
||||
"recel": {"source_file": "src/mame/pinball/recel.cpp", "source_line": 505,
|
||||
"roms": [], "required": False},
|
||||
"neogeo": {"source_file": "src/mame/neogeo/neogeo.cpp", "source_line": 10,
|
||||
"roms": [{"name": "sp-s2.sp1", "size": 131072, "crc32": "9036d879"}],
|
||||
"required": True},
|
||||
}
|
||||
reference = {"files": [
|
||||
{"name": "recel.zip", "category": "bios_zip", "required": True,
|
||||
"contents": [{"name": "a2361.b1", "size": 1024, "crc32": "eeb8f3f0"}]},
|
||||
{"name": "neogeo.zip", "category": "bios_zip", "required": True},
|
||||
]}
|
||||
profile = release_profile(
|
||||
"mame0258", bios_sets, "a" * 40, "b" * 40, ["mame0258"], reference,
|
||||
["recalbox"],
|
||||
)
|
||||
files = {f["name"]: f for f in profile["files"]}
|
||||
self.assertFalse(files["recel.zip"]["required"])
|
||||
self.assertTrue(files["neogeo.zip"]["required"])
|
||||
|
||||
def test_a_release_profile_is_left_out_of_the_current_refresh(self):
|
||||
from scripts.scraper.mame_hash_scraper import _find_mame_profiles
|
||||
|
||||
@@ -412,6 +515,12 @@ class AReleaseProfileDescribesItsOwnRelease(unittest.TestCase):
|
||||
self.assertIn("mame.yml", names)
|
||||
self.assertFalse({"mame0258.yml", "mame0278.yml"} & names)
|
||||
|
||||
def test_a_pinned_build_of_the_mame_tree_is_left_out(self):
|
||||
"""pSxMAME builds mamedev/mame at 0.133: refreshed, it would carry 0.289 refs."""
|
||||
from scripts.scraper.mame_hash_scraper import _find_mame_profiles
|
||||
|
||||
self.assertNotIn("psxmame.yml", {path.name for path in _find_mame_profiles()})
|
||||
|
||||
|
||||
class TestFbneoMerge(unittest.TestCase):
|
||||
"""Tests for merge_fbneo_profile."""
|
||||
|
||||
@@ -10,6 +10,7 @@ from scripts.scraper.mame_parser import (
|
||||
find_bios_root_sets,
|
||||
parse_mame_source_tree,
|
||||
parse_rom_block,
|
||||
set_is_required,
|
||||
)
|
||||
|
||||
# Standard GAME macro with MACHINE_IS_BIOS_ROOT, multiple ROM entries, BIOS variants
|
||||
@@ -51,6 +52,35 @@ ROM_END
|
||||
GAME( 2000, testnd, 0, testnd, testnd, test_state, init_test, ROT0, "Test", "Test ND", MACHINE_IS_BIOS_ROOT )
|
||||
"""
|
||||
|
||||
# Every ROM undumped, as macs.cpp declares mac2bios: the machine runs without the set
|
||||
ALL_NODUMP_FIXTURE = """\
|
||||
#define MACS2_BIOS \\
|
||||
ROM_REGION( 0x400000, "bios", 0 ) \\
|
||||
ROM_LOAD16_BYTE( "macs2os_l.bin", 0x00000, 0x80000, NO_DUMP ) \\
|
||||
ROM_LOAD16_BYTE( "macs2os_h.bin", 0x00001, 0x80000, NO_DUMP )
|
||||
|
||||
ROM_START( mac2bios )
|
||||
MACS2_BIOS
|
||||
|
||||
ROM_REGION( 0x1000000, "maincpu", 0 )
|
||||
ROM_COPY( "bios", 0x000000, 0x000000, 0x400000 )
|
||||
ROM_END
|
||||
|
||||
GAME( 1995, mac2bios, 0, macs, macs_m, macs_state, init_macs2, ROT0, "I'Max", "Multi Amenity Cassette System 2 BIOS", MACHINE_IS_BIOS_ROOT | MACHINE_NOT_WORKING )
|
||||
"""
|
||||
|
||||
# Every ROM optional, through both spellings romentry.h offers, plus one undumped
|
||||
ALL_OPTIONAL_FIXTURE = """\
|
||||
ROM_START( testopt )
|
||||
ROM_REGION( 0x10000, "maincpu", 0 )
|
||||
ROM_LOAD_OPTIONAL( "opt1.rom", 0x00000, 0x4000, CRC(aabbccdd) SHA1(1122334455667788990011223344556677889900) )
|
||||
ROMX_LOAD( "opt2.rom", 0x04000, 0x4000, CRC(aabbccde) SHA1(1122334455667788990011223344556677889901), ROM_OPTIONAL )
|
||||
ROM_LOAD( "gone.rom", 0x08000, 0x4000, NO_DUMP )
|
||||
ROM_END
|
||||
|
||||
GAME( 2000, testopt, 0, testopt, testopt, test_state, init_test, ROT0, "Test", "Test Optional", MACHINE_IS_BIOS_ROOT )
|
||||
"""
|
||||
|
||||
# ROM_LOAD with BAD_DUMP
|
||||
BADDUMP_FIXTURE = """\
|
||||
ROM_START( testbd )
|
||||
@@ -284,6 +314,47 @@ ROM_END
|
||||
self.assertEqual(roms[0]["sha1"], "aabbccddeeff00112233aabbccddeeff00112233")
|
||||
|
||||
|
||||
class TestSetIsRequired(unittest.TestCase):
|
||||
"""A set is required only if romload.cpp errors when it is missing."""
|
||||
|
||||
def test_all_no_dump_set_is_not_required(self) -> None:
|
||||
entries = parse_rom_block(ALL_NODUMP_FIXTURE, "mac2bios", keep_no_dump=True)
|
||||
self.assertEqual([e["name"] for e in entries], ["macs2os_l.bin", "macs2os_h.bin"])
|
||||
self.assertTrue(all(e["no_dump"] for e in entries))
|
||||
self.assertIs(set_is_required(entries), False)
|
||||
|
||||
def test_optional_and_no_dump_set_is_not_required(self) -> None:
|
||||
entries = parse_rom_block(ALL_OPTIONAL_FIXTURE, "testopt", keep_no_dump=True)
|
||||
self.assertEqual(len(entries), 3)
|
||||
self.assertTrue(entries[0]["optional"] and entries[1]["optional"])
|
||||
self.assertIs(set_is_required(entries), False)
|
||||
|
||||
def test_one_dumped_rom_makes_the_set_required(self) -> None:
|
||||
entries = parse_rom_block(NODUMP_FIXTURE, "testnd", keep_no_dump=True)
|
||||
self.assertIs(set_is_required(entries), True)
|
||||
|
||||
def test_bad_dump_is_still_fatal(self) -> None:
|
||||
entries = parse_rom_block(BADDUMP_FIXTURE, "testbd", keep_no_dump=True)
|
||||
self.assertIs(set_is_required(entries), True)
|
||||
|
||||
def test_no_rom_read_decides_nothing(self) -> None:
|
||||
self.assertIsNone(set_is_required([]))
|
||||
|
||||
def test_no_dump_stays_out_of_the_default_parse(self) -> None:
|
||||
self.assertEqual(parse_rom_block(ALL_NODUMP_FIXTURE, "mac2bios"), [])
|
||||
|
||||
def test_tree_records_required_per_set(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
mame_dir = os.path.join(tmpdir, "src", "mame", "seta")
|
||||
os.makedirs(mame_dir)
|
||||
with open(os.path.join(mame_dir, "macs.cpp"), "w") as f:
|
||||
f.write(ALL_NODUMP_FIXTURE + NEOGEO_FIXTURE)
|
||||
results = parse_mame_source_tree(tmpdir)
|
||||
self.assertIs(results["mac2bios"]["required"], False)
|
||||
self.assertEqual(results["mac2bios"]["roms"], [])
|
||||
self.assertIs(results["neogeo"]["required"], True)
|
||||
|
||||
|
||||
class TestParseMameSourceTree(unittest.TestCase):
|
||||
"""Tests for parse_mame_source_tree."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user