import socket import pytest from packet_codec import MAX_MESSAGE_BYTES, encode_packet from tcp_transport import LineMessageBuffer, TcpFramingError, frame_message, send_message def test_tcp_framing_adds_delimiter_only_at_transport_boundary(): encoded = encode_packet({"type": "playerState", "characterName": "Nomad"}) assert not encoded.payload.endswith(b"\n") framed = frame_message(encoded.payload) assert framed == encoded.payload + b"\n" def test_line_buffer_preserves_fragmented_and_coalesced_messages(): buffer = LineMessageBuffer() assert buffer.feed(b'{"type":"first"') == [] messages = buffer.feed(b'}\n{"type":"second"}\n{"type":"third"') assert messages == [b'{"type":"first"}', b'{"type":"second"}'] assert buffer.buffered_bytes > 0 assert buffer.feed(b'}\r\n') == [b'{"type":"third"}'] assert buffer.buffered_bytes == 0 def test_line_buffer_rejects_oversize_unterminated_and_terminated_messages(): with pytest.raises(TcpFramingError): LineMessageBuffer().feed(b"x" * (MAX_MESSAGE_BYTES + 1)) with pytest.raises(TcpFramingError): LineMessageBuffer().feed((b"x" * (MAX_MESSAGE_BYTES + 1)) + b"\n") def test_frame_rejects_raw_delimiters_and_oversize_payloads(): with pytest.raises(TcpFramingError): frame_message(b"bad\nmessage") with pytest.raises(TcpFramingError): frame_message(b"bad\rmessage") with pytest.raises(TcpFramingError): frame_message(b"x" * (MAX_MESSAGE_BYTES + 1)) def test_send_message_preserves_existing_tcp_wire_format(): reader, writer = socket.socketpair() try: payload = encode_packet({"type": "keepAlive"}).payload send_message(writer, payload) assert reader.recv(4096) == payload + b"\n" finally: reader.close() writer.close()