feat(client): add E2E connection test and batch encoding tests

D-030 Layer 3: E2E test spawns the Rust server binary, connects via
LocalBridge, sends a batched MoveNorth input, and verifies the player
moved to (16.5, 15.5). Also adds batch encoding roundtrip tests,
framed batch test, and Player entity fixture decode test. 43/43 pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 21:44:27 +01:00
co-authored by Claude Opus 4.6
parent e1e4e346c7
commit 5e4b8dbcf3
3 changed files with 210 additions and 7 deletions
+89 -7
View File
@@ -42,33 +42,58 @@ func test_decode_snapshot_empty() -> void:
assert_that(snapshot.entities.size()).is_equal(0)
func test_decode_snapshot_player() -> void:
var bytes = _load_fixture("snapshot_player")
var snapshot = Protocol.decode_snapshot(bytes)
assert_that(snapshot).is_not_null()
assert_that(snapshot.tick).is_equal(1)
assert_that(snapshot.entities.size()).is_equal(1)
var player = snapshot.entities[0]
assert_that(player.entity_id).is_equal(100)
assert_float(player.x).is_equal_approx(16.5, 0.001)
assert_float(player.y).is_equal_approx(16.5, 0.001)
assert_that(player.z).is_equal(0)
assert_that(player.kind.variant).is_equal("Player")
assert_that(player.kind.data).is_null()
func test_decode_snapshot_multi_entity() -> void:
var bytes = _load_fixture("snapshot_multi_entity")
var snapshot = Protocol.decode_snapshot(bytes)
assert_that(snapshot).is_not_null()
assert_that(snapshot.tick).is_equal(999)
assert_that(snapshot.entities.size()).is_equal(3)
assert_that(snapshot.entities.size()).is_equal(4)
# Player at (16.5, 16.5, 0)
var player = snapshot.entities[0]
assert_that(player.entity_id).is_equal(1)
assert_float(player.x).is_equal_approx(16.5, 0.001)
assert_float(player.y).is_equal_approx(16.5, 0.001)
assert_that(player.z).is_equal(0)
assert_that(player.kind.variant).is_equal("Player")
# NPC at (5, 10, 0)
var npc = snapshot.entities[0]
assert_that(npc.entity_id).is_equal(1)
var npc = snapshot.entities[1]
assert_that(npc.entity_id).is_equal(2)
assert_float(npc.x).is_equal_approx(5.0, 0.001)
assert_float(npc.y).is_equal_approx(10.0, 0.001)
assert_that(npc.z).is_equal(0)
assert_that(npc.kind.variant).is_equal("Npc")
# Object at (15.5, 3, 1)
var obj = snapshot.entities[1]
assert_that(obj.entity_id).is_equal(2)
var obj = snapshot.entities[2]
assert_that(obj.entity_id).is_equal(3)
assert_float(obj.x).is_equal_approx(15.5, 0.001)
assert_float(obj.y).is_equal_approx(3.0, 0.001)
assert_that(obj.z).is_equal(1)
assert_that(obj.kind.variant).is_equal("Object")
# Terrain at (0, 0, -1)
var terrain = snapshot.entities[2]
assert_that(terrain.entity_id).is_equal(3)
var terrain = snapshot.entities[3]
assert_that(terrain.entity_id).is_equal(4)
assert_float(terrain.x).is_equal_approx(0.0, 0.001)
assert_float(terrain.y).is_equal_approx(0.0, 0.001)
assert_that(terrain.z).is_equal(-1)
@@ -169,6 +194,63 @@ func test_encode_produces_nonempty_bytes() -> void:
assert_that(bytes.size()).is_greater(0)
# -- Batch input encoding (Vec<PlayerInput> wire format) -----------------------
func test_encode_player_inputs_single() -> void:
var inputs: Array = [{"tick": 10, "action_name": "MoveNorth"}]
var bytes := Protocol.encode_player_inputs(inputs)
assert_that(bytes.size()).is_greater(0)
# Decode as raw msgpack — should be an array with one element
var raw: Variant = Messagepack.decode(bytes)
assert_that(raw.status).is_null()
assert_that(raw.value is Array).is_true()
assert_that(raw.value.size()).is_equal(1)
assert_that(raw.value[0]["tick"]).is_equal(10)
assert_that(raw.value[0]["action"]).is_equal("MoveNorth")
func test_encode_player_inputs_multiple() -> void:
var inputs: Array = [
{"tick": 1, "action_name": "MoveNorth"},
{"tick": 1, "action_name": "Interact"},
{"tick": 2, "action_name": "MoveSouthwest"},
]
var bytes := Protocol.encode_player_inputs(inputs)
assert_that(bytes.size()).is_greater(0)
var raw: Variant = Messagepack.decode(bytes)
assert_that(raw.status).is_null()
assert_that(raw.value.size()).is_equal(3)
assert_that(raw.value[0]["action"]).is_equal("MoveNorth")
assert_that(raw.value[1]["action"]).is_equal("Interact")
assert_that(raw.value[2]["action"]).is_equal("MoveSouthwest")
func test_encode_player_inputs_with_data_variant() -> void:
var inputs: Array = [
{"tick": 5, "action_name": "UsePerceptionMode", "action_data": "thermal"},
]
var bytes := Protocol.encode_player_inputs(inputs)
assert_that(bytes.size()).is_greater(0)
var raw: Variant = Messagepack.decode(bytes)
assert_that(raw.status).is_null()
assert_that(raw.value[0]["action"] is Dictionary).is_true()
assert_that(raw.value[0]["action"]["UsePerceptionMode"]).is_equal("thermal")
func test_encode_player_inputs_empty() -> void:
var inputs: Array = []
var bytes := Protocol.encode_player_inputs(inputs)
assert_that(bytes.size()).is_greater(0)
var raw: Variant = Messagepack.decode(bytes)
assert_that(raw.status).is_null()
assert_that(raw.value is Array).is_true()
assert_that(raw.value.size()).is_equal(0)
# -- Diagonal movement fixtures (D-030 Layer 1 cross-language) -----------------
func test_decode_diagonal_fixtures() -> void: