diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/steamLaunchOptions.test.ts | 95 | ||||
| -rw-r--r-- | tests/test_flatpak_service.py | 299 | ||||
| -rw-r--r-- | tests/test_plugin_migration.py | 2 | ||||
| -rw-r--r-- | tests/test_steam_service.py | 101 | ||||
| -rw-r--r-- | tests/test_wrapper_service.py | 141 |
5 files changed, 66 insertions, 572 deletions
diff --git a/tests/steamLaunchOptions.test.ts b/tests/steamLaunchOptions.test.ts index c799907..1bb9526 100644 --- a/tests/steamLaunchOptions.test.ts +++ b/tests/steamLaunchOptions.test.ts @@ -78,21 +78,19 @@ test("removes only old plugin assignments and preserves DXVK settings", () => { ); }); -test("reads the matching app-details field and installs/removes Steam integration", async () => { +test("reads the matching app-details field and installs/removes host integration", async () => { const previousWindow = (globalThis as Record<string, unknown>).window; const previousSteamClient = (globalThis as Record<string, unknown>).SteamClient; let appOptions = "FOO=bar %command%"; let shortcutOptions = "--windowed"; - let shortcutTarget = '"flatpak"'; const appWrites: string[] = []; const shortcutWrites: string[] = []; - const targetWrites: string[] = []; const unregisters: number[] = []; const apps = { RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { callback(appId === 42 ? { strLaunchOptions: appOptions, strShortcutLaunchOptions: "wrong-field" } - : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions, strLaunchOptions: "wrong-field" }); + : { strShortcutLaunchOptions: shortcutOptions, strLaunchOptions: "wrong-field" }); return { unregister: () => unregisters.push(appId) }; }, SetAppLaunchOptions(appId: number, options: string) { @@ -105,11 +103,6 @@ test("reads the matching app-details field and installs/removes Steam integratio shortcutWrites.push(options); shortcutOptions = options; }, - SetShortcutExe(appId: number, executable: string) { - assert.equal(appId, 43); - targetWrites.push(executable); - shortcutTarget = executable; - }, }; (globalThis as Record<string, unknown>).window = { setTimeout, clearTimeout }; (globalThis as Record<string, unknown>).SteamClient = { Apps: apps }; @@ -122,16 +115,15 @@ test("reads the matching app-details field and installs/removes Steam integratio assert.equal(appWrites.length, 1); assert.equal(shortcutWrites.length, 0); - const shortcut = await installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); - assert.equal(shortcut.originalExecutable, "/usr/bin/flatpak"); - assert.equal(shortcut.snapshot.target, wrapper); - assert.deepEqual(targetWrites, [wrapper]); - const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.originalExecutable, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }); - assert.equal(restored.target, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); - assert.equal(shortcutWrites.length, 0); + const shortcut = await installWrapperIntegration(43, true, wrapper); + assert.equal(shortcut.snapshot.options, `${wrapper} %command% --windowed`); + assert.equal(shortcut.commandTokenAdded, true); + assert.deepEqual(shortcutWrites, [shortcut.snapshot.options]); + const restored = await removeWrapperIntegration(43, true, wrapper, shortcut.commandTokenAdded); + assert.equal(restored.options, "--windowed"); + assert.deepEqual(shortcutWrites, [shortcut.snapshot.options, "--windowed"]); - const cleaned = await removeWrapperIntegration(42, false, wrapper, undefined, installed.commandTokenAdded); + const cleaned = await removeWrapperIntegration(42, false, wrapper, installed.commandTokenAdded); assert.equal(cleaned.options, "FOO=bar %command%".replaceAll(" ", " ")); assert.ok(unregisters.includes(42)); assert.ok(unregisters.includes(43)); @@ -143,46 +135,35 @@ test("reads the matching app-details field and installs/removes Steam integratio } }); -test("uses shortcut launch options for a host shortcut without changing its Target", async () => { +test("uses shortcut launch options for a non-Steam shortcut", async () => { const previousWindow = (globalThis as Record<string, unknown>).window; const previousSteamClient = (globalThis as Record<string, unknown>).SteamClient; const originalOptions = 'DESKTOPINTEGRATION=1 "/home/deck/AppImages/dusk.appimage"'; let shortcutOptions = originalOptions; - let shortcutTarget = "env"; const shortcutWrites: string[] = []; - const targetWrites: string[] = []; const apps = { RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: shortcutTarget, strShortcutLaunchOptions: shortcutOptions }); + callback({ strShortcutLaunchOptions: shortcutOptions }); return { unregister() {} }; }, SetShortcutLaunchOptions(_appId: number, options: string) { shortcutWrites.push(options); shortcutOptions = options; }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - }, }; (globalThis as Record<string, unknown>).window = { setTimeout, clearTimeout }; (globalThis as Record<string, unknown>).SteamClient = { Apps: apps }; try { - const installed = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); - assert.equal(installed.originalExecutable, undefined); - assert.equal(installed.snapshot.target, "env"); + const installed = await installWrapperIntegration(44, true, wrapper); assert.equal(installed.snapshot.options, 'DESKTOPINTEGRATION=1 ~/.lsfg %command% "/home/deck/AppImages/dusk.appimage"'); - assert.deepEqual(targetWrites, []); assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - const secondInstall = await installWrapperIntegration(44, true, wrapper, false, { kind: "host" }); + const secondInstall = await installWrapperIntegration(44, true, wrapper); assert.equal(secondInstall.snapshot.options, installed.snapshot.options); assert.deepEqual(shortcutWrites, [installed.snapshot.options]); - const restored = await removeWrapperIntegration(44, true, wrapper, undefined, installed.commandTokenAdded, { kind: "host" }); - assert.equal(restored.target, "env"); + const restored = await removeWrapperIntegration(44, true, wrapper, installed.commandTokenAdded); assert.equal(restored.options, originalOptions); - assert.deepEqual(targetWrites, []); } finally { if (previousWindow === undefined) delete (globalThis as Record<string, unknown>).window; else (globalThis as Record<string, unknown>).window = previousWindow; @@ -191,42 +172,18 @@ test("uses shortcut launch options for a host shortcut without changing its Targ } }); -test("fails closed when shortcut Target ownership or setters are unavailable", async () => { - const previousWindow = (globalThis as Record<string, unknown>).window; - const previousSteamClient = (globalThis as Record<string, unknown>).SteamClient; - (globalThis as Record<string, unknown>).window = { setTimeout, clearTimeout }; - (globalThis as Record<string, unknown>).SteamClient = { - Apps: { - RegisterForAppDetails(_appId: number, callback: (details: SteamAppDetails) => void) { - callback({ strShortcutExe: _appId === 99 ? "/usr/bin/flatpak" : "garbage", strShortcutLaunchOptions: "" }); - return { unregister() {} }; - }, - }, - }; - try { - await assert.rejects(installWrapperIntegration(98, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /supported executable/); - await assert.rejects(installWrapperIntegration(99, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target API is unavailable/); - await assert.rejects(removeWrapperIntegration(99, true, wrapper, "/usr/bin/original", false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /Target changed externally/); - } finally { - if (previousWindow === undefined) delete (globalThis as Record<string, unknown>).window; - else (globalThis as Record<string, unknown>).window = previousWindow; - if (previousSteamClient === undefined) delete (globalThis as Record<string, unknown>).SteamClient; - else (globalThis as Record<string, unknown>).SteamClient = previousSteamClient; - } -}); - -test("restores launch options and shortcut Target when a setter fails after changing them", async () => { +test("restores launch options when a setter fails after changing them", async () => { const previousWindow = (globalThis as Record<string, unknown>).window; const previousSteamClient = (globalThis as Record<string, unknown>).SteamClient; let appOptions = "FOO=bar %command%"; - let shortcutTarget = "/usr/bin/flatpak"; + let shortcutOptions = "--windowed"; const appWrites: string[] = []; - const targetWrites: string[] = []; + const shortcutWrites: string[] = []; const apps = { RegisterForAppDetails(appId: number, callback: (details: SteamAppDetails) => void) { callback(appId === 42 ? { strLaunchOptions: appOptions } - : { strShortcutExe: shortcutTarget, strShortcutLaunchOptions: "" }); + : { strShortcutLaunchOptions: shortcutOptions }); return { unregister() {} }; }, SetAppLaunchOptions(_appId: number, options: string) { @@ -234,10 +191,10 @@ test("restores launch options and shortcut Target when a setter fails after chan appOptions = options; if (options.includes(wrapper)) throw new Error("simulated launch-option write failure"); }, - SetShortcutExe(_appId: number, executable: string) { - targetWrites.push(executable); - shortcutTarget = executable; - if (executable === wrapper) throw new Error("simulated Target write failure"); + SetShortcutLaunchOptions(_appId: number, options: string) { + shortcutWrites.push(options); + shortcutOptions = options; + if (options.includes(wrapper)) throw new Error("simulated shortcut launch-option write failure"); }, }; (globalThis as Record<string, unknown>).window = { setTimeout, clearTimeout }; @@ -247,9 +204,9 @@ test("restores launch options and shortcut Target when a setter fails after chan assert.equal(appOptions, "FOO=bar %command%"); assert.deepEqual(appWrites, [`FOO=bar ${wrapper} %command%`, "FOO=bar %command%"]); - await assert.rejects(installWrapperIntegration(43, true, wrapper, false, { kind: "flatpak", flatpakAppId: "com.example.Game" }), /simulated Target write failure/); - assert.equal(shortcutTarget, "/usr/bin/flatpak"); - assert.deepEqual(targetWrites, [wrapper, "/usr/bin/flatpak"]); + await assert.rejects(installWrapperIntegration(43, true, wrapper), /simulated shortcut launch-option write failure/); + assert.equal(shortcutOptions, "--windowed"); + assert.deepEqual(shortcutWrites, [`${wrapper} %command% --windowed`, "--windowed"]); } finally { if (previousWindow === undefined) delete (globalThis as Record<string, unknown>).window; else (globalThis as Record<string, unknown>).window = previousWindow; diff --git a/tests/test_flatpak_service.py b/tests/test_flatpak_service.py deleted file mode 100644 index d5baf61..0000000 --- a/tests/test_flatpak_service.py +++ /dev/null @@ -1,299 +0,0 @@ -import json -import sys -import tempfile -import types -import unittest -from pathlib import Path -from unittest.mock import Mock - - -sys.modules.setdefault( - "decky", - types.SimpleNamespace(DECKY_USER_HOME="/home/deck", logger=Mock()), -) -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "py_modules")) - -from lsfg_vk.flatpak_service import FlatpakService - - -class FlatpakServiceTests(unittest.TestCase): - def setUp(self): - self.tempdir = tempfile.TemporaryDirectory() - self.home = Path(self.tempdir.name) / "home" / "deck" - self.home.mkdir(parents=True) - self.service = FlatpakService() - self.service.user_home = self.home - self.service.config_dir = self.home / ".config/lsfg-vk" - self.service.config_file_path = self.service.config_dir / "conf.toml" - self.service.check_flatpak_available = Mock(return_value=True) - self.service._run_flatpak_command = Mock(side_effect=self._run_flatpak_command) - self.runtime_ref = "org.freedesktop.Platform/x86_64/24.08" - self.runtime_metadata = "" - self.user_branches = set() - self.system_branches = set() - self.install_branch = "24.08" - self.bundle = self.home / "lsfg-vk-24.08.flatpak" - self.bundle.write_bytes(b"bundle") - self.service._bundled_extension_path = Mock(return_value=self.bundle) - - def tearDown(self): - self.tempdir.cleanup() - - @staticmethod - def _result(stdout="", returncode=0, stderr=""): - return types.SimpleNamespace(stdout=stdout, returncode=returncode, stderr=stderr) - - @staticmethod - def _extension_line(branch): - return f"org.freedesktop.Platform.VulkanLayer.lsfgvk\tx86_64\t{branch}\n" - - def _run_flatpak_command(self, args, **_kwargs): - if args[0] == "info" and args[1] == "--show-runtime": - return self._result(self.runtime_ref + "\n") - if args[0] == "info" and args[1] == "--show-metadata": - return self._result(self.runtime_metadata) - if args[0] == "list": - branches = self.user_branches if "--user" in args else self.system_branches - return self._result("".join(self._extension_line(branch) for branch in sorted(branches))) - if args[0] == "install": - self.user_branches.add(self.install_branch) - return self._result() - if args[0] == "uninstall": - self.user_branches.discard(args[-1].rsplit("/", 1)[-1]) - return self._result() - raise AssertionError(f"Unexpected Flatpak command: {args}") - - def test_runtime_branch_mapping_is_strict_and_branch_specific(self): - self.assertEqual( - FlatpakService.runtime_branch_from_ref( - "org.freedesktop.Platform/x86_64/24.08" - ), - "24.08", - ) - self.assertEqual( - FlatpakService.runtime_branch_from_ref( - "org.freedesktop.Platform//25.08" - ), - "25.08", - ) - with self.assertRaises(ValueError): - FlatpakService.runtime_branch_from_ref("org.gnome.Sdk/x86_64/46") - with self.assertRaises(ValueError): - FlatpakService.runtime_branch_from_ref( - "org.freedesktop.Platform/x86_64/26.08" - ) - - def test_runtime_branch_mapping_reads_documented_gl_metadata(self): - metadata = """ -[Extension org.freedesktop.Platform.GL] -versions=25.08;25.08-extra;1.4 -version=1.4 -""" - self.assertEqual(FlatpakService.runtime_branch_from_metadata(metadata), "25.08") - with self.assertRaises(ValueError): - FlatpakService.runtime_branch_from_metadata( - "[Extension org.freedesktop.Platform.GL]\nversions=26.08;26.08-extra;1.4\n" - ) - - def test_resolve_reads_required_runtime_instead_of_any_installed_branch(self): - self.user_branches = {"23.08"} - - response = self.service.resolve_app_support("com.example.Game") - - self.assertTrue(response["success"]) - self.assertEqual(response["runtime_branch"], "24.08") - self.assertEqual(response["support_status"], "needs-runtime") - self.assertFalse(response["extension_installed"]) - self.assertEqual( - self.service._run_flatpak_command.call_args_list[0].args[0], - ["info", "--show-runtime", "com.example.Game"], - ) - self.assertEqual( - self.service._run_flatpak_command.call_args_list[1].args[0], - ["list", "--user", "--runtime", "--columns=application,arch,branch"], - ) - self.assertEqual( - self.service._run_flatpak_command.call_args_list[2].args[0], - ["list", "--system", "--runtime", "--columns=application,arch,branch"], - ) - - def test_resolve_maps_kde_and_gnome_runtimes_from_gl_metadata(self): - metadata = "[Extension org.freedesktop.Platform.GL]\nversions=25.08;25.08-extra;1.4\n" - for runtime in ("org.kde.Platform/x86_64/6.10", "org.gnome.Platform/x86_64/49"): - with self.subTest(runtime=runtime): - self.service._run_flatpak_command.reset_mock() - self.runtime_ref = runtime - self.runtime_metadata = metadata - response = self.service.resolve_app_support("com.example.Game") - self.assertEqual(response["runtime_branch"], "25.08") - self.assertEqual(response["support_status"], "needs-runtime") - self.assertEqual( - self.service._run_flatpak_command.call_args_list[1].args[0], - ["info", "--show-metadata", runtime], - ) - - def test_system_extension_is_ready_without_installing_a_user_copy(self): - self.system_branches = {"24.08"} - - response = self.service.ensure_app_support("com.example.Game") - - self.assertTrue(response["success"]) - self.assertEqual(response["support_status"], "ready") - self.assertEqual( - [call.args[0][0] for call in self.service._run_flatpak_command.call_args_list], - ["info", "list", "list"], - ) - self.assertFalse(any(call.args[0][0] == "install" for call in self.service._run_flatpak_command.call_args_list)) - - def test_install_records_only_a_new_user_owned_branch(self): - response = self.service.install_extension("24.08") - - self.assertTrue(response["success"]) - self.assertTrue(response["enabled"]) - self.assertTrue(response["installed"]) - install_args = self.service._run_flatpak_command.call_args_list[2].args[0] - self.assertEqual(install_args[:4], ["install", "--user", "--noninteractive", "--or-update"]) - self.assertEqual( - json.loads(self.service.ownership_path.read_text(encoding="utf-8")), - {"version": 1, "plugin_owned_branches": ["24.08"]}, - ) - - def test_preexisting_branch_is_not_claimed_or_removed(self): - self.user_branches = {"24.08"} - - install_response = self.service.install_extension("24.08") - cleanup_response = self.service.remove_plugin_owned_extensions() - - self.assertTrue(install_response["success"]) - self.assertTrue(install_response["enabled"]) - self.assertTrue(install_response["installed"]) - self.assertFalse(self.service.ownership_path.exists()) - self.assertTrue(cleanup_response["success"]) - self.assertEqual(self.service._run_flatpak_command.call_count, 2) - - def test_extension_toggle_preserves_preexisting_branch(self): - self.user_branches = {"24.08"} - - enable_response = self.service.set_extension_enabled("24.08", True) - disable_response = self.service.set_extension_enabled("24.08", False) - - self.assertTrue(enable_response["success"]) - self.assertTrue(enable_response["enabled"]) - self.assertTrue(enable_response["installed"]) - self.assertTrue(disable_response["success"]) - self.assertTrue(disable_response["enabled"]) - self.assertTrue(disable_response["installed"]) - self.assertFalse(disable_response["removed"]) - self.assertEqual(self.user_branches, {"24.08"}) - self.assertEqual( - [call.args[0][0] for call in self.service._run_flatpak_command.call_args_list], - ["list", "list", "list", "list"], - ) - - def test_extension_toggle_removes_owned_user_branch_but_preserves_system_branch(self): - self.service.ownership_path.parent.mkdir(parents=True, exist_ok=True) - self.service.ownership_path.write_text( - json.dumps({"version": 1, "plugin_owned_branches": ["24.08"]}), - encoding="utf-8", - ) - self.user_branches = {"24.08"} - self.system_branches = {"24.08"} - - disable_response = self.service.set_extension_enabled("24.08", False) - repeat_response = self.service.set_extension_enabled("24.08", False) - - self.assertTrue(disable_response["success"]) - self.assertTrue(disable_response["enabled"]) - self.assertTrue(disable_response["removed"]) - self.assertTrue(repeat_response["success"]) - self.assertTrue(repeat_response["enabled"]) - self.assertTrue(repeat_response["installed"]) - self.assertEqual(self.user_branches, set()) - self.assertEqual(self.system_branches, {"24.08"}) - self.assertFalse(self.service.ownership_path.exists()) - uninstall_commands = [ - call.args[0] - for call in self.service._run_flatpak_command.call_args_list - if call.args[0][0] == "uninstall" - ] - self.assertEqual(len(uninstall_commands), 1) - - def test_corrupt_ownership_metadata_fails_closed(self): - self.service.ownership_path.parent.mkdir(parents=True, exist_ok=True) - self.service.ownership_path.write_text("{not-json", encoding="utf-8") - - response = self.service.remove_plugin_owned_extensions() - - self.assertFalse(response["success"]) - self.assertTrue(response["ownership_uncertain"]) - self.assertEqual(self.service._run_flatpak_command.call_count, 0) - - def test_dangling_ownership_symlink_fails_closed(self): - self.service.ownership_path.parent.mkdir(parents=True, exist_ok=True) - self.service.ownership_path.symlink_to(self.home / "missing-metadata") - - response = self.service.remove_plugin_owned_extensions() - - self.assertFalse(response["success"]) - self.assertTrue(response["ownership_uncertain"]) - self.assertEqual(self.service._run_flatpak_command.call_count, 0) - - def test_ensure_app_support_installs_only_the_app_runtime_branch(self): - response = self.service.ensure_app_support("com.example.Game") - - self.assertTrue(response["success"]) - self.assertEqual(response["support_status"], "ready") - self.assertEqual(response["runtime_branch"], "24.08") - install_args = next( - call.args[0] - for call in self.service._run_flatpak_command.call_args_list - if call.args[0][0] == "install" - ) - self.assertEqual(install_args[0], "install") - self.assertIn("--user", install_args) - self.assertNotIn("23.08", install_args) - self.assertEqual( - json.loads(self.service.ownership_path.read_text(encoding="utf-8")), - {"version": 1, "plugin_owned_branches": ["24.08"]}, - ) - - def test_two_shortcuts_using_one_flatpak_share_one_extension_branch(self): - first = self.service.ensure_app_support("net.pcsx2.PCSX2") - second = self.service.ensure_app_support("net.pcsx2.PCSX2.Dev") - - self.assertEqual(first["support_status"], "ready") - self.assertEqual(second["support_status"], "ready") - install_commands = [ - call.args[0] - for call in self.service._run_flatpak_command.call_args_list - if call.args[0][0] == "install" - ] - self.assertEqual(len(install_commands), 1) - self.assertEqual( - json.loads(self.service.ownership_path.read_text(encoding="utf-8")), - {"version": 1, "plugin_owned_branches": ["24.08"]}, - ) - - def test_cleanup_removes_all_owned_branches_without_reusing_stale_metadata(self): - self.service.ownership_path.parent.mkdir(parents=True, exist_ok=True) - self.service.ownership_path.write_text( - json.dumps({"version": 1, "plugin_owned_branches": ["23.08", "24.08"]}), - encoding="utf-8", - ) - self.user_branches = {"23.08", "24.08"} - - response = self.service.remove_plugin_owned_extensions() - - self.assertTrue(response["success"]) - self.assertEqual(response["removed_branches"], ["23.08", "24.08"]) - self.assertFalse(self.service.ownership_path.exists()) - uninstall_commands = [ - call.args[0] - for call in self.service._run_flatpak_command.call_args_list - if call.args[0][0] == "uninstall" - ] - self.assertEqual(len(uninstall_commands), 2) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_plugin_migration.py b/tests/test_plugin_migration.py index a392f85..54e8f83 100644 --- a/tests/test_plugin_migration.py +++ b/tests/test_plugin_migration.py @@ -25,7 +25,6 @@ class PluginMigrationTests(unittest.TestCase): plugin = Plugin.__new__(Plugin) plugin.installation_service = Mock() - plugin.flatpak_service = Mock() asyncio.run(plugin._migration()) @@ -33,7 +32,6 @@ class PluginMigrationTests(unittest.TestCase): decky.migrate_settings.assert_called_once() decky.migrate_runtime.assert_called_once() plugin.installation_service.install.assert_not_called() - plugin.flatpak_service.migrate_v2.assert_not_called() finally: sys.path.remove("py_modules") if previous_decky is None: diff --git a/tests/test_steam_service.py b/tests/test_steam_service.py index 636c87f..dd78f10 100644 --- a/tests/test_steam_service.py +++ b/tests/test_steam_service.py @@ -11,105 +11,42 @@ sys.modules.setdefault( ) sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "py_modules")) -from lsfg_vk.steam_service import SteamService, classify_shortcut_transport +from lsfg_vk.steam_service import SteamService -class SteamTransportTests(unittest.TestCase): - def test_only_direct_canonical_flatpak_forms_are_classified(self): - self.assertEqual( - classify_shortcut_transport( - "/usr/bin/flatpak", - "run com.example.PCSX2 --fullscreen", - ), - {"kind": "flatpak", "flatpakAppId": "com.example.PCSX2"}, - ) - self.assertEqual( - classify_shortcut_transport( - "flatpak", - "run com.example.PCSX2 --fullscreen", - ), - {"kind": "flatpak", "flatpakAppId": "com.example.PCSX2"}, - ) - self.assertEqual( - classify_shortcut_transport( - "/usr/bin/flatpak run com.example.PCSX2", - "--fullscreen", - ), - {"kind": "flatpak", "flatpakAppId": "com.example.PCSX2"}, - ) - self.assertEqual( - classify_shortcut_transport( - "/usr/bin/bash", - "~/launch-game.sh --fullscreen", - ), - {"kind": "host"}, - ) - self.assertEqual( - classify_shortcut_transport( - "/usr/bin/flatpak", - "--user run com.example.PCSX2", - ), - {"kind": "host"}, - ) - self.assertEqual( - classify_shortcut_transport( - "/usr/bin/flatpak", - "run bash ~/launch-game.sh", - ), - {"kind": "host"}, - ) - self.assertEqual( - classify_shortcut_transport( - "~/.lsfg", - "run --branch=stable --arch=x86_64 com.example.PCSX2", - ), - {"kind": "flatpak", "flatpakAppId": "com.example.PCSX2"}, - ) - self.assertEqual( - classify_shortcut_transport( - "/home/deck/.lsfg", - "run com.example.PCSX2", - ), - {"kind": "flatpak", "flatpakAppId": "com.example.PCSX2"}, - ) - self.assertEqual( - classify_shortcut_transport("~/.lsfg", "--profile high"), - {"kind": "host"}, - ) - - def test_shortcut_data_preserves_transport_inputs(self): +class SteamServiceTests(unittest.TestCase): + def test_shortcut_data_is_host_only_and_preserves_launch_fields(self): game = SteamService._shortcut_game( { "appid": 123456, - "AppName": "PCSX2 shortcut", - "Exe": "/usr/bin/flatpak", - "LaunchOptions": "run net.pcsx2.PCSX2 --fullscreen", + "AppName": "Native shortcut", + "Exe": "/usr/bin/game", + "LaunchOptions": "--fullscreen", "StartDir": "/home/deck/Games", } ) - self.assertEqual(game["appid"], "123456") - self.assertEqual(game["transport"], { - "kind": "flatpak", - "flatpakAppId": "net.pcsx2.PCSX2", + self.assertEqual(game, { + "appid": "123456", + "name": "Native shortcut", + "nonSteam": True, + "executable": "/usr/bin/game", + "arguments": "--fullscreen", + "startDir": "/home/deck/Games", }) - self.assertEqual(game["executable"], "/usr/bin/flatpak") - self.assertEqual(game["arguments"], "run net.pcsx2.PCSX2 --fullscreen") - self.assertEqual(game["startDir"], "/home/deck/Games") - def test_wrapped_flatpak_shortcut_remains_a_flatpak_target(self): + def test_shortcut_data_accepts_missing_optional_launch_fields(self): game = SteamService._shortcut_game( { "appid": 987654, - "AppName": "Wrapped Flatpak", - "Exe": "~/.lsfg", - "LaunchOptions": "run --branch=stable --arch=x86_64 com.example.Game", + "AppName": "Game shortcut", } ) - self.assertEqual(game["transport"], { - "kind": "flatpak", - "flatpakAppId": "com.example.Game", + self.assertEqual(game, { + "appid": "987654", + "name": "Game shortcut", + "nonSteam": True, }) diff --git a/tests/test_wrapper_service.py b/tests/test_wrapper_service.py index 0632d93..592ffb3 100644 --- a/tests/test_wrapper_service.py +++ b/tests/test_wrapper_service.py @@ -1,4 +1,4 @@ -import os +import json import subprocess import sys import tempfile @@ -114,125 +114,6 @@ class WrapperServiceTests(unittest.TestCase): self.assertEqual(passthrough_values["KEEP"], "yes") self.assertEqual(passthrough_values["DXVK_HDR"], "1") - def test_flatpak_shortcut_receives_env_arguments_and_original_target(self): - fake_flatpak = self.home / ".local/bin/flatpak" - fake_flatpak.parent.mkdir(parents=True, exist_ok=True) - fake_flatpak.write_text( - "#!/bin/sh\n" - "printf 'ARG:%s\\n' \"$@\"\n", - encoding="utf-8", - ) - fake_flatpak.chmod(0o755) - self.service.set( - "123", - self._state(dxvkFrameRate=20, enableZink=True), - str(fake_flatpak), - False, - {"kind": "flatpak", "flatpakAppId": "com.example.Game"}, - ) - result = self._run(123, "run", "com.example.Game", "--windowed", env={"DXVK_CONFIG": "foo=1"}) - args = result.stdout.splitlines() - self.assertEqual(args[0], "ARG:run") - self.assertIn("ARG:--filesystem=" + str(self.service.config_dir) + ":rw", args) - self.assertIn("ARG:--filesystem=" + str(self.home / ".local/share/Steam/steamapps/common/Lossless Scaling") + ":ro", args) - self.assertIn("ARG:--env=LSFGVK_CONFIG=" + str(self.service.config_file_path), args) - self.assertIn("ARG:--env=LSFGVK_FLATPAK=1", args) - self.assertIn("ARG:--env=SteamAppId=123", args) - self.assertIn("ARG:--env=ENABLE_GAMESCOPE_WSI=0", args) - self.assertIn("ARG:--env=DXVK_HDR=0", args) - self.assertIn("ARG:--env=__GLX_VENDOR_LIBRARY_NAME=mesa", args) - self.assertIn("ARG:--env=MESA_LOADER_DRIVER_OVERRIDE=zink", args) - self.assertIn("ARG:--env=GALLIUM_DRIVER=zink", args) - self.assertIn("ARG:--env=DXVK_CONFIG=foo=1; dxvk.maxFrameRate = 20", args) - self.assertIn("ARG:com.example.Game", args) - self.assertIn("ARG:--windowed", args) - - def test_flatpak_full_executable_form_is_preserved(self): - fake_flatpak = self.home / ".local/bin/flatpak" - fake_flatpak.parent.mkdir(parents=True, exist_ok=True) - fake_flatpak.write_text( - "#!/bin/sh\n" - "printf 'ARG:%s\\n' \"$@\"\n", - encoding="utf-8", - ) - fake_flatpak.chmod(0o755) - response = self.service.set( - "123", - self._state(), - f"{fake_flatpak} run com.example.Game", - False, - {"kind": "flatpak", "flatpakAppId": "com.example.Game"}, - ) - self.assertTrue(response["success"]) - result = self._run(123, "--windowed") - args = result.stdout.splitlines() - self.assertEqual(args[0], "ARG:run") - self.assertIn("ARG:com.example.Game", args) - self.assertIn("ARG:--windowed", args) - - def test_host_transport_does_not_store_shortcut_target(self): - self.service.set( - "123", - self._state(), - "/usr/bin/flatpak", - False, - {"kind": "flatpak", "flatpakAppId": "com.example.Game"}, - ) - response = self.service.set( - "123", - self._state(), - "/usr/bin/ignored", - False, - {"kind": "host"}, - ) - self.assertTrue(response["success"]) - self.assertIsNone(response["shortcut_exe"]) - self.assertIsNone(self.service.get("123")["shortcut_exe"]) - - def test_flatpak_transport_rejects_non_run_invocation(self): - fake_flatpak = self.home / ".local/bin/flatpak" - fake_flatpak.parent.mkdir(parents=True, exist_ok=True) - fake_flatpak.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8") - fake_flatpak.chmod(0o755) - response = self.service.set( - "123", - self._state(), - str(fake_flatpak), - False, - {"kind": "flatpak", "flatpakAppId": "com.example.Game"}, - ) - self.assertTrue(response["success"]) - result = subprocess.run( - [str(self.service.wrapper_path), "bash", "launch-game.sh"], - env={"PATH": "/usr/bin:/bin", "SteamAppId": "123"}, - capture_output=True, - text=True, - ) - self.assertEqual(result.returncode, 64) - self.assertIn("direct flatpak run", result.stderr) - - def test_flatpak_transport_rejects_external_app_id_change(self): - fake_flatpak = self.home / ".local/bin/flatpak" - fake_flatpak.parent.mkdir(parents=True, exist_ok=True) - fake_flatpak.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8") - fake_flatpak.chmod(0o755) - response = self.service.set( - "123", - self._state(), - str(fake_flatpak), - False, - {"kind": "flatpak", "flatpakAppId": "com.example.Game"}, - ) - self.assertTrue(response["success"]) - result = subprocess.run( - [str(self.service.wrapper_path), "run", "com.other.Game"], - env={"PATH": "/usr/bin:/bin", "SteamAppId": "123"}, - capture_output=True, - text=True, - ) - self.assertEqual(result.returncode, 64) - self.assertIn("application ID changed externally", result.stderr) - def test_invalid_state_and_foreign_wrapper_fail_closed(self): invalid = self.service.set("0", self.service.default_state()) self.assertFalse(invalid["success"]) @@ -246,6 +127,26 @@ class WrapperServiceTests(unittest.TestCase): self.assertIn("unowned", response["error"]) self.assertEqual(self.service.wrapper_path.read_text(encoding="utf-8"), "#!/bin/sh\necho foreign\n") + def test_rejects_unsupported_persisted_fields_without_rewriting(self): + self.service.config_dir.mkdir(parents=True, exist_ok=True) + original = json.dumps({ + "version": self.service.FORMAT_VERSION, + "apps": { + "123": { + "state": self._state(), + "command_token_added": False, + "legacy": "unsupported", + }, + }, + }) + self.service.sidecar_path.write_text(original, encoding="utf-8") + + response = self.service.get("123") + + self.assertFalse(response["success"]) + self.assertIn("Unsupported workaround entry fields", response["error"]) + self.assertEqual(self.service.sidecar_path.read_text(encoding="utf-8"), original) + def test_remove_keeps_a_safe_owned_passthrough_wrapper(self): self.service.set("123", self.service.default_state()) response = self.service.remove("123") |
