Files
sideline/tests/test_benchmark.py
David Gwilliam 9e4d54a82e feat(tests): improve coverage to 56%, add benchmark regression tests
- Add EffectPlugin ABC with @abstractmethod decorators for interface enforcement
- Add runtime interface checking in discover_plugins() with issubclass()
- Add EffectContext factory with sensible defaults
- Standardize Display __init__ (remove redundant init in TerminalDisplay)
- Document effect behavior when ticker_height=0
- Evaluate legacy effects: document coexistence, no deprecation needed
- Research plugin patterns (VST, Python entry points)
- Fix pysixel dependency (removed broken dependency)

Test coverage improvements:
- Add DisplayRegistry tests
- Add MultiDisplay tests
- Add SixelDisplay tests
- Add controller._get_display tests
- Add effects controller command handling tests
- Add benchmark regression tests (@pytest.mark.benchmark)
- Add pytest marker for benchmark tests in pyproject.toml

Documentation updates:
- Update AGENTS.md with 56% coverage stats and effect plugin docs
- Update README.md with Sixel display mode and benchmark commands
- Add new modules to architecture section
2026-03-15 23:26:10 -07:00

101 lines
2.8 KiB
Python

"""
Tests for engine.benchmark module - performance regression tests.
"""
from unittest.mock import patch
import pytest
from engine.display import NullDisplay
class TestBenchmarkNullDisplay:
"""Performance tests for NullDisplay - regression tests."""
@pytest.mark.benchmark
def test_null_display_minimum_fps(self):
"""NullDisplay should meet minimum performance threshold."""
import time
display = NullDisplay()
display.init(80, 24)
buffer = ["x" * 80 for _ in range(24)]
iterations = 1000
start = time.perf_counter()
for _ in range(iterations):
display.show(buffer)
elapsed = time.perf_counter() - start
fps = iterations / elapsed
min_fps = 20000
assert fps >= min_fps, f"NullDisplay FPS {fps:.0f} below minimum {min_fps}"
@pytest.mark.benchmark
def test_effects_minimum_throughput(self):
"""Effects should meet minimum processing throughput."""
import time
from effects_plugins import discover_plugins
from engine.effects import EffectContext, get_registry
discover_plugins()
registry = get_registry()
effect = registry.get("noise")
assert effect is not None, "Noise effect should be registered"
buffer = ["x" * 80 for _ in range(24)]
ctx = EffectContext(
terminal_width=80,
terminal_height=24,
scroll_cam=0,
ticker_height=20,
mic_excess=0.0,
grad_offset=0.0,
frame_number=0,
has_message=False,
)
iterations = 500
start = time.perf_counter()
for _ in range(iterations):
effect.process(buffer, ctx)
elapsed = time.perf_counter() - start
fps = iterations / elapsed
min_fps = 10000
assert fps >= min_fps, (
f"Effect processing FPS {fps:.0f} below minimum {min_fps}"
)
class TestBenchmarkWebSocketDisplay:
"""Performance tests for WebSocketDisplay."""
@pytest.mark.benchmark
def test_websocket_display_minimum_fps(self):
"""WebSocketDisplay should meet minimum performance threshold."""
import time
with patch("engine.display.backends.websocket.websockets", None):
from engine.display import WebSocketDisplay
display = WebSocketDisplay()
display.init(80, 24)
buffer = ["x" * 80 for _ in range(24)]
iterations = 500
start = time.perf_counter()
for _ in range(iterations):
display.show(buffer)
elapsed = time.perf_counter() - start
fps = iterations / elapsed
min_fps = 10000
assert fps >= min_fps, (
f"WebSocketDisplay FPS {fps:.0f} below minimum {min_fps}"
)