forked from genewildish/Mainline
feat(tests): improve coverage to 56%, add benchmark regression tests
- Add EffectPlugin ABC with @abstractmethod decorators for interface enforcement - Add runtime interface checking in discover_plugins() with issubclass() - Add EffectContext factory with sensible defaults - Standardize Display __init__ (remove redundant init in TerminalDisplay) - Document effect behavior when ticker_height=0 - Evaluate legacy effects: document coexistence, no deprecation needed - Research plugin patterns (VST, Python entry points) - Fix pysixel dependency (removed broken dependency) Test coverage improvements: - Add DisplayRegistry tests - Add MultiDisplay tests - Add SixelDisplay tests - Add controller._get_display tests - Add effects controller command handling tests - Add benchmark regression tests (@pytest.mark.benchmark) - Add pytest marker for benchmark tests in pyproject.toml Documentation updates: - Update AGENTS.md with 56% coverage stats and effect plugin docs - Update README.md with Sixel display mode and benchmark commands - Add new modules to architecture section
This commit is contained in:
@@ -5,7 +5,75 @@ Tests for engine.controller module.
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from engine import config
|
||||
from engine.controller import StreamController
|
||||
from engine.controller import StreamController, _get_display
|
||||
|
||||
|
||||
class TestGetDisplay:
|
||||
"""Tests for _get_display function."""
|
||||
|
||||
@patch("engine.controller.WebSocketDisplay")
|
||||
@patch("engine.controller.TerminalDisplay")
|
||||
def test_get_display_terminal(self, mock_terminal, mock_ws):
|
||||
"""returns TerminalDisplay for display=terminal."""
|
||||
mock_terminal.return_value = MagicMock()
|
||||
mock_ws.return_value = MagicMock()
|
||||
|
||||
cfg = config.Config(display="terminal")
|
||||
display = _get_display(cfg)
|
||||
|
||||
mock_terminal.assert_called()
|
||||
assert isinstance(display, MagicMock)
|
||||
|
||||
@patch("engine.controller.WebSocketDisplay")
|
||||
@patch("engine.controller.TerminalDisplay")
|
||||
def test_get_display_websocket(self, mock_terminal, mock_ws):
|
||||
"""returns WebSocketDisplay for display=websocket."""
|
||||
mock_ws_instance = MagicMock()
|
||||
mock_ws.return_value = mock_ws_instance
|
||||
mock_terminal.return_value = MagicMock()
|
||||
|
||||
cfg = config.Config(display="websocket")
|
||||
_get_display(cfg)
|
||||
|
||||
mock_ws.assert_called()
|
||||
mock_ws_instance.start_server.assert_called()
|
||||
mock_ws_instance.start_http_server.assert_called()
|
||||
|
||||
@patch("engine.controller.SixelDisplay")
|
||||
def test_get_display_sixel(self, mock_sixel):
|
||||
"""returns SixelDisplay for display=sixel."""
|
||||
mock_sixel.return_value = MagicMock()
|
||||
cfg = config.Config(display="sixel")
|
||||
_get_display(cfg)
|
||||
|
||||
mock_sixel.assert_called()
|
||||
|
||||
def test_get_display_unknown_returns_null(self):
|
||||
"""returns NullDisplay for unknown display mode."""
|
||||
cfg = config.Config(display="unknown")
|
||||
display = _get_display(cfg)
|
||||
|
||||
from engine.display import NullDisplay
|
||||
|
||||
assert isinstance(display, NullDisplay)
|
||||
|
||||
@patch("engine.controller.WebSocketDisplay")
|
||||
@patch("engine.controller.TerminalDisplay")
|
||||
@patch("engine.controller.MultiDisplay")
|
||||
def test_get_display_both(self, mock_multi, mock_terminal, mock_ws):
|
||||
"""returns MultiDisplay for display=both."""
|
||||
mock_terminal_instance = MagicMock()
|
||||
mock_ws_instance = MagicMock()
|
||||
mock_terminal.return_value = mock_terminal_instance
|
||||
mock_ws.return_value = mock_ws_instance
|
||||
|
||||
cfg = config.Config(display="both")
|
||||
_get_display(cfg)
|
||||
|
||||
mock_multi.assert_called()
|
||||
call_args = mock_multi.call_args[0][0]
|
||||
assert mock_terminal_instance in call_args
|
||||
assert mock_ws_instance in call_args
|
||||
|
||||
|
||||
class TestStreamController:
|
||||
@@ -68,6 +136,24 @@ class TestStreamController:
|
||||
assert mic_ok is False
|
||||
assert ntfy_ok is True
|
||||
|
||||
@patch("engine.controller.MicMonitor")
|
||||
def test_initialize_sources_cc_subscribed(self, mock_mic):
|
||||
"""initialize_sources subscribes C&C handler."""
|
||||
mock_mic_instance = MagicMock()
|
||||
mock_mic_instance.available = False
|
||||
mock_mic_instance.start.return_value = False
|
||||
mock_mic.return_value = mock_mic_instance
|
||||
|
||||
with patch("engine.controller.NtfyPoller") as mock_ntfy:
|
||||
mock_ntfy_instance = MagicMock()
|
||||
mock_ntfy_instance.start.return_value = True
|
||||
mock_ntfy.return_value = mock_ntfy_instance
|
||||
|
||||
controller = StreamController()
|
||||
controller.initialize_sources()
|
||||
|
||||
mock_ntfy_instance.subscribe.assert_called()
|
||||
|
||||
|
||||
class TestStreamControllerCleanup:
|
||||
"""Tests for StreamController cleanup."""
|
||||
|
||||
Reference in New Issue
Block a user