"""Tests for the FigmentEffect plugin.""" import os from enum import Enum from unittest.mock import patch import pytest from effects_plugins.figment import FigmentEffect, FigmentPhase, FigmentState from engine.effects.types import EffectConfig, EffectContext FIXTURE_SVG = os.path.join( os.path.dirname(__file__), "fixtures", "test.svg" ) FIGMENTS_DIR = os.path.join(os.path.dirname(__file__), "fixtures") class TestFigmentPhase: def test_is_enum(self): assert issubclass(FigmentPhase, Enum) def test_has_all_phases(self): assert hasattr(FigmentPhase, "REVEAL") assert hasattr(FigmentPhase, "HOLD") assert hasattr(FigmentPhase, "DISSOLVE") class TestFigmentState: def test_creation(self): state = FigmentState( phase=FigmentPhase.REVEAL, progress=0.5, rows=["█▀▄", " █ "], gradient=[46, 40, 34, 28, 22, 22, 34, 40, 46, 82, 118, 231], center_row=5, center_col=10, ) assert state.phase == FigmentPhase.REVEAL assert state.progress == 0.5 assert len(state.rows) == 2 class TestFigmentEffectInit: def test_name(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) assert effect.name == "figment" def test_default_config(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) assert effect.config.enabled is False assert effect.config.intensity == 1.0 assert effect.config.params["interval_secs"] == 60 assert effect.config.params["display_secs"] == 4.5 def test_process_is_noop(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) buf = ["line1", "line2"] ctx = EffectContext( terminal_width=80, terminal_height=24, scroll_cam=0, ticker_height=20, ) result = effect.process(buf, ctx) assert result == buf assert result is buf def test_configure(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) new_cfg = EffectConfig(enabled=True, intensity=0.5) effect.configure(new_cfg) assert effect.config.enabled is True assert effect.config.intensity == 0.5 class TestFigmentStateMachine: def test_idle_initially(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) effect.config.enabled = True state = effect.get_figment_state(0, 80, 24) # Timer hasn't fired yet, should be None (idle) assert state is None def test_trigger_starts_reveal(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) effect.config.enabled = True effect.trigger(80, 24) state = effect.get_figment_state(1, 80, 24) assert state is not None assert state.phase == FigmentPhase.REVEAL def test_full_cycle(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) effect.config.enabled = True effect.config.params["display_secs"] = 0.15 # 3 phases x 0.05s effect.trigger(40, 20) # Advance through reveal (30 frames at 0.05s = 1.5s, but we shrunk it) # With display_secs=0.15, each phase is 0.05s = 1 frame state = effect.get_figment_state(1, 40, 20) assert state is not None assert state.phase == FigmentPhase.REVEAL # Advance enough frames to get through all phases last_state = None for frame in range(2, 100): state = effect.get_figment_state(frame, 40, 20) if state is None: break last_state = state # Should have completed the full cycle back to idle assert state is None def test_timer_fires_at_interval(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) effect.config.enabled = True effect.config.params["interval_secs"] = 0.1 # 2 frames at 20fps # Frame 0: idle state = effect.get_figment_state(0, 40, 20) assert state is None # Advance past interval (0.1s = 2 frames) state = effect.get_figment_state(1, 40, 20) state = effect.get_figment_state(2, 40, 20) state = effect.get_figment_state(3, 40, 20) # Timer should have fired by now assert state is not None class TestFigmentEdgeCases: def test_empty_figment_dir(self, tmp_path): effect = FigmentEffect(figment_dir=str(tmp_path)) effect.config.enabled = True effect.trigger(40, 20) state = effect.get_figment_state(1, 40, 20) # No SVGs available — should stay idle assert state is None def test_missing_figment_dir(self): effect = FigmentEffect(figment_dir="/nonexistent/path") effect.config.enabled = True effect.trigger(40, 20) state = effect.get_figment_state(1, 40, 20) assert state is None def test_disabled_ignores_trigger(self): effect = FigmentEffect(figment_dir=FIGMENTS_DIR) effect.config.enabled = False effect.trigger(80, 24) state = effect.get_figment_state(1, 80, 24) assert state is None