forked from genewildish/Mainline
- Add Camera class with modes: vertical, horizontal, omni, floating - Refactor scroll.py and demo to use Camera abstraction - Add vis_offset for horizontal scrolling support - Add camera_x to EffectContext for effects - Add pygame window resize handling - Add HUD effect plugin for demo mode - Add --demo flag to run demo mode - Add tests for Camera and vis_offset
113 lines
3.6 KiB
Python
113 lines
3.6 KiB
Python
"""
|
|
Tests for engine.layers module.
|
|
"""
|
|
|
|
import time
|
|
|
|
from engine import layers
|
|
|
|
|
|
class TestRenderMessageOverlay:
|
|
"""Tests for render_message_overlay function."""
|
|
|
|
def test_no_message_returns_empty(self):
|
|
"""Returns empty list when msg is None."""
|
|
result, cache = layers.render_message_overlay(None, 80, 24, (None, None))
|
|
assert result == []
|
|
assert cache[0] is None
|
|
|
|
def test_message_returns_overlay_lines(self):
|
|
"""Returns non-empty list when message is present."""
|
|
msg = ("Test Title", "Test Body", time.monotonic())
|
|
result, cache = layers.render_message_overlay(msg, 80, 24, (None, None))
|
|
assert len(result) > 0
|
|
assert cache[0] is not None
|
|
|
|
def test_cache_key_changes_with_text(self):
|
|
"""Cache key changes when message text changes."""
|
|
msg1 = ("Title1", "Body1", time.monotonic())
|
|
msg2 = ("Title2", "Body2", time.monotonic())
|
|
|
|
_, cache1 = layers.render_message_overlay(msg1, 80, 24, (None, None))
|
|
_, cache2 = layers.render_message_overlay(msg2, 80, 24, cache1)
|
|
|
|
assert cache1[0] != cache2[0]
|
|
|
|
def test_cache_reuse_avoids_recomputation(self):
|
|
"""Cache is returned when same message is passed (interface test)."""
|
|
msg = ("Same Title", "Same Body", time.monotonic())
|
|
|
|
result1, cache1 = layers.render_message_overlay(msg, 80, 24, (None, None))
|
|
result2, cache2 = layers.render_message_overlay(msg, 80, 24, cache1)
|
|
|
|
assert len(result1) > 0
|
|
assert len(result2) > 0
|
|
assert cache1[0] == cache2[0]
|
|
|
|
|
|
class TestRenderFirehose:
|
|
"""Tests for render_firehose function."""
|
|
|
|
def test_no_firehose_returns_empty(self):
|
|
"""Returns empty list when firehose height is 0."""
|
|
items = [("Headline", "Source", "12:00")]
|
|
result = layers.render_firehose(items, 80, 0, 24)
|
|
assert result == []
|
|
|
|
def test_firehose_returns_lines(self):
|
|
"""Returns lines when firehose height > 0."""
|
|
items = [("Headline", "Source", "12:00")]
|
|
result = layers.render_firehose(items, 80, 4, 24)
|
|
assert len(result) == 4
|
|
|
|
def test_firehose_includes_ansi_escapes(self):
|
|
"""Returns lines containing ANSI escape sequences."""
|
|
items = [("Headline", "Source", "12:00")]
|
|
result = layers.render_firehose(items, 80, 1, 24)
|
|
assert "\033[" in result[0]
|
|
|
|
|
|
class TestApplyGlitch:
|
|
"""Tests for apply_glitch function."""
|
|
|
|
def test_empty_buffer_unchanged(self):
|
|
"""Empty buffer is returned unchanged."""
|
|
result = layers.apply_glitch([], 0, 0.0, 80)
|
|
assert result == []
|
|
|
|
def test_buffer_length_preserved(self):
|
|
"""Buffer length is preserved after glitch application."""
|
|
buf = [f"\033[{i + 1};1Htest\033[K" for i in range(10)]
|
|
result = layers.apply_glitch(buf, 0, 0.5, 80)
|
|
assert len(result) == len(buf)
|
|
|
|
|
|
class TestRenderTickerZone:
|
|
"""Tests for render_ticker_zone function - focusing on interface."""
|
|
|
|
def test_returns_list(self):
|
|
"""Returns a list of strings."""
|
|
result, cache = layers.render_ticker_zone(
|
|
[],
|
|
scroll_cam=0,
|
|
camera_x=0,
|
|
ticker_h=10,
|
|
w=80,
|
|
noise_cache={},
|
|
grad_offset=0.0,
|
|
)
|
|
assert isinstance(result, list)
|
|
|
|
def test_returns_dict_for_cache(self):
|
|
"""Returns a dict for the noise cache."""
|
|
result, cache = layers.render_ticker_zone(
|
|
[],
|
|
scroll_cam=0,
|
|
camera_x=0,
|
|
ticker_h=10,
|
|
w=80,
|
|
noise_cache={},
|
|
grad_offset=0.0,
|
|
)
|
|
assert isinstance(cache, dict)
|