diff --git a/server/tests/test_packet_codec.py b/server/tests/test_packet_codec.py new file mode 100644 index 0000000..f3202e1 --- /dev/null +++ b/server/tests/test_packet_codec.py @@ -0,0 +1,48 @@ +import json + +import pytest + +from packet_codec import MAX_MESSAGE_BYTES, PacketCodecError, decode_packet, encode_packet +from transport_policy import Delivery + + +def test_encoded_packet_has_no_tcp_line_framing(): + encoded = encode_packet({"type": "transform", "x": 1.0}) + assert encoded.packet_type == "transform" + assert encoded.delivery is Delivery.UNRELIABLE_SEQUENCED + assert encoded.payload == b'{"type":"transform","x":1.0}' + assert not encoded.payload.endswith(b"\n") + + +def test_reliable_packet_carries_delivery_policy_separately_from_json(): + encoded = encode_packet({"type": "playerState", "characterName": "Nomad"}) + assert encoded.delivery is Delivery.RELIABLE_ORDERED + assert json.loads(encoded.payload) == {"type": "playerState", "characterName": "Nomad"} + + +def test_decode_packet_accepts_one_complete_message_without_delimiter(): + assert decode_packet(b'{"type":"sessionReady","playerId":7}') == { + "type": "sessionReady", + "playerId": 7, + } + + +def test_codec_rejects_nonfinite_invalid_utf8_nonobject_and_missing_type(): + with pytest.raises(PacketCodecError): + encode_packet({"type": "transform", "x": float("nan")}) + with pytest.raises(PacketCodecError): + decode_packet(b'{"type":"transform","x":NaN}') + with pytest.raises(PacketCodecError): + decode_packet(b"\xff") + with pytest.raises(PacketCodecError): + decode_packet(b"[]") + with pytest.raises(PacketCodecError): + decode_packet(b"{}") + + +def test_codec_enforces_64k_message_limit_before_transport(): + payload = "x" * MAX_MESSAGE_BYTES + with pytest.raises(PacketCodecError): + encode_packet({"type": "playerState", "characterName": payload}) + with pytest.raises(PacketCodecError): + decode_packet(b"x" * (MAX_MESSAGE_BYTES + 1))