"""Tests for pure peer statistics.""" from __future__ import annotations import math from app.services import fundamentals_peers as pr def test_median_ranks_at_50_tie_aware(): s = pr.peer_stat(3, [1, 2, 3, 4, 5], higher_is_better=True) assert s.median == 3 assert s.favorable_percentile == 50 # tie-aware rank of the median assert s.peer_count == 5 def test_all_equal_peers_rank_at_50(): s = pr.peer_stat(3, [3, 3, 3, 3, 3], higher_is_better=True) assert s.favorable_percentile == 50 # not 100 — ties don't get full credit def test_peer_stat_lower_is_better_flips_direction(): assert pr.peer_stat(3, [1, 2, 3, 4, 5], higher_is_better=False).favorable_percentile == 50 def test_peer_stat_unique_top_and_bottom(): assert pr.peer_stat(5, [1, 2, 3, 4, 5], higher_is_better=True).favorable_percentile == 100 assert pr.peer_stat(1, [1, 2, 3, 4, 5], higher_is_better=True).favorable_percentile == 0 def test_peer_stat_requires_min_valid_peers(): assert pr.peer_stat(3, [1, 2, 3, None], higher_is_better=True) is None # 3 valid < 5 assert pr.peer_stat(None, [1, 2, 3, 4, 5], higher_is_better=True) is None # null subject def test_peer_stat_excludes_null_and_non_finite(): s = pr.peer_stat(3, [1, 2, 3, 4, 5, None, math.nan, math.inf, -math.inf], higher_is_better=True) assert s.peer_count == 5 # nulls + NaN/inf dropped # a non-finite subject is invalid assert pr.peer_stat(math.nan, [1, 2, 3, 4, 5], higher_is_better=True) is None def test_net_debt_is_not_peer_eligible(): assert pr.peer_stat_for("net_debt", 100, [10, 20, 30, 40, 50]) is None # size-dependent assert pr.peer_stat_for("net_debt_to_ebitda", 1.0, [1, 2, 3, 4, 5]) is not None def test_peer_stat_for_uses_polarity(): # pe is lower-is-better: a low pe beats most peers s = pr.peer_stat_for("pe", 10, [10, 20, 30, 40, 50]) assert s.favorable_percentile == 100 def test_two_digit_sic(): assert pr.two_digit_sic("7372") == "73" assert pr.two_digit_sic("3571") == "35" assert pr.two_digit_sic(None) is None assert pr.two_digit_sic("x") is None