"""Tests for replayer.metrics percentile + summary helpers (B5).""" from __future__ import annotations import math from replayer.metrics import _percentile def test_percentile_single_value(): assert _percentile([42.0], 0.50) == 42.0 assert _percentile([42.0], 0.99) == 42.0 def test_percentile_two_values_interpolates(): # For [0, 10] linear interpolation gives p50=5.0, p90=9.0. assert math.isclose(_percentile([0.0, 10.0], 0.50), 5.0) assert math.isclose(_percentile([0.0, 10.0], 0.90), 9.0) def test_percentile_endpoints(): vals = [1.0, 2.0, 3.0, 4.0, 5.0] assert _percentile(vals, 0.0) == 1.0 assert _percentile(vals, 1.0) == 5.0 def test_percentile_matches_numpy_linear_default(): # Independently computed using numpy's default linear interpolation; # we hardcode the expectations so the test does not depend on numpy. vals = [1.0, 2.0, 4.0, 8.0, 16.0, 32.0] # rank for p50 = 0.5 * 5 = 2.5 -> 0.5 * 4 + 0.5 * 8 = 6.0 assert math.isclose(_percentile(vals, 0.50), 6.0) # rank for p90 = 0.9 * 5 = 4.5 -> 0.5 * 16 + 0.5 * 32 = 24.0 assert math.isclose(_percentile(vals, 0.90), 24.0) # rank for p99 = 0.99 * 5 = 4.95 -> 0.05 * 16 + 0.95 * 32 = 31.2 assert math.isclose(_percentile(vals, 0.99), 31.2) def test_percentile_no_off_by_one_at_boundary(): # Regression: previous round-based implementation returned the wrong # element when rank fell exactly on an integer. vals = [10.0, 20.0, 30.0] # rank for p50 = 0.5 * 2 = 1.0 -> exactly element 1 -> 20.0 assert _percentile(vals, 0.50) == 20.0