forked from genewildish/Mainline
Fixes: unused imports, import sorting, unused variable, overly broad exception type in test. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
"""Tests for the FigmentEffect plugin."""
|
|
|
|
import os
|
|
from enum import Enum
|
|
|
|
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
|
|
for frame in range(2, 100):
|
|
state = effect.get_figment_state(frame, 40, 20)
|
|
if state is None:
|
|
break
|
|
|
|
# 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
|