b9bfec961c
Some titles never show up in a Steam/Lutris/Heroic scan — standalone mod
launchers like SPT (Single-Player Tarkov), itch.io downloads, hand-installed
executables. Add a user-authored custom-games list (core/customgames.py) shown
alongside the other sources in `rigdoctor games` and the GUI.
Each entry can carry a launch command and a log directory:
- `rigdoctor games add "SPT" --command .../tarkov.sh` (logs/ auto-detected)
- `rigdoctor games play "SPT"` launches it under the crash-capture wrapper
(wrap.run gains an explicit game-name override, since there's no SteamAppId)
- the diagnostic now feeds the game's own logs to the analysis: gamelogs
.collect(game=...) tails the registered log dir (SPT's server/launcher logs)
alongside the kernel log, freshness-scoped by mtime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
86 lines
3.3 KiB
Python
86 lines
3.3 KiB
Python
"""Tests for user-added games (M6): add/remove/scan of titles no launcher reports (e.g. SPT)."""
|
|
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
from rigdoctor.core import customgames
|
|
|
|
|
|
class CustomGamesTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
self._file = Path(self._tmp.name) / "custom-games.json"
|
|
self._patch = mock.patch.object(customgames.config, "CUSTOM_GAMES_FILE", self._file)
|
|
self._patch.start()
|
|
|
|
def tearDown(self):
|
|
self._patch.stop()
|
|
self._tmp.cleanup()
|
|
|
|
def test_missing_file_scans_empty(self):
|
|
self.assertEqual(customgames.scan(), [])
|
|
self.assertEqual(customgames.names(), [])
|
|
|
|
def test_add_then_scan_returns_game(self):
|
|
self.assertTrue(customgames.add("SPT"))
|
|
games = customgames.scan()
|
|
self.assertEqual(len(games), 1)
|
|
self.assertEqual(games[0].name, "SPT")
|
|
self.assertEqual(games[0].launcher, "custom")
|
|
self.assertTrue(self._file.exists()) # persisted
|
|
|
|
def test_add_is_idempotent_case_insensitive(self):
|
|
self.assertTrue(customgames.add("SPT"))
|
|
self.assertFalse(customgames.add("spt")) # already present
|
|
self.assertFalse(customgames.add(" ")) # blank
|
|
self.assertEqual(customgames.names(), ["SPT"])
|
|
|
|
def test_remove(self):
|
|
customgames.add("SPT")
|
|
customgames.add("Minecraft")
|
|
self.assertTrue(customgames.remove("spt")) # case-insensitive
|
|
self.assertEqual(customgames.names(), ["Minecraft"])
|
|
self.assertFalse(customgames.remove("nope"))
|
|
|
|
def test_scan_sorted_by_name(self):
|
|
for n in ("Zomboid", "Apex", "SPT"):
|
|
customgames.add(n)
|
|
self.assertEqual([g.name for g in customgames.scan()], ["Apex", "SPT", "Zomboid"])
|
|
|
|
def test_command_and_logdir_stored_and_resolved(self):
|
|
logs = Path(self._tmp.name) / "logs"
|
|
logs.mkdir()
|
|
sh = Path(self._tmp.name) / "tarkov.sh"
|
|
sh.write_text("#!/bin/sh\n")
|
|
self.assertTrue(customgames.add("SPT", command=str(sh), logdir=str(logs)))
|
|
self.assertEqual(customgames.command("SPT"), [str(sh)])
|
|
self.assertEqual(customgames.log_dir("SPT"), str(logs))
|
|
|
|
def test_logdir_inferred_from_sibling_logs(self):
|
|
# A command with a sibling logs/ dir (SPT's layout) → logdir auto-detected.
|
|
sh = Path(self._tmp.name) / "tarkov.sh"
|
|
sh.write_text("#!/bin/sh\n")
|
|
(Path(self._tmp.name) / "logs").mkdir()
|
|
self.assertTrue(customgames.add("SPT", command=str(sh)))
|
|
self.assertEqual(customgames.log_dir("SPT"), str(Path(self._tmp.name) / "logs"))
|
|
|
|
def test_no_command_resolves_to_none(self):
|
|
customgames.add("SPT")
|
|
self.assertIsNone(customgames.command("SPT"))
|
|
self.assertIsNone(customgames.command("missing"))
|
|
self.assertIsNone(customgames.log_dir("SPT"))
|
|
|
|
def test_corrupt_file_degrades_to_empty(self):
|
|
self._file.parent.mkdir(parents=True, exist_ok=True)
|
|
self._file.write_text("{not json")
|
|
self.assertEqual(customgames.scan(), [])
|
|
# and a subsequent add still works (overwrites the garbage)
|
|
self.assertTrue(customgames.add("SPT"))
|
|
self.assertEqual(customgames.names(), ["SPT"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|