mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
feat: add launchbox detection to installer
This commit is contained in:
1 parent
393d32ed84
commit
69d53c97c9
14 files changed
+1509
-1116
No files matched your search
@@ -1,12 +1,18 @@
|
||||
"""Tests for install.py platform detection and config parsing."""
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import http.server
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
import unittest.mock
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
@@ -207,6 +213,509 @@ class TestEmbeddedDetection(unittest.TestCase):
|
||||
self.assertEqual(self._detect_with(set()), [])
|
||||
|
||||
|
||||
class TestLaunchboxDetection(unittest.TestCase):
|
||||
"""LaunchBox references its emulators in Data/Emulators.xml."""
|
||||
|
||||
def _make_launchbox(self, app_path: str, title: str = "Retroarch"):
|
||||
root = Path(tempfile.mkdtemp())
|
||||
data = root / "LaunchBox" / "Data"
|
||||
data.mkdir(parents=True)
|
||||
xml = data / "Emulators.xml"
|
||||
xml.write_text(
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n"
|
||||
"<LaunchBox>\n"
|
||||
" <Emulator>\n"
|
||||
" <ID>x</ID>\n"
|
||||
f" <Title>{title}</Title>\n"
|
||||
f" <ApplicationPath>{app_path}</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
"</LaunchBox>\n"
|
||||
)
|
||||
return root, xml
|
||||
|
||||
def test_relative_application_path(self):
|
||||
root, xml = self._make_launchbox("Emulators\\RetroArch\\retroarch.exe")
|
||||
ra_dir = root / "LaunchBox" / "Emulators" / "RetroArch"
|
||||
ra_dir.mkdir(parents=True)
|
||||
self.assertEqual(
|
||||
install._launchbox_retroarch_system_dir(xml), ra_dir / "system"
|
||||
)
|
||||
|
||||
def test_absolute_application_path(self):
|
||||
emu_dir = Path(tempfile.mkdtemp()) / "RetroArch"
|
||||
emu_dir.mkdir(parents=True)
|
||||
root, xml = self._make_launchbox(str(emu_dir / "retroarch.exe"))
|
||||
self.assertEqual(
|
||||
install._launchbox_retroarch_system_dir(xml), emu_dir / "system"
|
||||
)
|
||||
|
||||
def test_no_retroarch_entry(self):
|
||||
root, xml = self._make_launchbox("Emulators\\PCSX2\\pcsx2.exe", "PCSX2")
|
||||
self.assertIsNone(install._launchbox_retroarch_system_dir(xml))
|
||||
|
||||
def test_missing_emulator_directory(self):
|
||||
root, xml = self._make_launchbox("Emulators\\RetroArch\\retroarch.exe")
|
||||
self.assertIsNone(install._launchbox_retroarch_system_dir(xml))
|
||||
|
||||
def test_stale_entry_before_installed_one(self):
|
||||
root = Path(tempfile.mkdtemp())
|
||||
data = root / "LaunchBox" / "Data"
|
||||
data.mkdir(parents=True)
|
||||
ra_dir = root / "LaunchBox" / "Emulators" / "RetroArch"
|
||||
ra_dir.mkdir(parents=True)
|
||||
xml = data / "Emulators.xml"
|
||||
xml.write_text(
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n"
|
||||
"<LaunchBox>\n"
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch (old)</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch-old\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
"</LaunchBox>\n"
|
||||
)
|
||||
self.assertEqual(
|
||||
install._launchbox_retroarch_system_dir(xml), ra_dir / "system"
|
||||
)
|
||||
|
||||
def test_missing_or_malformed_xml(self):
|
||||
self.assertIsNone(
|
||||
install._launchbox_retroarch_system_dir(Path("/nonexistent/Emulators.xml"))
|
||||
)
|
||||
root = Path(tempfile.mkdtemp())
|
||||
bad = root / "Emulators.xml"
|
||||
bad.write_text("not xml at all <<<")
|
||||
self.assertIsNone(install._launchbox_retroarch_system_dir(bad))
|
||||
|
||||
|
||||
class TestRetroarchPathExpansion(unittest.TestCase):
|
||||
"""RetroArch abbreviates paths with '~' and ':' in its config."""
|
||||
|
||||
def _cfg(self, value: str) -> Path:
|
||||
app_dir = Path(tempfile.mkdtemp())
|
||||
(app_dir / "retroarch.cfg").write_text(f'system_directory = "{value}"\n')
|
||||
return app_dir
|
||||
|
||||
def test_application_dir_prefix(self):
|
||||
app_dir = self._cfg(":\\system")
|
||||
self.assertEqual(
|
||||
install._parse_retroarch_system_dir(app_dir / "retroarch.cfg"),
|
||||
app_dir / "system",
|
||||
)
|
||||
|
||||
def test_application_dir_prefix_forward_slash(self):
|
||||
app_dir = self._cfg(":/system")
|
||||
self.assertEqual(
|
||||
install._parse_retroarch_system_dir(app_dir / "retroarch.cfg"),
|
||||
app_dir / "system",
|
||||
)
|
||||
|
||||
def test_home_prefix(self):
|
||||
app_dir = self._cfg("~/bios")
|
||||
self.assertEqual(
|
||||
install._parse_retroarch_system_dir(app_dir / "retroarch.cfg"),
|
||||
Path.home() / "bios",
|
||||
)
|
||||
|
||||
def test_application_dir_overrides_config_dir(self):
|
||||
app_dir = self._cfg(":\\system")
|
||||
elsewhere = Path(tempfile.mkdtemp())
|
||||
self.assertEqual(
|
||||
install._parse_retroarch_system_dir(
|
||||
app_dir / "retroarch.cfg", elsewhere
|
||||
),
|
||||
elsewhere / "system",
|
||||
)
|
||||
|
||||
def test_absolute_path_untouched(self):
|
||||
target = Path(tempfile.mkdtemp()) / "bios"
|
||||
app_dir = self._cfg(str(target))
|
||||
self.assertEqual(
|
||||
install._parse_retroarch_system_dir(app_dir / "retroarch.cfg"), target
|
||||
)
|
||||
|
||||
|
||||
class TestLaunchboxRoot(unittest.TestCase):
|
||||
"""LaunchBox installs where the user chooses and keeps no registry key."""
|
||||
|
||||
def _make_root(self, root: Path) -> Path:
|
||||
(root / "Data").mkdir(parents=True)
|
||||
(root / "Data" / "Emulators.xml").write_text(
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n<LaunchBox></LaunchBox>\n"
|
||||
)
|
||||
return root
|
||||
|
||||
def test_shortcut_target_is_read(self):
|
||||
# Byte layout of the shortcut a real install writes
|
||||
lnk = Path(tempfile.mkdtemp()) / "LaunchBox.lnk"
|
||||
lnk.write_bytes(
|
||||
b"L\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xc0\x00\x00\x00"
|
||||
b"\x00\x00\x00\x46" + b"\x00" * 8
|
||||
+ b"C:\\Games\\LaunchBox\\Core\\LaunchBox.exe\x00"
|
||||
b"\x1c\x00\x00\x00LaunchBox\x00"
|
||||
)
|
||||
self.assertEqual(
|
||||
install._lnk_target(lnk, "LaunchBox.exe"),
|
||||
Path("C:/Games/LaunchBox/Core/LaunchBox.exe"),
|
||||
)
|
||||
|
||||
def test_shortcut_without_target_is_ignored(self):
|
||||
lnk = Path(tempfile.mkdtemp()) / "LaunchBox.lnk"
|
||||
lnk.write_bytes(b"L\x00\x00\x00 no target here ")
|
||||
self.assertIsNone(install._lnk_target(lnk, "LaunchBox.exe"))
|
||||
|
||||
def test_shortcut_pointing_elsewhere_falls_back(self):
|
||||
# A stale shortcut must not win over a real installation
|
||||
userprofile = Path(tempfile.mkdtemp())
|
||||
root = self._make_root(userprofile / "LaunchBox")
|
||||
appdata = Path(tempfile.mkdtemp())
|
||||
lnk_dir = (
|
||||
appdata / "Microsoft" / "Windows" / "Start Menu" / "Programs" / "LaunchBox"
|
||||
)
|
||||
lnk_dir.mkdir(parents=True)
|
||||
(lnk_dir / "LaunchBox.lnk").write_bytes(
|
||||
b"L\x00\x00\x00D:\\Gone\\LaunchBox\\Core\\LaunchBox.exe\x00"
|
||||
)
|
||||
env = {"APPDATA": str(appdata), "USERPROFILE": str(userprofile)}
|
||||
with unittest.mock.patch.dict(os.environ, env):
|
||||
self.assertEqual(install.launchbox_root("windows"), root)
|
||||
|
||||
def test_falls_back_to_userprofile(self):
|
||||
userprofile = Path(tempfile.mkdtemp())
|
||||
root = self._make_root(userprofile / "LaunchBox")
|
||||
env = {"APPDATA": str(Path(tempfile.mkdtemp())), "USERPROFILE": str(userprofile)}
|
||||
with unittest.mock.patch.dict(os.environ, env):
|
||||
self.assertEqual(install.launchbox_root("windows"), root)
|
||||
|
||||
def test_absent_on_linux(self):
|
||||
self.assertIsNone(install.launchbox_root("linux"))
|
||||
|
||||
def test_nothing_installed(self):
|
||||
env = {
|
||||
"APPDATA": str(Path(tempfile.mkdtemp())),
|
||||
"USERPROFILE": str(Path(tempfile.mkdtemp())),
|
||||
}
|
||||
with unittest.mock.patch.dict(os.environ, env):
|
||||
self.assertIsNone(install.launchbox_root("windows"))
|
||||
|
||||
|
||||
class TestLaunchboxBiosDirs(unittest.TestCase):
|
||||
"""LaunchBox computes where each emulator it manages keeps its BIOS."""
|
||||
|
||||
def _make(self, entries: list[tuple[str, str]]) -> Path:
|
||||
root = Path(tempfile.mkdtemp()) / "LaunchBox"
|
||||
(root / "Data").mkdir(parents=True)
|
||||
body = "".join(
|
||||
" <Emulator>\n"
|
||||
f" <Title>{title}</Title>\n"
|
||||
f" <ApplicationPath>{app}</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
for title, app in entries
|
||||
)
|
||||
(root / "Data" / "Emulators.xml").write_text(
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n"
|
||||
f"<LaunchBox>\n{body}</LaunchBox>\n"
|
||||
)
|
||||
for _, app in entries:
|
||||
(root / Path(app.replace("\\", "/")).parent).mkdir(parents=True, exist_ok=True)
|
||||
return root
|
||||
|
||||
def test_pcsx2_portable_default_bios(self):
|
||||
root = self._make([("PCSX2", "Emulators\\PCSX2\\pcsx2.exe")])
|
||||
emu = root / "Emulators" / "PCSX2"
|
||||
(emu / "portable.ini").write_text("")
|
||||
(emu / "inis").mkdir()
|
||||
(emu / "inis" / "PCSX2.ini").write_text("[Folders]\nBios = bios\n")
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["pcsx2"], emu / "bios")
|
||||
|
||||
def test_pcsx2_portable_absolute_bios(self):
|
||||
root = self._make([("PCSX2", "Emulators\\PCSX2\\pcsx2.exe")])
|
||||
emu = root / "Emulators" / "PCSX2"
|
||||
elsewhere = Path(tempfile.mkdtemp()) / "ps2bios"
|
||||
(emu / "portable.ini").write_text("")
|
||||
(emu / "inis").mkdir()
|
||||
(emu / "inis" / "PCSX2.ini").write_text(f"Bios = {elsewhere}\n")
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["pcsx2"], elsewhere)
|
||||
|
||||
def test_pcsx2_portable_txt_also_triggers_portable_mode(self):
|
||||
root = self._make([("PCSX2", "Emulators\\PCSX2\\pcsx2.exe")])
|
||||
emu = root / "Emulators" / "PCSX2"
|
||||
(emu / "portable.txt").write_text("")
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["pcsx2"], emu / "bios")
|
||||
|
||||
def test_pcsx2_portable_txt_names_a_data_root(self):
|
||||
root = self._make([("PCSX2", "Emulators\\PCSX2\\pcsx2.exe")])
|
||||
emu = root / "Emulators" / "PCSX2"
|
||||
(emu / "portable.txt").write_text("mydata\n")
|
||||
self.assertEqual(
|
||||
install.launchbox_bios_dirs(root)["pcsx2"], emu / "mydata" / "bios"
|
||||
)
|
||||
|
||||
def test_pcsx2_without_config_uses_documents(self):
|
||||
root = self._make([("PCSX2", "Emulators\\PCSX2\\pcsx2.exe")])
|
||||
userprofile = Path(tempfile.mkdtemp())
|
||||
with unittest.mock.patch.dict(os.environ, {"USERPROFILE": str(userprofile)}):
|
||||
self.assertEqual(
|
||||
install.launchbox_bios_dirs(root)["pcsx2"],
|
||||
userprofile / "Documents" / "PCSX2" / "bios",
|
||||
)
|
||||
|
||||
def test_xemu_defaults_to_bios_folder(self):
|
||||
root = self._make([("Xemu", "Emulators\\Xemu\\xemu.exe")])
|
||||
emu = root / "Emulators" / "Xemu"
|
||||
with unittest.mock.patch.dict(os.environ, {"APPDATA": str(Path(tempfile.mkdtemp()))}):
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["xemu"], emu / "bios")
|
||||
|
||||
def test_xemu_honours_configured_bootrom(self):
|
||||
root = self._make([("Xemu", "Emulators\\Xemu\\xemu.exe")])
|
||||
emu = root / "Emulators" / "Xemu"
|
||||
configured = Path(tempfile.mkdtemp()) / "xbox"
|
||||
configured.mkdir()
|
||||
(configured / "mcpx_1.0.bin").write_text("x")
|
||||
(emu / "xemu.toml").write_text(
|
||||
"[sys.files]\n"
|
||||
f"bootrom_path = '{configured / 'mcpx_1.0.bin'}'\n"
|
||||
)
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["xemu"], configured)
|
||||
|
||||
def test_dolphin_portable_user_folder(self):
|
||||
root = self._make([("Dolphin", "Emulators\\Dolphin\\Dolphin.exe")])
|
||||
emu = root / "Emulators" / "Dolphin"
|
||||
(emu / "portable.txt").write_text("")
|
||||
self.assertEqual(install.launchbox_bios_dirs(root)["dolphin"], emu / "User")
|
||||
|
||||
def test_dolphin_without_portable_marker_is_absent(self):
|
||||
root = self._make([("Dolphin", "Emulators\\Dolphin\\Dolphin.exe")])
|
||||
(root / "Emulators" / "Dolphin" / "User").mkdir()
|
||||
self.assertNotIn("dolphin", install.launchbox_bios_dirs(root))
|
||||
|
||||
def test_unknown_emulators_are_ignored(self):
|
||||
root = self._make([("Cemu", "Emulators\\Cemu\\Cemu.exe")])
|
||||
self.assertEqual(install.launchbox_bios_dirs(root), {})
|
||||
|
||||
def test_doctype_is_rejected(self):
|
||||
root = Path(tempfile.mkdtemp()) / "LaunchBox"
|
||||
(root / "Data").mkdir(parents=True)
|
||||
(root / "Data" / "Emulators.xml").write_text(
|
||||
"<!DOCTYPE LaunchBox [<!ENTITY a 'x'>]>\n<LaunchBox></LaunchBox>\n"
|
||||
)
|
||||
self.assertEqual(install.launchbox_emulators(root / "Data" / "Emulators.xml"), {})
|
||||
|
||||
|
||||
class TestStandaloneCopiesExtraDirs(unittest.TestCase):
|
||||
"""Setups that keep emulators outside the default locations."""
|
||||
|
||||
def _manifest(self) -> dict:
|
||||
return {
|
||||
"standalone_copies": [
|
||||
{
|
||||
"pattern": "ps2-*.bin",
|
||||
"emulator": "pcsx2",
|
||||
"targets": {"windows": []},
|
||||
},
|
||||
{
|
||||
"file": "GC/USA/IPL.bin",
|
||||
"emulator": "dolphin",
|
||||
"targets": {"windows": []},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
def test_pattern_entry_copies_into_extra_dir(self):
|
||||
bios = Path(tempfile.mkdtemp())
|
||||
(bios / "ps2-0230a.bin").write_text("rom")
|
||||
extra = Path(tempfile.mkdtemp()) / "bios"
|
||||
extra.mkdir()
|
||||
copied, _ = install.do_standalone_copies(
|
||||
self._manifest(), bios, "windows", {"pcsx2": extra}
|
||||
)
|
||||
self.assertEqual(copied, 1)
|
||||
self.assertTrue((extra / "ps2-0230a.bin").exists())
|
||||
|
||||
def test_file_entry_keeps_its_subdirectory(self):
|
||||
bios = Path(tempfile.mkdtemp())
|
||||
(bios / "GC" / "USA").mkdir(parents=True)
|
||||
(bios / "GC" / "USA" / "IPL.bin").write_text("ipl")
|
||||
user = Path(tempfile.mkdtemp()) / "User"
|
||||
(user / "GC" / "USA").mkdir(parents=True)
|
||||
copied, _ = install.do_standalone_copies(
|
||||
self._manifest(), bios, "windows", {"dolphin": user}
|
||||
)
|
||||
self.assertEqual(copied, 1)
|
||||
self.assertTrue((user / "GC" / "USA" / "IPL.bin").exists())
|
||||
|
||||
def test_no_extra_dirs_is_unchanged(self):
|
||||
bios = Path(tempfile.mkdtemp())
|
||||
(bios / "ps2-0230a.bin").write_text("rom")
|
||||
self.assertEqual(
|
||||
install.do_standalone_copies(self._manifest(), bios, "windows"), (0, 0)
|
||||
)
|
||||
|
||||
|
||||
@unittest.skipUnless(shutil.which("pwsh"), "pwsh not available")
|
||||
class TestLaunchboxDetectionPowershell(unittest.TestCase):
|
||||
"""install.ps1 must resolve LaunchBox's portable RetroArch on its own."""
|
||||
|
||||
def _run(self, entries: str, seed=None, manifest: dict | None = None):
|
||||
userprofile = Path(tempfile.mkdtemp())
|
||||
ra_dir = userprofile / "LaunchBox" / "Emulators" / "RetroArch"
|
||||
ra_dir.mkdir(parents=True)
|
||||
data = userprofile / "LaunchBox" / "Data"
|
||||
data.mkdir(parents=True)
|
||||
(data / "Emulators.xml").write_text(
|
||||
"<?xml version=\"1.0\" standalone=\"yes\"?>\n"
|
||||
"<LaunchBox>\n"
|
||||
f"{entries}"
|
||||
"</LaunchBox>\n"
|
||||
)
|
||||
if seed is not None:
|
||||
seed(userprofile)
|
||||
serve_root = Path(tempfile.mkdtemp())
|
||||
(serve_root / "install").mkdir()
|
||||
(serve_root / "install" / "retroarch.json").write_text(
|
||||
json.dumps(manifest if manifest is not None else {"files": []})
|
||||
)
|
||||
handler = functools.partial(
|
||||
http.server.SimpleHTTPRequestHandler, directory=str(serve_root)
|
||||
)
|
||||
httpd = http.server.ThreadingHTTPServer(("127.0.0.1", 0), handler)
|
||||
threading.Thread(target=httpd.serve_forever, daemon=True).start()
|
||||
try:
|
||||
env = dict(os.environ)
|
||||
env.update(
|
||||
USERPROFILE=str(userprofile),
|
||||
APPDATA=str(tempfile.mkdtemp()),
|
||||
RETROBIOS_BASE_URL=f"http://127.0.0.1:{httpd.server_address[1]}",
|
||||
)
|
||||
proc = subprocess.run(
|
||||
["pwsh", "-NoProfile", "-File", str(REPO_ROOT / "install.ps1")],
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60,
|
||||
)
|
||||
finally:
|
||||
httpd.shutdown()
|
||||
return proc, ra_dir
|
||||
|
||||
def _assert_resolved(self, proc, ra_dir):
|
||||
self.assertIn("Found LaunchBox with RetroArch at", proc.stdout)
|
||||
self.assertIn(str(ra_dir), proc.stdout)
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn("Done.", proc.stdout)
|
||||
|
||||
def test_detects_launchbox_retroarch(self):
|
||||
proc, ra_dir = self._run(
|
||||
" <Emulator>\n"
|
||||
" <Title>Retroarch</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
)
|
||||
self._assert_resolved(proc, ra_dir)
|
||||
|
||||
def test_stale_entry_before_installed_one(self):
|
||||
proc, ra_dir = self._run(
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch (old)</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch-old\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
)
|
||||
self._assert_resolved(proc, ra_dir)
|
||||
|
||||
def test_system_directory_from_config(self):
|
||||
def seed(root: Path) -> None:
|
||||
ra = root / "LaunchBox" / "Emulators" / "RetroArch"
|
||||
(ra / "bios").mkdir(parents=True)
|
||||
(ra / "retroarch.cfg").write_text('system_directory = ":\\bios"\n')
|
||||
|
||||
proc, ra_dir = self._run(
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n",
|
||||
seed=seed,
|
||||
)
|
||||
self.assertIn("Found LaunchBox with RetroArch at", proc.stdout)
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
self.assertIn(str(ra_dir / "bios"), proc.stdout)
|
||||
|
||||
def test_standalone_copy_reaches_launchbox_emulator(self):
|
||||
def seed(root: Path) -> None:
|
||||
system = root / "LaunchBox" / "Emulators" / "RetroArch" / "system"
|
||||
system.mkdir(parents=True)
|
||||
(system / "ps2-0230a.bin").write_text("rom")
|
||||
pcsx2 = root / "LaunchBox" / "Emulators" / "PCSX2"
|
||||
(pcsx2 / "bios").mkdir(parents=True)
|
||||
(pcsx2 / "portable.ini").write_text("")
|
||||
(pcsx2 / "inis").mkdir()
|
||||
(pcsx2 / "inis" / "PCSX2.ini").write_text("[Folders]\nBios = bios\n")
|
||||
|
||||
manifest = {
|
||||
"files": [],
|
||||
"standalone_copies": [
|
||||
{
|
||||
"pattern": "ps2-*.bin",
|
||||
"emulator": "pcsx2",
|
||||
"targets": {"windows": []},
|
||||
}
|
||||
],
|
||||
}
|
||||
proc, ra_dir = self._run(
|
||||
" <Emulator>\n"
|
||||
" <Title>RetroArch</Title>\n"
|
||||
" <ApplicationPath>Emulators\\RetroArch\\retroarch.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n"
|
||||
" <Emulator>\n"
|
||||
" <Title>PCSX2</Title>\n"
|
||||
" <ApplicationPath>Emulators\\PCSX2\\pcsx2.exe</ApplicationPath>\n"
|
||||
" </Emulator>\n",
|
||||
seed=seed,
|
||||
manifest=manifest,
|
||||
)
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
landed = ra_dir.parent / "PCSX2" / "bios" / "ps2-0230a.bin"
|
||||
self.assertTrue(landed.exists(), proc.stdout)
|
||||
|
||||
|
||||
class TestDetectFrontends(unittest.TestCase):
|
||||
"""Frontends have no BIOS directory of their own but hint at the setup."""
|
||||
|
||||
def test_esde_from_home_directory(self):
|
||||
home = Path(tempfile.mkdtemp())
|
||||
(home / "ES-DE").mkdir()
|
||||
old = os.environ.pop("ESDE_APPDATA_DIR", None)
|
||||
try:
|
||||
self.assertIn("esde", install.detect_frontends("linux", home=home))
|
||||
finally:
|
||||
if old is not None:
|
||||
os.environ["ESDE_APPDATA_DIR"] = old
|
||||
|
||||
def test_esde_from_env_dir(self):
|
||||
home = Path(tempfile.mkdtemp())
|
||||
appdata = Path(tempfile.mkdtemp())
|
||||
os.environ["ESDE_APPDATA_DIR"] = str(appdata)
|
||||
try:
|
||||
self.assertIn("esde", install.detect_frontends("linux", home=home))
|
||||
finally:
|
||||
del os.environ["ESDE_APPDATA_DIR"]
|
||||
|
||||
def test_nothing_detected(self):
|
||||
home = Path(tempfile.mkdtemp())
|
||||
old = os.environ.pop("ESDE_APPDATA_DIR", None)
|
||||
try:
|
||||
self.assertEqual(install.detect_frontends("linux", home=home), [])
|
||||
finally:
|
||||
if old is not None:
|
||||
os.environ["ESDE_APPDATA_DIR"] = old
|
||||
|
||||
|
||||
class TestNormalizePlatform(unittest.TestCase):
|
||||
"""Manifest URLs are case sensitive: user input must be normalized."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user