"""Unit tests for automatic brightness limiting (ABL) current estimation.""" import numpy as np import pytest from ledgrab.core.processing.power_limit import ( DEFAULT_MILLIAMPS_PER_LED, estimate_current_ma, power_limit_scale, ) def test_default_ma_per_led_constant(): assert DEFAULT_MILLIAMPS_PER_LED == 55 def test_full_white_draws_ma_per_led_times_count(): colors = np.full((100, 3), 255, dtype=np.uint8) assert estimate_current_ma(colors, 55) == pytest.approx(100 * 55) def test_black_draws_zero(): colors = np.zeros((100, 3), dtype=np.uint8) assert estimate_current_ma(colors, 55) == 0.0 def test_half_white_is_half_current(): full = estimate_current_ma(np.full((100, 3), 255, dtype=np.uint8), 55) half = estimate_current_ma(np.full((100, 3), 128, dtype=np.uint8), 55) assert half == pytest.approx(full * 128 / 255, rel=1e-6) def test_zero_ma_per_led_draws_zero(): colors = np.full((100, 3), 255, dtype=np.uint8) assert estimate_current_ma(colors, 0) == 0.0 def test_empty_frame_is_safe(): colors = np.zeros((0, 3), dtype=np.uint8) assert estimate_current_ma(colors, 55) == 0.0 assert power_limit_scale(colors, 1000, 55) == 1.0 def test_scale_is_one_when_disabled(): colors = np.full((100, 3), 255, dtype=np.uint8) assert power_limit_scale(colors, 0, 55) == 1.0 assert power_limit_scale(colors, -1, 55) == 1.0 def test_scale_is_one_within_budget(): colors = np.full((100, 3), 255, dtype=np.uint8) # 5500 mA at 55 mA/LED assert power_limit_scale(colors, 6000, 55) == 1.0 assert power_limit_scale(colors, 5500, 55) == 1.0 # exactly on budget def test_scale_brings_full_white_to_budget(): colors = np.full((100, 3), 255, dtype=np.uint8) # 5500 mA scale = power_limit_scale(colors, 2750, 55) # half budget assert scale == pytest.approx(0.5, rel=1e-6) def test_applying_scale_lands_within_budget(): colors = np.full((100, 3), 255, dtype=np.uint8) # 5500 mA budget = 2750 scale = power_limit_scale(colors, budget, 55) # Mirror the processor's fixed-point application (factor/256). factor = int(scale * 256) scaled = ((colors.astype(np.uint16) * factor) >> 8).astype(np.uint8) # Fixed-point rounding can only ever round DOWN, so we never exceed budget. assert estimate_current_ma(scaled, 55) <= budget