""" tests/test_analyzer.py ----------------------- Unit tests for core/analyzer.py. Uses three deterministic draws so every assertion is hand-verifiable. Draw data (all Powerball, game_id from tmp_db): Draw 1 (oldest) 2024-01-01: [ 1, 13, 36, 61, 69] Draw 2 2024-01-03: [ 1, 2, 13, 45, 69] Draw 3 (newest) 2024-01-05: [ 2, 13, 22, 36, 55] """ import pytest from db.models import get_game_by_name, insert_draw from core.analyzer import ( delta_analysis, frequency_analysis, gap_analysis, odd_even_ratio, pair_analysis, positional_frequency, sum_range_analysis, ) DRAWS = [ ("2024-01-01", [1, 13, 36, 61, 69]), ("2024-01-03", [1, 2, 13, 45, 69]), ("2024-01-05", [2, 13, 22, 36, 55]), ] @pytest.fixture def pb_game(tmp_db): """Return Powerball game row and insert the three test draws.""" game = get_game_by_name("Powerball") for date, nums in DRAWS: insert_draw(game["id"], date, nums, bonus=7, source="test") return game # ── frequency_analysis ──────────────────────────────────────────────────────── def test_frequency_counts_all_draws(pb_game): data = frequency_analysis(pb_game["id"]) assert data[13] == 3 # in all 3 draws assert data[1] == 2 assert data[69] == 2 assert data[36] == 2 assert data[2] == 2 assert data[61] == 1 def test_frequency_sorted_high_to_low(pb_game): data = frequency_analysis(pb_game["id"]) counts = list(data.values()) assert counts == sorted(counts, reverse=True) def test_frequency_last_n_restricts_draws(pb_game): # last_n=1 → only draw 3: [2, 13, 22, 36, 55] data = frequency_analysis(pb_game["id"], last_n=1) for n in (2, 13, 22, 36, 55): assert data[n] == 1 assert 1 not in data assert 69 not in data def test_frequency_last_n_two_draws(pb_game): # last_n=2 → draws 2 and 3: [1,2,13,45,69] + [2,13,22,36,55] data = frequency_analysis(pb_game["id"], last_n=2) assert data[2] == 2 assert data[13] == 2 assert data[1] == 1 assert 61 not in data def test_frequency_empty_db_returns_empty(tmp_db): game = get_game_by_name("Powerball") assert frequency_analysis(game["id"]) == {} # ── gap_analysis ────────────────────────────────────────────────────────────── def test_gap_zero_for_numbers_in_last_draw(pb_game): gaps = gap_analysis(pb_game["id"]) # Draw 3 = [2, 13, 22, 36, 55] — all have gap 0 for n in (2, 13, 22, 36, 55): assert gaps[n] == 0, f"Expected gap 0 for {n}, got {gaps[n]}" def test_gap_one_for_draw_before_last(pb_game): gaps = gap_analysis(pb_game["id"]) # 1 and 69 were last in draw 2 (one before latest) assert gaps[1] == 1 assert gaps[69] == 1 def test_gap_two_for_number_two_draws_back(pb_game): gaps = gap_analysis(pb_game["id"]) # 61 only in draw 1 (two draws before latest) assert gaps[61] == 2 def test_gap_total_for_never_appeared(pb_game): gaps = gap_analysis(pb_game["id"]) # Number 3 never appeared → gap = total draws = 3 assert gaps[3] == 3 def test_gap_covers_full_pool(pb_game): gaps = gap_analysis(pb_game["id"]) game = get_game_by_name("Powerball") assert len(gaps) == game["main_max"] def test_gap_empty_db_returns_empty(tmp_db): game = get_game_by_name("Powerball") assert gap_analysis(game["id"]) == {} # ── positional_frequency ────────────────────────────────────────────────────── def test_positional_has_correct_positions(pb_game): pf = positional_frequency(pb_game["id"]) game = get_game_by_name("Powerball") assert set(pf.keys()) == set(range(1, game["main_count"] + 1)) def test_positional_counts_correct_values(pb_game): pf = positional_frequency(pb_game["id"]) # Position 1: draw1=1, draw2=1, draw3=2 → {1: 2, 2: 1} assert pf[1][1] == 2 assert pf[1][2] == 1 # Position 2: draw1=13, draw2=2, draw3=13 → {13: 2, 2: 1} assert pf[2][13] == 2 assert pf[2][2] == 1 # Position 5: draw1=69, draw2=69, draw3=55 → {69: 2, 55: 1} assert pf[5][69] == 2 assert pf[5][55] == 1 def test_positional_empty_db_returns_empty_counters(tmp_db): game = get_game_by_name("Powerball") pf = positional_frequency(game["id"]) assert all(len(v) == 0 for v in pf.values()) # ── pair_analysis ───────────────────────────────────────────────────────────── def test_pair_counts_known_pairs(pb_game): pairs = pair_analysis(pb_game["id"]) # (1,13) appears in draw1 and draw2 assert pairs[(1, 13)] == 2 # (1,69) appears in draw1 and draw2 assert pairs[(1, 69)] == 2 # (13,69) appears in draw1 and draw2 assert pairs[(13, 69)] == 2 # (2,13) appears in draw2 and draw3 assert pairs[(2, 13)] == 2 # (13,36) appears in draw1 and draw3 assert pairs[(13, 36)] == 2 def test_pair_keys_are_sorted_tuples(pb_game): pairs = pair_analysis(pb_game["id"]) for n1, n2 in pairs.keys(): assert n1 < n2 def test_pair_respects_top_n(pb_game): pairs = pair_analysis(pb_game["id"], top_n=3) assert len(pairs) <= 3 def test_pair_empty_db_returns_empty(tmp_db): game = get_game_by_name("Powerball") assert pair_analysis(game["id"]) == {} # ── odd_even_ratio ──────────────────────────────────────────────────────────── def test_odd_even_counts_correct(pb_game): ratios = odd_even_ratio(pb_game["id"]) assert len(ratios) == 3 # Draw 1 [1,13,36,61,69]: odd=4, even=1 r1 = next(r for r in ratios if r["date"] == "2024-01-01") assert r1["odd"] == 4 assert r1["even"] == 1 # Draw 3 [2,13,22,36,55]: odd=2, even=3 r3 = next(r for r in ratios if r["date"] == "2024-01-05") assert r3["odd"] == 2 assert r3["even"] == 3 def test_odd_even_sums_to_main_count(pb_game): game = get_game_by_name("Powerball") ratios = odd_even_ratio(pb_game["id"]) for r in ratios: assert r["odd"] + r["even"] == game["main_count"] def test_odd_even_empty_db(tmp_db): game = get_game_by_name("Powerball") assert odd_even_ratio(game["id"]) == [] # ── sum_range_analysis ──────────────────────────────────────────────────────── def test_sum_values_correct(pb_game): sums = sum_range_analysis(pb_game["id"]) assert len(sums) == 3 s1 = next(s for s in sums if s["date"] == "2024-01-01") assert s1["sum"] == 1 + 13 + 36 + 61 + 69 # 180 s2 = next(s for s in sums if s["date"] == "2024-01-03") assert s2["sum"] == 1 + 2 + 13 + 45 + 69 # 130 s3 = next(s for s in sums if s["date"] == "2024-01-05") assert s3["sum"] == 2 + 13 + 22 + 36 + 55 # 128 def test_sum_empty_db(tmp_db): game = get_game_by_name("Powerball") assert sum_range_analysis(game["id"]) == [] # ── delta_analysis ──────────────────────────────────────────────────────────── def test_delta_values_correct(pb_game): deltas = delta_analysis(pb_game["id"]) assert len(deltas) == 3 d1 = next(d for d in deltas if d["date"] == "2024-01-01") # sorted [1,13,36,61,69] → diffs [12, 23, 25, 8] assert d1["deltas"] == [12, 23, 25, 8] d3 = next(d for d in deltas if d["date"] == "2024-01-05") # sorted [2,13,22,36,55] → diffs [11, 9, 14, 19] assert d3["deltas"] == [11, 9, 14, 19] def test_delta_length_matches_main_count_minus_one(pb_game): game = get_game_by_name("Powerball") deltas = delta_analysis(pb_game["id"]) for d in deltas: assert len(d["deltas"]) == game["main_count"] - 1 def test_delta_empty_db(tmp_db): game = get_game_by_name("Powerball") assert delta_analysis(game["id"]) == []