""" Tests for engine.display module. """ from unittest.mock import MagicMock from engine.display import DisplayRegistry, NullDisplay, TerminalDisplay from engine.display.backends.multi import MultiDisplay class TestDisplayProtocol: """Test that display backends satisfy the Display protocol.""" def test_terminal_display_is_display(self): """TerminalDisplay satisfies Display protocol.""" display = TerminalDisplay() assert hasattr(display, "init") assert hasattr(display, "show") assert hasattr(display, "clear") assert hasattr(display, "cleanup") def test_null_display_is_display(self): """NullDisplay satisfies Display protocol.""" display = NullDisplay() assert hasattr(display, "init") assert hasattr(display, "show") assert hasattr(display, "clear") assert hasattr(display, "cleanup") class TestDisplayRegistry: """Tests for DisplayRegistry class.""" def setup_method(self): """Reset registry before each test.""" DisplayRegistry._backends = {} DisplayRegistry._initialized = False def test_register_adds_backend(self): """register adds a backend to the registry.""" DisplayRegistry.register("test", TerminalDisplay) assert DisplayRegistry.get("test") == TerminalDisplay def test_register_case_insensitive(self): """register is case insensitive.""" DisplayRegistry.register("TEST", TerminalDisplay) assert DisplayRegistry.get("test") == TerminalDisplay def test_get_returns_none_for_unknown(self): """get returns None for unknown backend.""" assert DisplayRegistry.get("unknown") is None def test_list_backends_returns_all(self): """list_backends returns all registered backends.""" DisplayRegistry.register("a", TerminalDisplay) DisplayRegistry.register("b", NullDisplay) backends = DisplayRegistry.list_backends() assert "a" in backends assert "b" in backends def test_create_returns_instance(self): """create returns a display instance.""" DisplayRegistry.register("test", NullDisplay) display = DisplayRegistry.create("test") assert isinstance(display, NullDisplay) def test_create_returns_none_for_unknown(self): """create returns None for unknown backend.""" display = DisplayRegistry.create("unknown") assert display is None def test_initialize_registers_defaults(self): """initialize registers default backends.""" DisplayRegistry.initialize() assert DisplayRegistry.get("terminal") == TerminalDisplay assert DisplayRegistry.get("null") == NullDisplay from engine.display.backends.sixel import SixelDisplay from engine.display.backends.websocket import WebSocketDisplay assert DisplayRegistry.get("websocket") == WebSocketDisplay assert DisplayRegistry.get("sixel") == SixelDisplay def test_initialize_idempotent(self): """initialize can be called multiple times safely.""" DisplayRegistry.initialize() DisplayRegistry._backends["custom"] = TerminalDisplay DisplayRegistry.initialize() assert "custom" in DisplayRegistry.list_backends() class TestTerminalDisplay: """Tests for TerminalDisplay class.""" def test_init_sets_dimensions(self): """init stores terminal dimensions.""" display = TerminalDisplay() display.init(80, 24) assert display.width == 80 assert display.height == 24 def test_show_returns_none(self): """show returns None after writing to stdout.""" display = TerminalDisplay() display.width = 80 display.height = 24 display.show(["line1", "line2"]) def test_clear_does_not_error(self): """clear works without error.""" display = TerminalDisplay() display.clear() def test_cleanup_does_not_error(self): """cleanup works without error.""" display = TerminalDisplay() display.cleanup() class TestNullDisplay: """Tests for NullDisplay class.""" def test_init_stores_dimensions(self): """init stores dimensions.""" display = NullDisplay() display.init(100, 50) assert display.width == 100 assert display.height == 50 def test_show_does_nothing(self): """show discards buffer without error.""" display = NullDisplay() display.show(["line1", "line2", "line3"]) def test_clear_does_nothing(self): """clear does nothing.""" display = NullDisplay() display.clear() def test_cleanup_does_nothing(self): """cleanup does nothing.""" display = NullDisplay() display.cleanup() class TestMultiDisplay: """Tests for MultiDisplay class.""" def test_init_stores_dimensions(self): """init stores dimensions and forwards to displays.""" mock_display1 = MagicMock() mock_display2 = MagicMock() multi = MultiDisplay([mock_display1, mock_display2]) multi.init(120, 40) assert multi.width == 120 assert multi.height == 40 mock_display1.init.assert_called_once_with(120, 40, reuse=False) mock_display2.init.assert_called_once_with(120, 40, reuse=False) def test_show_forwards_to_all_displays(self): """show forwards buffer to all displays.""" mock_display1 = MagicMock() mock_display2 = MagicMock() multi = MultiDisplay([mock_display1, mock_display2]) buffer = ["line1", "line2"] multi.show(buffer) mock_display1.show.assert_called_once_with(buffer) mock_display2.show.assert_called_once_with(buffer) def test_clear_forwards_to_all_displays(self): """clear forwards to all displays.""" mock_display1 = MagicMock() mock_display2 = MagicMock() multi = MultiDisplay([mock_display1, mock_display2]) multi.clear() mock_display1.clear.assert_called_once() mock_display2.clear.assert_called_once() def test_cleanup_forwards_to_all_displays(self): """cleanup forwards to all displays.""" mock_display1 = MagicMock() mock_display2 = MagicMock() multi = MultiDisplay([mock_display1, mock_display2]) multi.cleanup() mock_display1.cleanup.assert_called_once() mock_display2.cleanup.assert_called_once() def test_empty_displays_list(self): """handles empty displays list gracefully.""" multi = MultiDisplay([]) multi.init(80, 24) multi.show(["test"]) multi.clear() multi.cleanup() def test_init_with_reuse(self): """init passes reuse flag to child displays.""" mock_display = MagicMock() multi = MultiDisplay([mock_display]) multi.init(80, 24, reuse=True) mock_display.init.assert_called_once_with(80, 24, reuse=True)