Files
cthulhu/tests/steam_big_picture_log.py

95 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Check a fresh, physical arrows-first Steam Big Picture run of Cthulhu."""
import argparse
import json
from pathlib import Path
def check_log(path: Path) -> None:
records = [json.loads(line) for line in path.read_text().splitlines() if line.strip()]
starts = [index for index, record in enumerate(records)
if record.get("message") == "starting Cthulhu"]
if not starts:
raise ValueError("no Cthulhu startup in log")
records = records[starts[-1]:]
steam_pid = None
steam_document = False
first_link = None
first_caret = None
tab_focus = False
home = power = confirm = cancel = False
links_before_arrow = set()
for record in records:
message = record.get("message")
if message == "X11 foreground ownership changed":
pid = record.get("pid") or 0
if first_link is not None and pid and pid != steam_pid and not cancel:
raise ValueError("foreground left Steam before the dialog check finished")
if first_link is None and pid:
steam_pid = pid
continue
if message == "suspended for XTerm focus handoff" and first_link is not None and not cancel:
raise ValueError("focus switched away from Steam before the dialog check finished")
if (message == "delivering accessible presentation" and
record.get("role") == "document web" and
record.get("utterance", "").startswith("Steam Big Picture Mode")):
steam_document = True
if message == "document caret navigation completed" and record.get("moved") is True:
if first_link is not None and first_caret is None:
first_caret = record.get("time")
continue
if message != "delivering accessible presentation" or record.get("cause") != "object:state-changed:focused":
continue
role = record.get("role")
utterance = record.get("utterance", "")
if role == "link" and utterance and steam_document:
if first_link is None:
first_link = record.get("time")
links_before_arrow.add(utterance)
elif first_caret is None:
links_before_arrow.add(utterance)
else:
tab_focus = True
if first_caret is None:
continue
if role == "menu item" and utterance == "Home, menu item":
home = True
elif role == "menu item" and utterance == "Power, menu item":
power = home
elif role == "button" and utterance == "Confirm, button":
confirm = power
elif role == "button" and utterance == "Cancel, button":
cancel = confirm
if cancel:
break
if not steam_document or first_link is None:
raise ValueError("Steam never exposed its document and an initial focused link")
if len(links_before_arrow) != 1:
raise ValueError("focus moved between links before the first browse arrow; test arrows first")
if first_caret is None:
raise ValueError("no successful browse arrow after Steam became ready")
if not tab_focus:
raise ValueError("no focused link after the first arrow and Tab")
if not home or not power:
raise ValueError("Escape did not expose Home and Power")
if not confirm or not cancel:
raise ValueError("Power did not expose both Confirm and Cancel buttons")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("log", type=Path, help="fresh Cthulhu debug log")
arguments = parser.parse_args()
try:
check_log(arguments.log)
except (OSError, ValueError, json.JSONDecodeError) as error:
parser.exit(1, f"Steam Big Picture check failed: {error}\n")
print("Steam Big Picture arrows-first focus, menu, and dialog check passed")
if __name__ == "__main__":
main()