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.
185 lines
6.6 KiB
Python
185 lines
6.6 KiB
Python
"""
|
|
Tests for UIPanel.
|
|
"""
|
|
|
|
from engine.pipeline.ui import StageControl, UIConfig, UIPanel
|
|
|
|
|
|
class MockStage:
|
|
"""Mock stage for testing."""
|
|
|
|
def __init__(self, name, category="effect"):
|
|
self.name = name
|
|
self.category = category
|
|
self._enabled = True
|
|
|
|
def is_enabled(self):
|
|
return self._enabled
|
|
|
|
|
|
class TestUIPanel:
|
|
"""Tests for UIPanel."""
|
|
|
|
def test_init(self):
|
|
"""UIPanel initializes with default config."""
|
|
panel = UIPanel()
|
|
assert panel.config.panel_width == 24
|
|
assert panel.config.stage_list_height == 12
|
|
assert panel.scroll_offset == 0
|
|
assert panel.selected_stage is None
|
|
|
|
def test_register_stage(self):
|
|
"""register_stage adds a stage control."""
|
|
panel = UIPanel()
|
|
stage = MockStage("noise")
|
|
panel.register_stage(stage, enabled=True)
|
|
assert "noise" in panel.stages
|
|
ctrl = panel.stages["noise"]
|
|
assert ctrl.name == "noise"
|
|
assert ctrl.enabled is True
|
|
assert ctrl.selected is False
|
|
|
|
def test_select_stage(self):
|
|
"""select_stage sets selection."""
|
|
panel = UIPanel()
|
|
stage1 = MockStage("noise")
|
|
stage2 = MockStage("fade")
|
|
panel.register_stage(stage1)
|
|
panel.register_stage(stage2)
|
|
panel.select_stage("fade")
|
|
assert panel.selected_stage == "fade"
|
|
assert panel.stages["fade"].selected is True
|
|
assert panel.stages["noise"].selected is False
|
|
|
|
def test_toggle_stage(self):
|
|
"""toggle_stage flips enabled state."""
|
|
panel = UIPanel()
|
|
stage = MockStage("glitch")
|
|
panel.register_stage(stage, enabled=True)
|
|
result = panel.toggle_stage("glitch")
|
|
assert result is False
|
|
assert panel.stages["glitch"].enabled is False
|
|
result = panel.toggle_stage("glitch")
|
|
assert result is True
|
|
|
|
def test_get_enabled_stages(self):
|
|
"""get_enabled_stages returns only enabled stage names."""
|
|
panel = UIPanel()
|
|
panel.register_stage(MockStage("noise"), enabled=True)
|
|
panel.register_stage(MockStage("fade"), enabled=False)
|
|
panel.register_stage(MockStage("glitch"), enabled=True)
|
|
enabled = panel.get_enabled_stages()
|
|
assert set(enabled) == {"noise", "glitch"}
|
|
|
|
def test_scroll_stages(self):
|
|
"""scroll_stages moves the view."""
|
|
panel = UIPanel(UIConfig(stage_list_height=3))
|
|
for i in range(10):
|
|
panel.register_stage(MockStage(f"stage{i}"))
|
|
assert panel.scroll_offset == 0
|
|
panel.scroll_stages(1)
|
|
assert panel.scroll_offset == 1
|
|
panel.scroll_stages(-1)
|
|
assert panel.scroll_offset == 0
|
|
# Clamp at max
|
|
panel.scroll_stages(100)
|
|
assert panel.scroll_offset == 7 # 10 - 3 = 7
|
|
|
|
def test_render_produces_lines(self):
|
|
"""render produces list of strings of correct width."""
|
|
panel = UIPanel(UIConfig(panel_width=20))
|
|
panel.register_stage(MockStage("noise"), enabled=True)
|
|
panel.register_stage(MockStage("fade"), enabled=False)
|
|
panel.select_stage("noise")
|
|
lines = panel.render(80, 24)
|
|
# All lines should be exactly panel_width chars (20)
|
|
for line in lines:
|
|
assert len(line) == 20
|
|
# Should have header, stage rows, separator, params area, footer
|
|
assert len(lines) >= 5
|
|
|
|
def test_process_key_event_space_toggles_stage(self):
|
|
"""process_key_event with space toggles UI panel visibility."""
|
|
panel = UIPanel()
|
|
stage = MockStage("glitch")
|
|
panel.register_stage(stage, enabled=True)
|
|
panel.select_stage("glitch")
|
|
# Space should now toggle UI panel visibility, not stage
|
|
assert panel._show_panel is True
|
|
handled = panel.process_key_event(" ")
|
|
assert handled is True
|
|
assert panel._show_panel is False
|
|
# Pressing space again should show panel
|
|
handled = panel.process_key_event(" ")
|
|
assert panel._show_panel is True
|
|
|
|
def test_process_key_event_space_does_not_toggle_in_picker(self):
|
|
"""Space should not toggle UI panel when preset picker is active."""
|
|
panel = UIPanel()
|
|
panel._show_panel = True
|
|
panel._show_preset_picker = True
|
|
handled = panel.process_key_event(" ")
|
|
assert handled is False # Not handled when picker active
|
|
assert panel._show_panel is True # Unchanged
|
|
|
|
def test_process_key_event_s_selects_next(self):
|
|
"""process_key_event with s cycles selection."""
|
|
panel = UIPanel()
|
|
panel.register_stage(MockStage("noise"))
|
|
panel.register_stage(MockStage("fade"))
|
|
panel.register_stage(MockStage("glitch"))
|
|
panel.select_stage("noise")
|
|
handled = panel.process_key_event("s")
|
|
assert handled is True
|
|
assert panel.selected_stage == "fade"
|
|
|
|
def test_process_key_event_hjkl_navigation(self):
|
|
"""process_key_event with HJKL keys."""
|
|
panel = UIPanel()
|
|
stage = MockStage("noise")
|
|
panel.register_stage(stage)
|
|
panel.select_stage("noise")
|
|
|
|
# J or Down should scroll or adjust param
|
|
assert panel.scroll_stages(1) is None # Just test it doesn't error
|
|
# H or Left should adjust param (when param selected)
|
|
panel.selected_stage = "noise"
|
|
panel._focused_param = "intensity"
|
|
panel.stages["noise"].params["intensity"] = 0.5
|
|
|
|
# Left/H should decrease
|
|
handled = panel.process_key_event("h")
|
|
assert handled is True
|
|
# L or Right should increase
|
|
handled = panel.process_key_event("l")
|
|
assert handled is True
|
|
|
|
# K should scroll up
|
|
panel.selected_stage = None
|
|
handled = panel.process_key_event("k")
|
|
assert handled is True
|
|
|
|
def test_set_event_callback(self):
|
|
"""set_event_callback registers callback."""
|
|
panel = UIPanel()
|
|
called = []
|
|
|
|
def callback(stage_name, enabled):
|
|
called.append((stage_name, enabled))
|
|
|
|
panel.set_event_callback("stage_toggled", callback)
|
|
panel.toggle_stage("test") # No stage, won't trigger
|
|
# Simulate toggle through event
|
|
panel._emit_event("stage_toggled", stage_name="noise", enabled=False)
|
|
assert called == [("noise", False)]
|
|
|
|
def test_register_stage_returns_control(self):
|
|
"""register_stage should return the StageControl instance."""
|
|
panel = UIPanel()
|
|
stage = MockStage("noise_effect")
|
|
control = panel.register_stage(stage, enabled=True)
|
|
assert control is not None
|
|
assert isinstance(control, StageControl)
|
|
assert control.name == "noise_effect"
|
|
assert control.enabled is True
|