import asyncio from engine.network.client import GameClient from engine.network.protocol import DEFAULT_PORT, decode_message, encode_message from engine.network.server import GameServer def run(coro): return asyncio.run(asyncio.wait_for(coro, timeout=5)) def test_default_port_is_42069(): assert DEFAULT_PORT == 42069 def test_encode_decode_round_trip(): message = {"type": "move", "entity_id": "p1", "x": 3, "y": 4} decoded = decode_message(encode_message(message).rstrip(b"\n")) assert decoded == message def test_two_clients_see_each_others_join_and_move(): async def scenario(): server = GameServer(host="127.0.0.1", port=0) await server.start() try: alice = GameClient("alice", "Alice", host="127.0.0.1", port=server.port) bob = GameClient("bob", "Bob", host="127.0.0.1", port=server.port) await alice.connect() await bob.connect() # bob's hello -> alice should see a "join" for bob join_event = await alice.receive() assert join_event == {"type": "join", "entity_id": "bob", "name": "Bob"} await bob.send_move("demo_world", 5, 5, 0) move_event = await alice.receive() assert move_event == {"type": "move", "entity_id": "bob", "map_id": "demo_world", "x": 5, "y": 5, "z": 0} await bob.close() leave_event = await alice.receive() assert leave_event == {"type": "leave", "entity_id": "bob"} await alice.close() finally: await server.stop() run(scenario()) def test_broadcast_excludes_the_sender(): async def scenario(): server = GameServer(host="127.0.0.1", port=0) await server.start() try: alice = GameClient("alice", "Alice", host="127.0.0.1", port=server.port) await alice.connect() await alice.send_move("demo_world", 1, 1, 0) # nothing else connected, so alice's own move should never be echoed back to her; # confirm by racing a short timeout against receive() try: await asyncio.wait_for(alice.receive(), timeout=0.2) assert False, "sender should not receive its own broadcast" except asyncio.TimeoutError: pass await alice.close() finally: await server.stop() run(scenario()) def test_server_reports_connected_clients(): async def scenario(): server = GameServer(host="127.0.0.1", port=0) await server.start() try: assert server.clients == {} alice = GameClient("alice", "Alice", host="127.0.0.1", port=server.port) await alice.connect() await asyncio.sleep(0.1) # let the server process the hello assert "alice" in server.clients await alice.close() finally: await server.stop() run(scenario())