New SnapshotEventRouter class (46 lines) provides callable-based snapshot dispatch via register(), register_always(), and dispatch(). main.gd _process() now calls _router.dispatch(snapshot) instead of 15+ inline if-has blocks. Handlers registered in _ready(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
90 lines
3.3 KiB
GDScript
90 lines
3.3 KiB
GDScript
## SnapshotEventRouter unit tests (#559).
|
|
## Verifies callable-based dispatch: keyed handlers receive correct field values,
|
|
## always handlers run on every dispatch, absent fields don't trigger handlers.
|
|
##
|
|
## D-030: fixture-based, server-free, no subprocess required.
|
|
class_name TestSnapshotEventRouter
|
|
extends GdUnitTestSuite
|
|
|
|
|
|
# -- Keyed handlers -----------------------------------------------------------
|
|
|
|
func test_keyed_handler_called_when_field_present() -> void:
|
|
var router := SnapshotEventRouter.new()
|
|
var received: Array = []
|
|
router.register("current_monologue", func(): received.append("monologue"))
|
|
router.dispatch({"current_monologue": {"text": "Test."}})
|
|
assert_that(received.size()).is_equal(1)
|
|
assert_that(received[0]).is_equal("monologue")
|
|
|
|
|
|
func test_keyed_handler_not_called_when_field_absent() -> void:
|
|
var router := SnapshotEventRouter.new()
|
|
var received: Array = []
|
|
router.register("current_monologue", func(): received.append("monologue"))
|
|
router.dispatch({"tick": 1})
|
|
assert_that(received.size()).is_equal(0)
|
|
|
|
|
|
func test_multiple_keyed_handlers_same_field() -> void:
|
|
## Multiple handlers on the same key run in registration order.
|
|
var router := SnapshotEventRouter.new()
|
|
var order: Array = []
|
|
router.register("save_result", func(): order.append("first"))
|
|
router.register("save_result", func(): order.append("second"))
|
|
router.dispatch({"save_result": {"success": true}})
|
|
assert_that(order).is_equal(["first", "second"])
|
|
|
|
|
|
func test_keyed_handlers_multiple_fields() -> void:
|
|
## Each keyed handler fires only for its registered field.
|
|
var router := SnapshotEventRouter.new()
|
|
var received: Array = []
|
|
router.register("current_monologue", func(): received.append("mono"))
|
|
router.register("current_dialogue", func(): received.append("dlg"))
|
|
router.dispatch({"current_monologue": {"text": "Hi."}})
|
|
assert_that(received).is_equal(["mono"])
|
|
received.clear()
|
|
router.dispatch({"current_dialogue": {"speech": "Hello."}, "current_monologue": {"text": "Hmm."}})
|
|
assert_bool(received.has("mono")).is_true()
|
|
assert_bool(received.has("dlg")).is_true()
|
|
|
|
|
|
# -- Always handlers ----------------------------------------------------------
|
|
|
|
func test_always_handler_called_on_every_dispatch() -> void:
|
|
var router := SnapshotEventRouter.new()
|
|
var count: Array[int] = [0]
|
|
router.register_always(func(): count[0] += 1)
|
|
router.dispatch({"tick": 1})
|
|
router.dispatch({"tick": 2})
|
|
router.dispatch({})
|
|
assert_int(count[0]).is_equal(3)
|
|
|
|
|
|
func test_always_handler_runs_before_keyed() -> void:
|
|
## Always handlers run before keyed handlers (dispatch order guarantee).
|
|
var router := SnapshotEventRouter.new()
|
|
var order: Array = []
|
|
router.register("current_monologue", func(): order.append("keyed"))
|
|
router.register_always(func(): order.append("always"))
|
|
router.dispatch({"current_monologue": {"text": "Hi."}})
|
|
assert_that(order[0]).is_equal("always")
|
|
assert_that(order[1]).is_equal("keyed")
|
|
|
|
|
|
# -- Empty dispatch ------------------------------------------------------------
|
|
|
|
func test_empty_snapshot_no_crash() -> void:
|
|
var router := SnapshotEventRouter.new()
|
|
router.register("foo", func(): pass)
|
|
router.register_always(func(): pass)
|
|
# Must not crash
|
|
router.dispatch({})
|
|
|
|
|
|
func test_no_handlers_no_crash() -> void:
|
|
var router := SnapshotEventRouter.new()
|
|
# Must not crash
|
|
router.dispatch({"tick": 1, "entities": []})
|