mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 12:19:13 -05:00
fix: write truth systems in a stable order
Systems a core covers without a file were added while walking a set, so the hash seed placed them and two runs wrote dist/truth/<platform>.yml in two orders. The normalized system map was built from a set too.
This commit is contained in:
1 parent
bbd778b390
commit
bc2233e725
2 files changed
+62
-5
No files matched your search
+8
-5
@@ -550,10 +550,12 @@ def generate_platform_truth(
|
||||
if fname:
|
||||
declared_by_name.setdefault(fname, []).append((psid, fe))
|
||||
|
||||
# Normalized ID -> platform system ID
|
||||
# Normalized ID -> platform system ID. Walked in the platform's order,
|
||||
# not the set's: two IDs normalizing alike went to whichever the hash
|
||||
# seed put last.
|
||||
norm_to_platform: dict[str, str] = {}
|
||||
for psid in platform_sys_ids:
|
||||
norm_to_platform[_norm_system_id(psid)] = psid
|
||||
for psid in config.get("systems", {}):
|
||||
norm_to_platform.setdefault(_norm_system_id(psid), psid)
|
||||
|
||||
def _map_sys_id(profile_sid: str) -> str:
|
||||
"""Map a profile system ID to the platform's system ID."""
|
||||
@@ -669,8 +671,9 @@ def generate_platform_truth(
|
||||
|
||||
# Ensure all systems of resolved cores have entries (even with 0 files).
|
||||
# This documents that the system is covered: the core was analyzed and
|
||||
# needs no external files for this system.
|
||||
for emu_name in cores_profiled:
|
||||
# needs no external files for this system. Sorted: the set's order is
|
||||
# the hash seed's, and it decided where each empty system was written.
|
||||
for emu_name in sorted(cores_profiled):
|
||||
profile = profiles[emu_name]
|
||||
for prof_sid in profile.get("systems", []):
|
||||
sys_id = _map_sys_id(prof_sid)
|
||||
|
||||
@@ -8,6 +8,10 @@ out on RetroBat, EmuDeck and RetroDECK.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
@@ -400,5 +404,55 @@ class TruthKnowsWhatTheEmulatorInstalls(unittest.TestCase):
|
||||
self.assertEqual(names, [])
|
||||
|
||||
|
||||
class TheModelIsAFunctionOfItsInputs(unittest.TestCase):
|
||||
"""Two runs on the same inputs wrote dist/truth/<platform>.yml with its
|
||||
systems in two orders. The systems a core covers without a file were
|
||||
added by walking a set, so the hash seed decided where each was written.
|
||||
"""
|
||||
|
||||
NAMES = [f"core{i:02d}" for i in range(16)]
|
||||
SCRIPT = (
|
||||
"import json, sys\n"
|
||||
"sys.path.insert(0, sys.argv[1])\n"
|
||||
"from truth import generate_platform_truth\n"
|
||||
"names = [f'core{i:02d}' for i in range(16)]\n"
|
||||
"profiles = {n: {'emulator': n, 'type': 'libretro',\n"
|
||||
" 'systems': [f'maker-system-{n}'], 'files': []} for n in names}\n"
|
||||
"config = {'cores': names,\n"
|
||||
" 'systems': {f'maker-system-{n}': {'files': []} for n in names}}\n"
|
||||
"print(json.dumps(generate_platform_truth('p', config, {}, profiles)))\n"
|
||||
)
|
||||
|
||||
def _model(self, seed: str) -> str:
|
||||
proc = subprocess.run(
|
||||
[sys.executable, "-c", self.SCRIPT, str(REPO_ROOT / "scripts")],
|
||||
env={**os.environ, "PYTHONHASHSEED": seed},
|
||||
capture_output=True, text=True, timeout=120, check=True,
|
||||
)
|
||||
return proc.stdout
|
||||
|
||||
def test_the_hash_seed_changes_nothing(self):
|
||||
first = self._model("0")
|
||||
for seed in ("1", "2", "3", "4"):
|
||||
with self.subTest(seed=seed):
|
||||
self.assertEqual(self._model(seed), first)
|
||||
|
||||
def test_the_profile_order_changes_nothing(self):
|
||||
profiles = {
|
||||
n: {"emulator": n, "type": "libretro", "systems": [f"maker-system-{n}"],
|
||||
"files": [{"name": f"{n}.bin", "system": f"maker-system-{n}",
|
||||
"md5": f"{i:032x}"}]}
|
||||
for i, n in enumerate(self.NAMES)
|
||||
}
|
||||
config = {"cores": self.NAMES,
|
||||
"systems": {f"maker-system-{n}": {"files": []} for n in self.NAMES}}
|
||||
expected = json.dumps(generate_platform_truth("p", config, {}, profiles))
|
||||
shuffled = list(profiles.items())
|
||||
random.Random(7).shuffle(shuffled)
|
||||
self.assertEqual(
|
||||
json.dumps(generate_platform_truth("p", config, {}, dict(shuffled))), expected
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user