mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-08 11:03:46 -06:00
fix: refuse only the axis a list lacks
The MinUI family's lists record cores and regions and no system: every narrowing was refused with a remedy that fetched the same list. Each option is now refused by the axis missing, with what works, and a pack names its platform's list only when that list records the axis. Line mode names what c chooses and skips a question with one answer, and Options leaves out parallel downloads when nothing is downloaded.
This commit is contained in:
1 parent
5704dd6793
commit
0fa4552dae
10 files changed
+314
-63
No files matched your search
+25
-13
@@ -370,18 +370,28 @@ class RefusedBeforeAnyInstall(unittest.TestCase):
|
||||
(tmp / "retroarch.cfg").write_text("")
|
||||
(tmp / "cores").mkdir()
|
||||
(tmp / "cores" / "mgba_libretro.so").write_bytes(b"")
|
||||
with mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch.object(install, "detect_frontends", return_value=[]), \
|
||||
mock.patch.object(install, "detect_platforms", return_value=detected), \
|
||||
mock.patch.object(install, "fetch_manifest") as fetch, \
|
||||
mock.patch.object(sys, "argv", ["install.py", "--installed-cores", "--no-input"]), \
|
||||
contextlib.redirect_stdout(io.StringIO()), \
|
||||
contextlib.redirect_stderr(io.StringIO()) as err:
|
||||
with self.assertRaises(SystemExit) as stop:
|
||||
install.main()
|
||||
self.assertEqual(stop.exception.code, 1)
|
||||
self.assertIn("batocera ships its cores", err.getvalue())
|
||||
fetch.assert_not_called()
|
||||
# Two setups found stop a run without questions before either is
|
||||
# read (code_audit_18 P2-3): the refusal is checked with Batocera
|
||||
# named, and with both found nothing is fetched either.
|
||||
for argv, said in (
|
||||
(["--platform", "batocera", "--dest", str(tmp / "bios")],
|
||||
"batocera ships its cores"),
|
||||
([], "2 setups were found here")):
|
||||
with self.subTest(argv=argv), \
|
||||
mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch.object(install, "detect_frontends", return_value=[]), \
|
||||
mock.patch.object(install, "detect_platforms", return_value=detected), \
|
||||
mock.patch.object(install, "_mounted_cards", return_value=[]), \
|
||||
mock.patch.object(install, "fetch_manifest") as fetch, \
|
||||
mock.patch.object(sys, "argv", ["install.py", "--installed-cores",
|
||||
"--no-input", *argv]), \
|
||||
contextlib.redirect_stdout(io.StringIO()), \
|
||||
contextlib.redirect_stderr(io.StringIO()) as err:
|
||||
with self.assertRaises(SystemExit) as stop:
|
||||
install.main()
|
||||
self.assertEqual(stop.exception.code, 1)
|
||||
self.assertIn(said, err.getvalue())
|
||||
fetch.assert_not_called()
|
||||
|
||||
|
||||
class AnUnknownTargetStopsTheRunFirst(unittest.TestCase):
|
||||
@@ -393,12 +403,14 @@ class AnUnknownTargetStopsTheRunFirst(unittest.TestCase):
|
||||
self.addCleanup(shutil.rmtree, tmp, True)
|
||||
detected = [("emudeck", tmp / "bios"), ("retroarch", tmp / "system")]
|
||||
lists = {"emudeck": {"steamos": {"cores": []}}, "retroarch": {"x86_64": {"cores": []}}}
|
||||
# Listed for both platforms: a listing reads every list found.
|
||||
with mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch.object(install, "detect_frontends", return_value=[]), \
|
||||
mock.patch.object(install, "detect_platforms", return_value=detected), \
|
||||
mock.patch.object(install, "fetch_targets", side_effect=lists.get), \
|
||||
mock.patch.object(install, "fetch_manifest") as fetch, \
|
||||
mock.patch.object(sys, "argv", ["install.py", "--target", "steamos", "--no-input"]), \
|
||||
mock.patch.object(sys, "argv", ["install.py", "--target", "steamos",
|
||||
"--list-systems", "--no-input"]), \
|
||||
contextlib.redirect_stdout(io.StringIO()), \
|
||||
contextlib.redirect_stderr(io.StringIO()) as err:
|
||||
with self.assertRaises(SystemExit) as stop:
|
||||
|
||||
@@ -612,7 +612,8 @@ class TheOneLinerNarrows(unittest.TestCase):
|
||||
with FakeRepository(selection=False) as repo:
|
||||
proc = repo.run("--region", "us")
|
||||
self.assertEqual(proc.returncode, 1)
|
||||
self.assertIn("records no systems or regions", proc.stderr)
|
||||
self.assertIn("records no regions, so --region cannot narrow it", proc.stderr)
|
||||
self.assertIn("older release", proc.stderr)
|
||||
self.assertEqual(repo.installed(), [])
|
||||
|
||||
def test_a_pinned_ref_is_named_as_the_way_out(self):
|
||||
@@ -675,18 +676,19 @@ class TheOneLinerNarrows(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(shutil.which("script"), "script(1) provides the terminal")
|
||||
def test_the_custom_mode_at_a_terminal(self):
|
||||
"""Typed answers: customise, PlayStation only, no core, US first."""
|
||||
"""Typed answers: customise, PlayStation only, US first. Its one
|
||||
core is not asked about (tui_audit_11 P3-10)."""
|
||||
with FakeRepository() as repo:
|
||||
command = " ".join(shlex.quote(part) for part in repo.command())
|
||||
proc = subprocess.run(
|
||||
["script", "-qec", command, "/dev/null"],
|
||||
input="c\n2\n\n2\n\n", env=repo.env(), capture_output=True,
|
||||
input="c\n2\n2\n\n", env=repo.env(), capture_output=True,
|
||||
text=True, timeout=60, check=False,
|
||||
)
|
||||
out = proc.stdout
|
||||
self.assertEqual(proc.returncode, 0, out + proc.stderr)
|
||||
self.assertIn("choose systems, cores and regions", out)
|
||||
self.assertIn("pcsx_rearmed", out)
|
||||
self.assertNotIn("Cores:", out)
|
||||
self.assertIn("--system sony-playstation --region north-america", out)
|
||||
self.assertEqual(repo.installed(), ["pcsx/extra.bin", "scph5501.bin"])
|
||||
|
||||
|
||||
+134
-1
@@ -7432,7 +7432,7 @@ class AuditSeventeenAndTen(unittest.TestCase):
|
||||
with contextlib.redirect_stderr(err), self.assertRaises(SystemExit):
|
||||
install._requested_narrowing(_args(system=["nintendo-gba"]), "retroarch",
|
||||
install.LOCAL.pack.manifest("retroarch")["files"], [])
|
||||
self.assertIn("add --manifest FILE, a copy of install/retroarch.json", err.getvalue())
|
||||
self.assertIn("Add --manifest FILE, a copy of install/retroarch.json", err.getvalue())
|
||||
self.assertNotIn("older release", err.getvalue())
|
||||
|
||||
def test_a_pack_cannot_write_escapes_through_its_system_names(self):
|
||||
@@ -8660,6 +8660,139 @@ class AuditEighteenAndEleven(unittest.TestCase):
|
||||
["Onion SD card (ONION, no BIOS folder)",
|
||||
"Onion SD card (OLDONION, 6 BIOS files)"])
|
||||
|
||||
# tui_audit_11 P2-1: a list or a pack that records some axes only.
|
||||
|
||||
def minui(self, plat: str = "minui", systems: bool = False, cores: bool = True,
|
||||
regions: bool = True) -> tuple[Path, Path, dict]:
|
||||
"""A list of plat's shape (the MinUI family records cores and regions,
|
||||
no system), the pack built from it and the files' payloads."""
|
||||
from test_install_offline import GBA, JP, US # noqa: PLC0415
|
||||
|
||||
payloads = {"Bios/MGBA/gba_bios.bin": (GBA, "nintendo-gba", "mgba", None),
|
||||
"Bios/PS/scph5501.bin": (US, "sony-playstation", "pcsx_rearmed",
|
||||
"north-america"),
|
||||
"Bios/PS/scph5500.bin": (JP, "sony-playstation", "pcsx_rearmed", "japan")}
|
||||
files = []
|
||||
for dest, (data, system, core, region) in payloads.items():
|
||||
entry = {"dest": dest, "sha1": hashlib.sha1(data).hexdigest(), "size": len(data),
|
||||
"repo_path": f"bios/{dest}", "cores": [core] if cores else None}
|
||||
if systems:
|
||||
entry["systems"] = [system]
|
||||
if regions and region:
|
||||
entry.update(regions=[region], region_groups=["ps"])
|
||||
files.append(entry)
|
||||
listing = self.root / f"{plat}.json"
|
||||
install_list = {"manifest_version": 2, "platform": plat, "files": files}
|
||||
listing.write_text(json.dumps(install_list))
|
||||
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
self.addCleanup(sys.path.remove, str(REPO_ROOT / "scripts"))
|
||||
import generate_pack # noqa: PLC0415
|
||||
|
||||
pack_list = {"files": [{"path": dest, "sha1": entry["sha1"], "size": entry["size"]}
|
||||
for dest, entry in zip(payloads, files)]}
|
||||
generate_pack.annotate_pack_systems(pack_list, generate_pack.pack_systems(install_list))
|
||||
name = {"minui": "MinUI", "misterfpga": "MiSTer_FPGA"}[plat]
|
||||
pack = self.root / f"{name}_v1_BIOS_Pack.zip"
|
||||
with zipfile.ZipFile(pack, "w") as archive:
|
||||
for dest, (data, *_rest) in payloads.items():
|
||||
archive.writestr(dest, data)
|
||||
archive.writestr("manifest.json", json.dumps(pack_list))
|
||||
return listing, pack, pack_list
|
||||
|
||||
def narrowed(self, plat: str, **given) -> tuple[int, str, list]:
|
||||
"""(exit code, what was said, the files kept) of a --dry-run narrowed
|
||||
as given."""
|
||||
dest = self.root / "dest"
|
||||
if not dest.exists():
|
||||
make_card(dest, "MinUI")
|
||||
stream = io.StringIO()
|
||||
code = 0
|
||||
with mock.patch.object(install.EVENTS, "stream", stream), \
|
||||
mock.patch.object(install, "detect_os", return_value="linux"), \
|
||||
mock.patch.dict(os.environ, {install.OFFLINE_VARIABLE: "1"}), \
|
||||
contextlib.redirect_stdout(io.StringIO()) as out, \
|
||||
contextlib.redirect_stderr(io.StringIO()) as err:
|
||||
try:
|
||||
install._install(_args(platform=plat, dest=dest, dry_run=True, events=True,
|
||||
no_input=True, declared_only=False, **given),
|
||||
io.StringIO())
|
||||
except SystemExit as stop:
|
||||
code = stop.code
|
||||
finally:
|
||||
install.LOCAL.reset()
|
||||
kept = [json.loads(line)["dest"] for line in stream.getvalue().splitlines()
|
||||
if '"event": "file"' in line]
|
||||
return code, out.getvalue() + err.getvalue(), kept
|
||||
|
||||
def test_a_list_without_systems_narrows_by_what_it_records(self):
|
||||
"""tui_audit_11 P2-1: install/minui.json records cores and regions,
|
||||
no system, and all three options were refused with a remedy that
|
||||
fetched the same list."""
|
||||
listing, _pack, _listed = self.minui()
|
||||
code, text, kept = self.narrowed("minui", manifest=listing, core=["mgba"])
|
||||
self.assertEqual(code, 0, text)
|
||||
self.assertEqual(kept, ["Bios/MGBA/gba_bios.bin"])
|
||||
code, text, kept = self.narrowed("minui", manifest=listing, region=["us"])
|
||||
self.assertEqual(code, 0, text)
|
||||
self.assertNotIn("Bios/PS/scph5500.bin", kept)
|
||||
code, text, _kept = self.narrowed("minui", manifest=listing,
|
||||
system=["nintendo-gba"])
|
||||
self.assertEqual(code, 1)
|
||||
self.assertIn("records no systems, so --system cannot narrow it", text)
|
||||
self.assertIn("Run it without --system, or narrow with --core and --region", text)
|
||||
self.assertNotIn("one-line installer", text)
|
||||
# The remedy followed: what it names works.
|
||||
code, text, _kept = self.narrowed("minui", manifest=listing, core=["mgba"],
|
||||
region=["us"])
|
||||
self.assertEqual(code, 0, text)
|
||||
|
||||
def test_a_pack_names_its_list_only_when_that_list_records_it(self):
|
||||
"""tui_audit_11 P2-1: a MinUI pack sent --core to install/minui.json,
|
||||
refused the same way, and a MiSTer pack to install/misterfpga.json,
|
||||
which records no core. The pack now records what its list narrows
|
||||
by, and each remedy changes the outcome."""
|
||||
listing, pack, listed = self.minui()
|
||||
self.assertEqual(listed["list_records"], ["cores", "regions"])
|
||||
code, text, _kept = self.narrowed("minui", from_pack=[pack], core=["mgba"])
|
||||
self.assertEqual(code, 1)
|
||||
self.assertIn("Add --manifest FILE, a copy of install/minui.json, which records them",
|
||||
text)
|
||||
code, text, kept = self.narrowed("minui", from_pack=[pack], manifest=listing,
|
||||
core=["mgba"])
|
||||
self.assertEqual((code, kept), (0, ["Bios/MGBA/gba_bios.bin"]), text)
|
||||
mister_list, mister, listed = self.minui("misterfpga", systems=True, cores=False,
|
||||
regions=False)
|
||||
self.assertEqual(listed["list_records"], ["regions", "systems"])
|
||||
code, text, _kept = self.narrowed("misterfpga", from_pack=[mister], core=["x"])
|
||||
self.assertEqual(code, 1)
|
||||
self.assertIn("MiSTer FPGA's own file list records no cores either. Run it without "
|
||||
"--core, or narrow with --system.", text)
|
||||
self.assertNotIn("--manifest", text)
|
||||
code, text, kept = self.narrowed("misterfpga", from_pack=[mister],
|
||||
system=["nintendo-gba"])
|
||||
self.assertEqual((code, kept), (0, ["Bios/MGBA/gba_bios.bin"]), text)
|
||||
self.assertTrue(mister_list.exists())
|
||||
|
||||
def test_line_mode_offers_what_can_be_chosen(self):
|
||||
"""tui_audit_11 P3-10: "c) choose systems, cores and regions" with a
|
||||
pack that records systems only, and "Cores: 1) azahar" asked with
|
||||
one answer."""
|
||||
_listing, _pack, listed = self.minui("misterfpga", systems=True, cores=False,
|
||||
regions=False)
|
||||
files = [{"dest": f["path"], "sha1": f["sha1"], "size": f["size"],
|
||||
"repo_path": "x", "systems": f["systems"]} for f in listed["files"]]
|
||||
self.assertEqual(install.narrowing_words(files, []), "systems")
|
||||
listing, _pack, _listed = self.minui()
|
||||
minui = json.loads(listing.read_text())["files"]
|
||||
self.assertEqual(install.narrowing_words(minui, []), "cores and regions")
|
||||
one_core = [{**entry, "systems": ["nintendo-3ds"], "cores": ["azahar"]}
|
||||
for entry in minui[:1]]
|
||||
with mock.patch.object(install, "_ask", side_effect=["", ""]) as asked, \
|
||||
contextlib.redirect_stdout(io.StringIO()) as out:
|
||||
install._choose_narrowing(one_core, [], {}, None)
|
||||
self.assertNotIn("Cores:", out.getvalue())
|
||||
self.assertEqual(asked.call_count, 0)
|
||||
|
||||
def test_the_card_marker_table_is_written_from_the_rules(self):
|
||||
"""code_audit_18 P3-6, tui_audit_11 P2-2: the table left out the
|
||||
SHARE drives. It is generated: every card rule and SHARE drive file
|
||||
|
||||
Reference in new issue
Block a user