extends GutTest ## The input packet is the only thing a client can put on the wire, so its ## bounds are a security surface as much as a format. func _round_trip(f: InputFrame) -> InputFrame: var b := StreamPeerBuffer.new() b.big_endian = false f.write(b) b.seek(0) return InputFrame.read(b) func test_round_trip_preserves_tick_and_buttons() -> void: var f := InputFrame.make(123456, Vector2(0.5, -0.25), 1.75, InputFrame.BTN_FIRE | InputFrame.BTN_ESCAPE) var out := _round_trip(f) assert_eq(out.tick, 123456) assert_true(out.pressed(InputFrame.BTN_FIRE)) assert_true(out.pressed(InputFrame.BTN_ESCAPE)) assert_false(out.pressed(InputFrame.BTN_INTERACT)) func test_move_survives_quantisation_within_tolerance() -> void: var out := _round_trip(InputFrame.make(1, Vector2(0.5, -0.25), 0.0, 0)) assert_almost_eq(out.move.x, 0.5, 0.01) assert_almost_eq(out.move.y, -0.25, 0.01) func test_aim_survives_quantisation() -> void: var out := _round_trip(InputFrame.make(1, Vector2.ZERO, 2.5, 0)) assert_almost_eq(out.aim, 2.5, 0.001) func test_oversized_move_cannot_be_expressed_on_the_wire() -> void: var out := _round_trip(InputFrame.make(1, Vector2(50.0, 50.0), 0.0, 0)) assert_lt(out.move.length(), 1.45, "the byte encoding must cap the move vector") func test_frame_is_exactly_the_declared_size() -> void: var b := StreamPeerBuffer.new() InputFrame.make(1, Vector2.ONE, 1.0, 7).write(b) assert_eq(b.data_array.size(), InputFrame.SIZE) ## The slot is what makes "use item" expressible without a second message type. func test_round_trip_preserves_the_inventory_slot() -> void: var out := _round_trip(InputFrame.make(1, Vector2.ZERO, 0.0, InputFrame.BTN_USE, SimConfig.INVENTORY_SLOTS - 1)) assert_eq(out.slot, SimConfig.INVENTORY_SLOTS - 1) assert_true(out.pressed(InputFrame.BTN_USE)) assert_false(out.pressed(InputFrame.BTN_DROP)) ## Every slot the game has must survive the byte it is sent in. This is the ## check that fails if the slot count ever outgrows the format. func test_every_slot_index_survives_the_wire() -> void: for i in SimConfig.INVENTORY_SLOTS: assert_eq(_round_trip(InputFrame.make(1, Vector2.ZERO, 0.0, 0, i)).slot, i) assert_lte(SimConfig.INVENTORY_SLOTS, 256, "the slot rides in one byte") ## Button bits have to stay distinct, or one action would trigger another. func test_button_bits_do_not_overlap() -> void: var bits := [InputFrame.BTN_FIRE, InputFrame.BTN_ESCAPE, InputFrame.BTN_INTERACT, InputFrame.BTN_USE, InputFrame.BTN_DROP] var seen := 0 for bit in bits: assert_eq(seen & bit, 0, "bit %d collides with an earlier one" % bit) assert_lte(bit, 128, "the button field is a single byte") seen |= bit