import importlib.util from pathlib import Path def _load_patterns_module(): repo_root = Path(__file__).resolve().parents[1] # Canonical home for shipped demos — `workspace/` is gitignored. module_path = repo_root / "src" / "static" / "bundled-demos" / "led_patterns.py" spec = importlib.util.spec_from_file_location("led_patterns", module_path) module = importlib.util.module_from_spec(spec) assert spec is not None and spec.loader is not None spec.loader.exec_module(module) return module def test_rainbow_frame_shape_and_bounds(): patterns = _load_patterns_module() frame = patterns.rainbow_frame(12, 3) assert len(frame) == 12 for color in frame: assert len(color) == 3 assert all(0 <= c <= 255 for c in color) def test_chase_frame_has_head_and_tail(): patterns = _load_patterns_module() frame = patterns.chase_frame(8, 5, color=(10, 20, 30), tail=(1, 2, 3)) assert len(frame) == 8 assert frame[5] == (10, 20, 30) assert frame[4] == (1, 2, 3) assert sum(1 for c in frame if c != (0, 0, 0)) == 2 def test_bounce_head_pingpongs_off_ends(): patterns = _load_patterns_module() bounce = patterns._bounce_head_index assert bounce(5, 0) == 0 and bounce(5, 4) == 4 assert bounce(5, 5) == 3 and bounce(5, 8) == 1 and bounce(5, 16) == bounce(5, 0) def test_scanner_bounce_has_head_and_fading_tail(): patterns = _load_patterns_module() frame = patterns.scanner_bounce_frame( 8, 20, head_color=(80, 10, 10), tail_color=(20, 50, 90), tail_len=4 ) assert len(frame) == 8 bright = max(range(8), key=lambda i: sum(frame[i])) assert sum(frame[bright]) >= 80 def test_knight_rider_tail_falls_off(): patterns = _load_patterns_module() fr = patterns.knight_rider_scanner_frame(16, 55, tail_len=8, falloff_gamma=3.0) assert len(fr) == 16 reds_sorted = sorted(fr[i][0] for i in range(16) if sum(fr[i]) > 0) assert len(reds_sorted) >= 2 assert reds_sorted[-1] >= 200 assert reds_sorted[0] < reds_sorted[-1] * 0.5 def test_twinkle_frame_is_deterministic_for_same_inputs(): patterns = _load_patterns_module() a = patterns.twinkle_frame(20, frame=9, seed=777, sparkles=4) b = patterns.twinkle_frame(20, frame=9, seed=777, sparkles=4) assert a == b def test_twinkle_frame_varies_between_frames(): patterns = _load_patterns_module() a = patterns.twinkle_frame(20, frame=1, seed=777, sparkles=4) b = patterns.twinkle_frame(20, frame=2, seed=777, sparkles=4) assert a != b