harness.pyΒΆ
Part of Q1K3.
1"""Smoke harness for Q1K3: starts the game from the menu and drives the player.
2
3Runs headless through ``SceneRunner``, and clicks / types through
4``InputSimulator`` rather than poking node state, so the real input path is the
5thing under test.
6"""
7
8from __future__ import annotations
9
10import sys
11from pathlib import Path
12
13_PORT_DIR = Path(__file__).parent
14if str(_PORT_DIR) not in sys.path:
15 sys.path.insert(0, str(_PORT_DIR))
16
17from nodes.root import Q1K3Root # noqa: E402
18
19from simvx.core import Button, Key # noqa: E402
20from simvx.core.testing import InputSimulator, SceneRunner # noqa: E402
21
22
23def _first_button(node) -> Button | None:
24 if isinstance(node, Button):
25 return node
26 for child in node.children:
27 found = _first_button(child)
28 if found is not None:
29 return found
30 return None
31
32
33def main() -> int:
34 runner = SceneRunner(screen_size=(1280, 720))
35 runner.load(Q1K3Root())
36 sim = InputSimulator(runner.tree)
37 runner.advance_frames(2)
38
39 root = runner.root
40 assert isinstance(root, Q1K3Root)
41 if not runner.tree.paused or not root.menu.visible:
42 print("FAIL: the title screen should be up and the tree paused at boot")
43 return 1
44
45 play = _first_button(root.menu)
46 if play is None:
47 print("FAIL: no start button on the title screen")
48 return 1
49 x, y, w, h = play.get_global_rect()
50 sim.click((x + w / 2, y + h / 2))
51 runner.advance_frames(2)
52
53 if runner.tree.paused or root.player is None:
54 print("FAIL: the start button did not start the game")
55 return 1
56
57 start = root.player.p
58 sim.press_key(Key.W)
59 runner.advance_frames(30)
60 sim.release_key(Key.W)
61 if (root.player.p - start).length() < 1.0:
62 print("FAIL: holding forward did not move the player")
63 return 1
64
65 sim.tap_key(Key.ESCAPE)
66 runner.advance_frames(2)
67 if not runner.tree.paused or not root.menu.visible:
68 print("FAIL: Escape did not return to the title screen")
69 return 1
70
71 print(f"OK: started from the menu; player at {root.player.p}; entities={len(root._entities)}")
72 return 0
73
74
75if __name__ == "__main__":
76 sys.exit(main())