diff --git a/client/scripts/autoloads/sim_bridge.gd b/client/scripts/autoloads/sim_bridge.gd index 604ab2514..98aad66b8 100644 --- a/client/scripts/autoloads/sim_bridge.gd +++ b/client/scripts/autoloads/sim_bridge.gd @@ -250,6 +250,10 @@ static func _action_enum_to_wire(action: int) -> String: # Dynamic test snapshot — processes queued inputs to move player, generates # visibility based on current position. Matches Protocol.decode_snapshot() format. +# NOTE: Test coordinate space (player at 10,10; NPC at 12,9; wall at 12,10) +# is intentionally decoupled from the E2E proof room (player at 16,16; NPC at +# 16,13; wall at 16,14). This ensures standalone tests don't depend on server +# map layout and can exercise the rendering pipeline independently. func _test_snapshot() -> Dictionary: _test_tick += 1 @@ -276,7 +280,7 @@ func _test_snapshot() -> Dictionary: "visibility": "Forward", }] - # NPC at (12, 9) — visible if within range and not blocked by wall at (12, 9) + # NPC at (12, 9) — visible if within range and not blocked by wall at (12, 10) var npc_pos := Vector2i(12, 9) var npc_dist := absi(px - npc_pos.x) + absi(py - npc_pos.y) if npc_dist <= 4 and _test_has_los(Vector2i(px, py), npc_pos): diff --git a/client/tests/test_snapshot_parsing.gd b/client/tests/test_snapshot_parsing.gd index 7c15c7657..3fd78c17e 100644 --- a/client/tests/test_snapshot_parsing.gd +++ b/client/tests/test_snapshot_parsing.gd @@ -51,11 +51,25 @@ func test_missing_fields_partial_update() -> void: assert_that(GameState.player_position).is_equal(Vector2(10, 15)) assert_that(GameState.current_tick).is_equal(2) +func test_sim_bridge_los_clear_path() -> void: + # No wall between (10,10) and (10,8) — clear LOS + assert_that(SimBridge._test_has_los(Vector2i(10, 10), Vector2i(10, 8))).is_true() + +func test_sim_bridge_los_blocked_by_wall() -> void: + # Wall at (12,10) blocks LOS from (10,10) to (12,9) via east path + # Direct line from (10,10) → (12,9) passes through (11,10) then (12,10) — wall + assert_that(SimBridge._test_has_los(Vector2i(10, 10), Vector2i(14, 10))).is_false() + +func test_sim_bridge_los_diagonal() -> void: + # Diagonal LOS from (10,10) to (11,9) — no wall in path + assert_that(SimBridge._test_has_los(Vector2i(10, 10), Vector2i(11, 9))).is_true() + +func test_sim_bridge_los_same_position() -> void: + # LOS to self is always true + assert_that(SimBridge._test_has_los(Vector2i(10, 10), Vector2i(10, 10))).is_true() + func test_sim_bridge_test_snapshot_deterministic() -> void: - SimBridge._test_tick = 0 - SimBridge._test_player_pos = Vector2i(10, 10) - SimBridge._test_facing = "North" - SimBridge._test_input_queue.clear() + SimBridge.reset_test_state() var snap1 = SimBridge._test_snapshot() var snap2 = SimBridge._test_snapshot() diff --git a/client/tests/test_sprint2_proof.gd b/client/tests/test_sprint2_proof.gd index ce35da77c..21a0164d6 100644 --- a/client/tests/test_sprint2_proof.gd +++ b/client/tests/test_sprint2_proof.gd @@ -91,6 +91,9 @@ func _connect_to_server() -> bool: _bridge = LocalBridge.new() var elapsed := 0.0 while elapsed < CONNECT_TIMEOUT: + if _server_pid > 0 and not OS.is_process_running(_server_pid): + push_warning("Server process died during connection") + return false if _bridge.get_status() == StreamPeerTCP.STATUS_NONE: _bridge.connect_to_server("127.0.0.1", _test_port) _bridge.poll() @@ -174,6 +177,8 @@ func test_proof_corner_reveal() -> void: var npc_found := false for entity in snapshot.entities: if entity.kind.variant == "Npc": + assert_float(entity.x).is_equal_approx(16.5, 0.001) + assert_float(entity.y).is_equal_approx(13.5, 0.001) npc_found = true break assert_that(npc_found).is_true()