""" 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