""" Tests for engine.display.backends.websocket module. """ from unittest.mock import MagicMock, patch import pytest from engine.display.backends.websocket import WebSocketDisplay class TestWebSocketDisplayImport: """Test that websocket module can be imported.""" def test_import_does_not_error(self): """Module imports without error.""" from engine.display import backends assert backends is not None class TestWebSocketDisplayInit: """Tests for WebSocketDisplay initialization.""" def test_default_init(self): """Default initialization sets correct defaults.""" with patch("engine.display.backends.websocket.websockets", None): display = WebSocketDisplay() assert display.host == "0.0.0.0" assert display.port == 8765 assert display.http_port == 8766 assert display.width == 80 assert display.height == 24 def test_custom_init(self): """Custom initialization uses provided values.""" with patch("engine.display.backends.websocket.websockets", None): display = WebSocketDisplay(host="localhost", port=9000, http_port=9001) assert display.host == "localhost" assert display.port == 9000 assert display.http_port == 9001 def test_is_available_when_websockets_present(self): """is_available returns True when websockets is available.""" pytest.importorskip("websockets") display = WebSocketDisplay() assert display.is_available() is True @pytest.mark.skipif( pytest.importorskip("websockets") is not None, reason="websockets is available" ) def test_is_available_when_websockets_missing(self): """is_available returns False when websockets is not available.""" display = WebSocketDisplay() assert display.is_available() is False class TestWebSocketDisplayProtocol: """Test that WebSocketDisplay satisfies Display protocol.""" def test_websocket_display_is_display(self): """WebSocketDisplay satisfies Display protocol.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() assert hasattr(display, "init") assert hasattr(display, "show") assert hasattr(display, "clear") assert hasattr(display, "cleanup") class TestWebSocketDisplayMethods: """Tests for WebSocketDisplay methods.""" def test_init_stores_dimensions(self): """init stores terminal dimensions.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() display.init(100, 40) assert display.width == 100 assert display.height == 40 @pytest.mark.skip(reason="port binding conflict in CI environment") def test_client_count_initially_zero(self): """client_count returns 0 when no clients connected.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() assert display.client_count() == 0 def test_get_ws_port(self): """get_ws_port returns configured port.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay(port=9000) assert display.get_ws_port() == 9000 def test_get_http_port(self): """get_http_port returns configured port.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay(http_port=9001) assert display.get_http_port() == 9001 def test_frame_delay_defaults_to_zero(self): """get_frame_delay returns 0 by default.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() assert display.get_frame_delay() == 0.0 def test_set_frame_delay(self): """set_frame_delay stores the value.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() display.set_frame_delay(0.05) assert display.get_frame_delay() == 0.05 class TestWebSocketDisplayCallbacks: """Tests for WebSocketDisplay callback methods.""" def test_set_client_connected_callback(self): """set_client_connected_callback stores callback.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() callback = MagicMock() display.set_client_connected_callback(callback) assert display._client_connected_callback is callback def test_set_client_disconnected_callback(self): """set_client_disconnected_callback stores callback.""" with patch("engine.display.backends.websocket.websockets", MagicMock()): display = WebSocketDisplay() callback = MagicMock() display.set_client_disconnected_callback(callback) assert display._client_disconnected_callback is callback class TestWebSocketDisplayUnavailable: """Tests when WebSocket support is unavailable.""" @pytest.mark.skipif( pytest.importorskip("websockets") is not None, reason="websockets is available" ) def test_start_server_noop_when_unavailable(self): """start_server does nothing when websockets unavailable.""" display = WebSocketDisplay() display.start_server() assert display._server_thread is None @pytest.mark.skipif( pytest.importorskip("websockets") is not None, reason="websockets is available" ) def test_start_http_server_noop_when_unavailable(self): """start_http_server does nothing when websockets unavailable.""" display = WebSocketDisplay() display.start_http_server() assert display._http_thread is None @pytest.mark.skipif( pytest.importorskip("websockets") is not None, reason="websockets is available" ) def test_show_noops_when_unavailable(self): """show does nothing when websockets unavailable.""" display = WebSocketDisplay() display.show(["line1", "line2"])