Files
dotfiles/scripts/tests/gamemode-watch.test.py
T
funman300 0ab08e8561 gamemode: global auto-trigger via niri window watch
Add scripts/gamemode-watch.py, launched at niri startup, which subscribes
to niri's event stream and toggles gamemode whenever a game window
(steam_app_*, RuneLite, gamescope) is open — so Steam games trigger
gamemode with zero per-game setup instead of needing gamemoderun %command%.

'winwatch' is a third reference-counted source alongside feral + manual.
Pure Watcher class is unit-tested; SIGTERM/finally guarantee cleanup so
the watcher stopping never leaves gamemode stuck on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:51:52 -07:00

97 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""Unit tests for gamemode-watch's pure event logic (no niri, no subprocess).
Loads the hyphenated script by path and drives Watcher with synthetic events,
asserting the exact sequence of add/del calls."""
import importlib.util
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
MOD_PATH = os.path.join(HERE, "..", "gamemode-watch.py")
spec = importlib.util.spec_from_file_location("gamemode_watch", MOD_PATH)
gw = importlib.util.module_from_spec(spec)
spec.loader.exec_module(gw)
fails = 0
def check(desc, got, want):
global fails
if got == want:
print(f"ok - {desc}")
else:
print(f"FAIL - {desc} (got {got!r} want {want!r})")
fails = 1
# --- is_game ---------------------------------------------------------------
check("steam_app_ matches", gw.is_game("steam_app_480"), True)
check("bare steam_app_ matches", gw.is_game("steam_app_"), True)
check("RuneLite matches", gw.is_game("RuneLite"), True)
check("runelite matches", gw.is_game("runelite"), True)
check("runelite full id matches", gw.is_game("net-runelite-client-RuneLite"), True)
check("gamescope matches", gw.is_game("gamescope"), True)
check("Gamescope (case) matches", gw.is_game("Gamescope"), True)
check("Alacritty is not a game", gw.is_game("Alacritty"), False)
check("bolt-launcher excluded", gw.is_game("bolt-launcher"), False)
check("empty app_id is not a game", gw.is_game(""), False)
check("None app_id is not a game", gw.is_game(None), False)
# --- Watcher transitions ---------------------------------------------------
def drive(events):
calls = []
w = gw.Watcher(lambda action: calls.append(action))
for ev in events:
w.handle(ev)
return calls
def win(wid, app_id):
return {"WindowOpenedOrChanged": {"window": {"id": wid, "app_id": app_id}}}
def closed(wid):
return {"WindowClosed": {"id": wid}}
def snapshot(pairs):
return {"WindowsChanged": {"windows": [{"id": i, "app_id": a} for i, a in pairs]}}
check("empty snapshot: no calls", drive([snapshot([])]), [])
check("non-game window: no calls", drive([win(1, "Alacritty")]), [])
check("one game opens: add", drive([win(1, "steam_app_10")]), ["add"])
check(
"second game keeps active (single add)",
drive([win(1, "steam_app_10"), win(2, "RuneLite")]),
["add"],
)
check(
"close one of two: still active",
drive([win(1, "steam_app_10"), win(2, "RuneLite"), closed(2)]),
["add"],
)
check(
"close last game: add then del",
drive([win(1, "steam_app_10"), closed(1)]),
["add", "del"],
)
check(
"snapshot already containing a game: add (restart mid-game)",
drive([snapshot([(1, "Alacritty"), (5, "steam_app_9")])]),
["add"],
)
check(
"game window changes to non-game app_id: del",
drive([win(1, "steam_app_10"), win(1, "Alacritty")]),
["add", "del"],
)
check(
"repeated OpenedOrChanged for same game: single add",
drive([win(1, "gamescope"), win(1, "gamescope"), win(1, "gamescope")]),
["add"],
)
sys.exit(fails)