from app.scoring import SCORE_FNS def test_linear_decay_values(): fn = SCORE_FNS["linear_decay"] assert fn(True, 0, 60_000) == 1.0 assert fn(True, 30_000, 60_000) == 0.75 assert fn(True, 60_000, 60_000) == 0.5 # Past the deadline the score floors at 0.5 (still correct, fully decayed). assert fn(True, 90_000, 60_000) == 0.5 assert fn(False, 0, 60_000) == 0.0 def test_linear_decay_snaps_to_grid(): """Every score is on the 0.05 grid (21 distinct values).""" fn = SCORE_FNS["linear_decay"] for elapsed in range(0, 60_001, 137): # arbitrary irrational-ish step s = fn(True, elapsed, 60_000) # multiplied by 20, must be an integer assert abs(s * 20 - round(s * 20)) < 1e-9, (elapsed, s) def test_flat_values(): fn = SCORE_FNS["flat"] assert fn(True, 0, 60_000) == 1.0 assert fn(True, 60_000, 60_000) == 1.0 assert fn(True, 90_000, 60_000) == 1.0 assert fn(False, 0, 60_000) == 0.0 def test_exponential_decay_values(): fn = SCORE_FNS["exponential_decay"] assert fn(True, 0, 60_000) == 1.0 # At deadline: 0.5 + 0.5 * e^-2 ≈ 0.5677 → snaps to 0.55 assert fn(True, 60_000, 60_000) == 0.55 assert fn(True, 90_000, 60_000) == fn(True, 60_000, 60_000) assert fn(False, 0, 60_000) == 0.0