forked from genewildish/Mainline
Major changes: - Pipeline architecture with capability-based dependency resolution - Effects plugin system with performance monitoring - Display abstraction with multiple backends (terminal, null, websocket) - Camera system for viewport scrolling - Sensor framework for real-time input - Command-and-control system via ntfy - WebSocket display backend for browser clients - Comprehensive test suite and documentation Issue #48: ADR for preset scripting language included This commit consolidates 110 individual commits into a single feature integration that can be reviewed and tested before further refinement.
242 lines
9.4 KiB
Python
242 lines
9.4 KiB
Python
"""
|
|
Tests for engine.effects.controller module.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from engine.effects.controller import (
|
|
_format_stats,
|
|
handle_effects_command,
|
|
set_effect_chain_ref,
|
|
show_effects_menu,
|
|
)
|
|
|
|
|
|
class TestHandleEffectsCommand:
|
|
"""Tests for handle_effects_command function."""
|
|
|
|
def test_list_effects(self):
|
|
"""list command returns formatted effects list."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_plugin.config.enabled = True
|
|
mock_plugin.config.intensity = 0.5
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
with patch("engine.effects.controller._get_effect_chain") as mock_chain:
|
|
mock_chain.return_value.get_order.return_value = ["noise"]
|
|
|
|
result = handle_effects_command("/effects list")
|
|
|
|
assert "noise: ON" in result
|
|
assert "intensity=0.5" in result
|
|
|
|
def test_enable_effect(self):
|
|
"""enable command calls registry.enable."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise on")
|
|
|
|
assert "Enabled: noise" in result
|
|
mock_registry.return_value.enable.assert_called_once_with("noise")
|
|
|
|
def test_disable_effect(self):
|
|
"""disable command calls registry.disable."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise off")
|
|
|
|
assert "Disabled: noise" in result
|
|
mock_registry.return_value.disable.assert_called_once_with("noise")
|
|
|
|
def test_set_intensity(self):
|
|
"""intensity command sets plugin intensity."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_plugin.config.intensity = 0.5
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise intensity 0.8")
|
|
|
|
assert "intensity to 0.8" in result
|
|
assert mock_plugin.config.intensity == 0.8
|
|
|
|
def test_invalid_intensity_range(self):
|
|
"""intensity outside 0.0-1.0 returns error."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise intensity 1.5")
|
|
|
|
assert "between 0.0 and 1.0" in result
|
|
|
|
def test_reorder_pipeline(self):
|
|
"""reorder command calls chain.reorder."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_registry.return_value.list_all.return_value = {}
|
|
|
|
with patch("engine.effects.controller._get_effect_chain") as mock_chain:
|
|
mock_chain_instance = MagicMock()
|
|
mock_chain_instance.reorder.return_value = True
|
|
mock_chain.return_value = mock_chain_instance
|
|
|
|
result = handle_effects_command("/effects reorder noise,fade")
|
|
|
|
assert "Reordered pipeline" in result
|
|
mock_chain_instance.reorder.assert_called_once_with(["noise", "fade"])
|
|
|
|
def test_reorder_failure(self):
|
|
"""reorder returns error on failure."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_registry.return_value.list_all.return_value = {}
|
|
|
|
with patch("engine.effects.controller._get_effect_chain") as mock_chain:
|
|
mock_chain_instance = MagicMock()
|
|
mock_chain_instance.reorder.return_value = False
|
|
mock_chain.return_value = mock_chain_instance
|
|
|
|
result = handle_effects_command("/effects reorder bad")
|
|
|
|
assert "Failed to reorder" in result
|
|
|
|
def test_unknown_effect(self):
|
|
"""unknown effect returns error."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_registry.return_value.list_all.return_value = {}
|
|
|
|
result = handle_effects_command("/effects unknown on")
|
|
|
|
assert "Unknown effect" in result
|
|
|
|
def test_unknown_command(self):
|
|
"""unknown command returns error."""
|
|
result = handle_effects_command("/unknown")
|
|
assert "Unknown command" in result
|
|
|
|
def test_non_effects_command(self):
|
|
"""non-effects command returns error."""
|
|
result = handle_effects_command("not a command")
|
|
assert "Unknown command" in result
|
|
|
|
def test_invalid_intensity_value(self):
|
|
"""invalid intensity value returns error."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise intensity bad")
|
|
|
|
assert "Invalid intensity" in result
|
|
|
|
def test_missing_action(self):
|
|
"""missing action returns usage."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_registry.return_value.get.return_value = mock_plugin
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
result = handle_effects_command("/effects noise")
|
|
|
|
assert "Usage" in result
|
|
|
|
def test_stats_command(self):
|
|
"""stats command returns formatted stats."""
|
|
with patch("engine.effects.controller.get_monitor") as mock_monitor:
|
|
mock_monitor.return_value.get_stats.return_value = {
|
|
"frame_count": 100,
|
|
"pipeline": {"avg_ms": 1.5, "min_ms": 1.0, "max_ms": 2.0},
|
|
"effects": {},
|
|
}
|
|
|
|
result = handle_effects_command("/effects stats")
|
|
|
|
assert "Performance Stats" in result
|
|
|
|
def test_list_only_effects(self):
|
|
"""list command works with just /effects."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_plugin.config.enabled = False
|
|
mock_plugin.config.intensity = 0.5
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
with patch("engine.effects.controller._get_effect_chain") as mock_chain:
|
|
mock_chain.return_value = None
|
|
|
|
result = handle_effects_command("/effects")
|
|
|
|
assert "noise: OFF" in result
|
|
|
|
|
|
class TestShowEffectsMenu:
|
|
"""Tests for show_effects_menu function."""
|
|
|
|
def test_returns_formatted_menu(self):
|
|
"""returns formatted effects menu."""
|
|
with patch("engine.effects.controller.get_registry") as mock_registry:
|
|
mock_plugin = MagicMock()
|
|
mock_plugin.config.enabled = True
|
|
mock_plugin.config.intensity = 0.75
|
|
mock_registry.return_value.list_all.return_value = {"noise": mock_plugin}
|
|
|
|
with patch("engine.effects.controller._get_effect_chain") as mock_chain:
|
|
mock_chain_instance = MagicMock()
|
|
mock_chain_instance.get_order.return_value = ["noise"]
|
|
mock_chain.return_value = mock_chain_instance
|
|
|
|
result = show_effects_menu()
|
|
|
|
assert "EFFECTS MENU" in result
|
|
assert "noise" in result
|
|
|
|
|
|
class TestFormatStats:
|
|
"""Tests for _format_stats function."""
|
|
|
|
def test_returns_error_when_no_monitor(self):
|
|
"""returns error when monitor unavailable."""
|
|
with patch("engine.effects.controller.get_monitor") as mock_monitor:
|
|
mock_monitor.return_value.get_stats.return_value = {"error": "No data"}
|
|
|
|
result = _format_stats()
|
|
|
|
assert "No data" in result
|
|
|
|
def test_formats_pipeline_stats(self):
|
|
"""formats pipeline stats correctly."""
|
|
with patch("engine.effects.controller.get_monitor") as mock_monitor:
|
|
mock_monitor.return_value.get_stats.return_value = {
|
|
"frame_count": 50,
|
|
"pipeline": {"avg_ms": 2.5, "min_ms": 2.0, "max_ms": 3.0},
|
|
"effects": {"noise": {"avg_ms": 0.5, "min_ms": 0.4, "max_ms": 0.6}},
|
|
}
|
|
|
|
result = _format_stats()
|
|
|
|
assert "Pipeline" in result
|
|
assert "noise" in result
|
|
|
|
|
|
class TestSetEffectChainRef:
|
|
"""Tests for set_effect_chain_ref function."""
|
|
|
|
def test_sets_global_ref(self):
|
|
"""set_effect_chain_ref updates global reference."""
|
|
mock_chain = MagicMock()
|
|
set_effect_chain_ref(mock_chain)
|
|
|
|
from engine.effects.controller import _get_effect_chain
|
|
|
|
result = _get_effect_chain()
|
|
assert result == mock_chain
|