import pytest import asyncio import struct from openttd.protocol import OpenTTDProtocol, PacketGameType from openttd.client import OpenTTDClient class MockTransport: def __init__(self): self._closing = False def is_closing(self): return self._closing def close(self): self._closing = True def write(self, data): return len(data) class MockProtocol: async def send_packet(self, data): raise Exception("Send failed") @pytest.mark.asyncio async def test_client_connect_exception(monkeypatch): # Coverage for client.py:51-53 client = OpenTTDClient(host="127.0.0.1") async def mock_fail(*args, **kwargs): raise Exception("Async Failure") monkeypatch.setattr(asyncio.get_running_loop(), "create_connection", mock_fail) with pytest.raises(Exception, match="Async Failure"): await client.connect() @pytest.mark.asyncio async def test_client_quit_exception(): # Coverage for client.py:76 client = OpenTTDClient(host="127.0.0.1") client._transport = MockTransport() client._protocol = MockProtocol() # send_packet raises await client.quit() # Should hit the except: pass @pytest.mark.asyncio async def test_client_no_company_password(): # Coverage for client.py:126-127 client = OpenTTDClient(host="127.0.0.1") # _company_password is empty by default await client.receive_ServerNeedCompanyPassword(None, 0, "srv") # Should log error and return @pytest.mark.asyncio async def test_client_chat_no_callback(): # Coverage for client.py:162 client = OpenTTDClient(host="127.0.0.1") # on_chat is None await client.receive_ServerChat(None, 1, "Hello") @pytest.mark.asyncio async def test_protocol_receive_exception(): # Coverage for protocol.py:74-75 # Trigger exception in receive_packet loop class BadHandler: encryption_enabled = False proto = OpenTTDProtocol(BadHandler()) # data too short for read_uint16 res = proto.receive_packet(None, memoryview(b"\x01")) assert res == (PacketGameType.ServerUnused, {}) def test_protocol_welcome_parser(): # Coverage for protocol.py:110-112 data = memoryview(struct.pack("