Write the eight-beat tutorial sheet, its safe visitor script, persistence and replay rules. Add a deterministic, skippable/restartable Tutorial RefCounted state machine with headless tests. UI/GameManager wiring remains the next task. Headless 235/235, Python 94/94.
50 lines
2.4 KiB
GDScript
50 lines
2.4 KiB
GDScript
extends RefCounted
|
|
## Deterministic headless tests for the first-shift tutorial state machine.
|
|
|
|
const Tutorial := preload("res://src/game/tutorial.gd")
|
|
|
|
func test_tutorial_advances_only_on_the_expected_action() -> bool:
|
|
var tutorial := Tutorial.new()
|
|
tutorial.start()
|
|
var a := TestUtils.check(tutorial.current()["id"] == "arrive", "starts at arrival")
|
|
var b := TestUtils.check(not tutorial.advance("wheel_opened"), "wrong action is ignored")
|
|
var c := TestUtils.check(tutorial.advance("moved"), "movement advances")
|
|
var d := TestUtils.check(tutorial.current()["id"] == "focus", "moves to focus")
|
|
var e := TestUtils.check(tutorial.advance("cycled"), "target cycling advances")
|
|
var f := TestUtils.check(tutorial.current()["id"] == "wheel", "moves to the action wheel")
|
|
return a and b and c and d and e and f
|
|
|
|
func test_tutorial_runs_all_beats_and_completes() -> bool:
|
|
var tutorial := Tutorial.new()
|
|
tutorial.start()
|
|
var events := ["moved", "cycled", "wheel_opened", "inspected",
|
|
"polite_direction", "formal_warning", "radio_submitted", "review_opened"]
|
|
var ok := true
|
|
for event in events:
|
|
ok = ok and tutorial.advance(event)
|
|
ok = ok and tutorial.is_complete()
|
|
ok = ok and not tutorial.is_skipped()
|
|
ok = ok and tutorial.progress() == Vector2i(Tutorial.BEATS.size(), Tutorial.BEATS.size())
|
|
return TestUtils.check(ok, "all eight beats complete in order")
|
|
|
|
func test_tutorial_accepts_body_camera_for_warning() -> bool:
|
|
var tutorial := Tutorial.new()
|
|
tutorial.start()
|
|
for event in ["moved", "cycled", "wheel_opened", "inspected", "polite_direction"]:
|
|
tutorial.advance(event)
|
|
var a := TestUtils.check(tutorial.advance("body_camera"), "body camera satisfies warning")
|
|
var b := TestUtils.check(tutorial.current()["id"] == "radio", "advances to radio")
|
|
return a and b
|
|
|
|
func test_tutorial_skip_and_restart() -> bool:
|
|
var tutorial := Tutorial.new()
|
|
tutorial.start()
|
|
var a := TestUtils.check(tutorial.advance("moved"), "one beat completed")
|
|
tutorial.skip()
|
|
var b := TestUtils.check(tutorial.is_complete() and tutorial.is_skipped(), "skip completes tutorial")
|
|
var c := TestUtils.check(not tutorial.advance("moved"), "completed tutorial is inert")
|
|
tutorial.restart()
|
|
var d := TestUtils.check(not tutorial.is_complete() and not tutorial.is_skipped(), "restart clears flags")
|
|
var e := TestUtils.check(tutorial.current()["id"] == "arrive", "restart returns to beat one")
|
|
return a and b and c and d and e
|