## GameState.apply_snapshot() tests — v2+ field coverage. ## ## Complements test_snapshot_parsing.gd (which covers v1 basics: tick, entities, ## player_position). This file covers v2+ fields and derived state. ## ## D-030: fixture-based, server-free, no subprocess required. class_name TestGameState extends GdUnitTestSuite func before_each() -> void: # Reset fields touched by these tests to known defaults. GameState.current_tick = 0 GameState.player_position = Vector2.ZERO GameState.player_facing = "North" GameState.game_time = {} GameState.nearby_interactions = [] GameState.current_monologue = null GameState.player_stance = "Walk" GameState.player_inventory = [] GameState.stationary_ticks = 0 GameState.insert_active = true # -- v2: game_time (D-031) ------------------------------------------------- func test_apply_snapshot_sets_game_time() -> void: var snapshot := { "tick": 10, "entities": [], "game_time": {"day": 3, "time_of_day": 480, "day_phase": "Morning", "tick_rate": 1}, } GameState.apply_snapshot(snapshot) assert_that(GameState.game_time).is_not_null() assert_that(GameState.game_time.get("day")).is_equal(3) assert_that(GameState.game_time.get("time_of_day")).is_equal(480) func test_apply_snapshot_game_time_missing_keeps_previous() -> void: GameState.game_time = {"day": 2, "time_of_day": 360} GameState.apply_snapshot({"tick": 5, "entities": []}) # No "game_time" key → field unchanged assert_that(GameState.game_time.get("day")).is_equal(2) # -- v2: player_facing (D-015) -------------------------------------------- func test_apply_snapshot_sets_player_facing() -> void: var snapshot := { "tick": 1, "entities": [], "player_facing": "Southeast", } GameState.apply_snapshot(snapshot) assert_that(GameState.player_facing).is_equal("Southeast") func test_apply_snapshot_player_facing_missing_keeps_default() -> void: GameState.player_facing = "West" GameState.apply_snapshot({"tick": 1, "entities": []}) assert_that(GameState.player_facing).is_equal("West") # -- v4: nearby_interactions (#404/#405) ---------------------------------- func test_apply_snapshot_sets_nearby_interactions() -> void: var interactions := [ {"entity_id": 5, "entity_type": "Npc", "distance": 1.2, "verbs": [{"kind": "Talk", "label": "Talk", "priority": 1, "available": true}]}, ] GameState.apply_snapshot({"tick": 1, "entities": [], "nearby_interactions": interactions}) assert_that(GameState.nearby_interactions.size()).is_equal(1) assert_that(GameState.nearby_interactions[0].get("entity_id")).is_equal(5) func test_apply_snapshot_nearby_interactions_absent_clears_list() -> void: GameState.nearby_interactions = [{"entity_id": 1}] GameState.apply_snapshot({"tick": 2, "entities": []}) assert_that(GameState.nearby_interactions.size()).is_equal(0) # -- v5: current_monologue (#414) ----------------------------------------- func test_apply_snapshot_sets_monologue() -> void: var monologue := {"id": "m1", "text": "Something is off here.", "duration_seconds": 4.0, "priority": 1, "is_urgent": false} GameState.apply_snapshot({"tick": 1, "entities": [], "current_monologue": monologue}) assert_that(GameState.current_monologue).is_not_null() assert_that(GameState.current_monologue.get("text")).is_equal("Something is off here.") func test_apply_snapshot_monologue_absent_clears_field() -> void: GameState.current_monologue = {"id": "old", "text": "Old line."} GameState.apply_snapshot({"tick": 2, "entities": []}) assert_that(GameState.current_monologue).is_null() # -- v6: player_stance (#449, D-053) -------------------------------------- func test_apply_snapshot_sets_player_stance() -> void: GameState.apply_snapshot({"tick": 1, "entities": [], "player_stance": "Crouch"}) assert_that(GameState.player_stance).is_equal("Crouch") # -- v6: player_inventory (#449, D-065) ----------------------------------- func test_apply_snapshot_sets_player_inventory() -> void: var inventory := [{"item_id": 42, "name": "Security pass", "slot": 0}] GameState.apply_snapshot({"tick": 1, "entities": [], "player_inventory": inventory}) assert_that(GameState.player_inventory.size()).is_equal(1) assert_that(GameState.player_inventory[0].get("name")).is_equal("Security pass") func test_apply_snapshot_inventory_absent_clears_list() -> void: GameState.player_inventory = [{"item_id": 1}] GameState.apply_snapshot({"tick": 2, "entities": []}) assert_that(GameState.player_inventory.size()).is_equal(0) # -- Stationary tick counter (D-071) ------------------------------------- func test_stationary_ticks_increments_when_player_position_unchanged() -> void: var snapshot := { "tick": 1, "entities": [{"entity_id": 1, "x": 10.0, "y": 10.0, "z": 0, "kind": {"variant": "Player", "data": null}}], } GameState.apply_snapshot(snapshot) # first call: position changes from ZERO GameState.apply_snapshot(snapshot) # second call: position unchanged → +1 assert_int(GameState.stationary_ticks).is_greater(0) func test_stationary_ticks_resets_on_player_movement() -> void: var s1 := { "tick": 1, "entities": [{"entity_id": 1, "x": 10.0, "y": 10.0, "z": 0, "kind": {"variant": "Player", "data": null}}], } var s2 := { "tick": 2, "entities": [{"entity_id": 1, "x": 11.0, "y": 10.0, "z": 0, "kind": {"variant": "Player", "data": null}}], } GameState.apply_snapshot(s1) GameState.apply_snapshot(s1) # stationary assert_int(GameState.stationary_ticks).is_greater(0) GameState.apply_snapshot(s2) # moved → reset assert_int(GameState.stationary_ticks).is_equal(0) # -- insert_active (OQ-07, #522) ----------------------------------------- func test_apply_snapshot_insert_active_false() -> void: GameState.apply_snapshot({"tick": 1, "entities": [], "insert_active": false}) assert_bool(GameState.insert_active).is_false() func test_apply_snapshot_insert_active_defaults_true_when_absent() -> void: GameState.insert_active = false GameState.apply_snapshot({"tick": 2, "entities": []}) assert_bool(GameState.insert_active).is_true()