## 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": []})