diff --git a/tests/test_effects.py b/tests/test_effects.py index 08e8586..12d41a5 100644 --- a/tests/test_effects.py +++ b/tests/test_effects.py @@ -331,3 +331,97 @@ class TestPerformanceMonitor: monitor.reset() stats = monitor.get_stats() assert "error" in stats + + +class TestEffectPipelinePerformance: + def test_pipeline_stays_within_frame_budget(self): + """Verify effect pipeline completes within frame budget (33ms for 30fps).""" + from engine.effects import ( + EffectChain, + EffectConfig, + EffectContext, + EffectRegistry, + ) + + class DummyEffect: + name = "dummy" + config = EffectConfig(enabled=True, intensity=1.0) + + def process(self, buf, ctx): + return [line * 2 for line in buf] + + registry = EffectRegistry() + registry.register(DummyEffect()) + + from engine.effects.performance import PerformanceMonitor + + monitor = PerformanceMonitor(max_frames=10) + chain = EffectChain(registry, monitor) + chain.set_order(["dummy"]) + + buf = ["x" * 80] * 20 + + for i in range(10): + ctx = EffectContext( + terminal_width=80, + terminal_height=24, + scroll_cam=0, + ticker_height=20, + mic_excess=0.0, + grad_offset=0.0, + frame_number=i, + has_message=False, + ) + chain.process(buf, ctx) + + stats = monitor.get_stats() + assert "error" not in stats + assert stats["pipeline"]["max_ms"] < 33.0 + + def test_individual_effects_performance(self): + """Verify individual effects don't exceed 10ms per frame.""" + from engine.effects import ( + EffectChain, + EffectConfig, + EffectContext, + EffectRegistry, + ) + + class SlowEffect: + name = "slow" + config = EffectConfig(enabled=True, intensity=1.0) + + def process(self, buf, ctx): + result = [] + for line in buf: + result.append(line) + result.append(line + line) + return result + + registry = EffectRegistry() + registry.register(SlowEffect()) + + from engine.effects.performance import PerformanceMonitor + + monitor = PerformanceMonitor(max_frames=5) + chain = EffectChain(registry, monitor) + chain.set_order(["slow"]) + + buf = ["x" * 80] * 10 + + for i in range(5): + ctx = EffectContext( + terminal_width=80, + terminal_height=24, + scroll_cam=0, + ticker_height=20, + mic_excess=0.0, + grad_offset=0.0, + frame_number=i, + has_message=False, + ) + chain.process(buf, ctx) + + stats = monitor.get_stats() + assert "error" not in stats + assert stats["effects"]["slow"]["max_ms"] < 10.0