#!/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)