Files
lottosight/tests/test_analysis_charts.py
2026-05-23 12:25:23 -04:00

202 lines
5.8 KiB
Python

"""
tests/test_analysis_charts.py
------------------------------
Tests for the pure chart-drawing functions in ui/analysis.py.
Uses matplotlib's Agg (non-interactive) backend so no display is required.
Each test verifies that the function populates the axes correctly
and doesn't raise on empty or populated data.
"""
import matplotlib
matplotlib.use("Agg")
from matplotlib.figure import Figure
import pytest
from db.models import get_game_by_name, insert_draw
from ui.analysis import (
_empty,
_draw_frequency,
_draw_heatmap,
_draw_gap,
_draw_pairs,
_draw_odd_even,
_draw_sum_range,
_draw_deltas,
)
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]),
]
def _ax():
"""Return a fresh Axes on a headless figure."""
fig = Figure()
return fig.add_subplot(111)
@pytest.fixture
def pb(tmp_db):
game = get_game_by_name("Powerball")
for date, nums in DRAWS:
insert_draw(game["id"], date, nums, bonus=7, source="test")
return game
# ── _empty ────────────────────────────────────────────────────────────────────
def test_empty_disables_axis(tmp_db):
ax = _ax()
_empty(ax, "test message")
assert not ax.get_visible() or not ax.axison
# ── _draw_frequency ───────────────────────────────────────────────────────────
def test_draw_frequency_creates_bars(pb):
ax = _ax()
_draw_frequency(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_frequency_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_frequency(ax, pb["id"]) # should show _empty placeholder, not raise
def test_draw_frequency_last_n(pb):
ax = _ax()
_draw_frequency(ax, pb["id"], last_n=1)
assert len(ax.patches) > 0
def test_draw_frequency_title_includes_last_n(pb):
ax = _ax()
_draw_frequency(ax, pb["id"], last_n=50)
assert "50" in ax.get_title()
# ── _draw_heatmap ─────────────────────────────────────────────────────────────
def test_draw_heatmap_creates_image(pb):
ax = _ax()
_draw_heatmap(ax, pb["id"])
assert len(ax.images) > 0
def test_draw_heatmap_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_heatmap(ax, pb["id"])
# ── _draw_gap ─────────────────────────────────────────────────────────────────
def test_draw_gap_creates_bars(pb):
ax = _ax()
_draw_gap(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_gap_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_gap(ax, pb["id"])
# ── _draw_pairs ───────────────────────────────────────────────────────────────
def test_draw_pairs_creates_bars(pb):
ax = _ax()
_draw_pairs(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_pairs_respects_top_n(pb):
ax = _ax()
_draw_pairs(ax, pb["id"], top_n=5)
assert len(ax.patches) <= 5
def test_draw_pairs_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_pairs(ax, pb["id"])
def test_draw_pairs_title_set(pb):
ax = _ax()
_draw_pairs(ax, pb["id"], top_n=10)
assert "Pair" in ax.get_title() or "pair" in ax.get_title().lower()
# ── _draw_odd_even ────────────────────────────────────────────────────────────
def test_draw_odd_even_creates_bars(pb):
ax = _ax()
_draw_odd_even(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_odd_even_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_odd_even(ax, pb["id"])
def test_draw_odd_even_title_set(pb):
ax = _ax()
_draw_odd_even(ax, pb["id"])
assert "Odd" in ax.get_title() or "Even" in ax.get_title()
# ── _draw_sum_range ───────────────────────────────────────────────────────────
def test_draw_sum_range_creates_patches(pb):
ax = _ax()
_draw_sum_range(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_sum_range_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_sum_range(ax, pb["id"])
def test_draw_sum_range_title_set(pb):
ax = _ax()
_draw_sum_range(ax, pb["id"])
assert "Sum" in ax.get_title()
# ── _draw_deltas ──────────────────────────────────────────────────────────────
def test_draw_deltas_creates_bars(pb):
ax = _ax()
_draw_deltas(ax, pb["id"])
assert len(ax.patches) > 0
def test_draw_deltas_empty_db_no_error(tmp_db):
pb = get_game_by_name("Powerball")
ax = _ax()
_draw_deltas(ax, pb["id"])
def test_draw_deltas_title_set(pb):
ax = _ax()
_draw_deltas(ax, pb["id"])
assert "Delta" in ax.get_title()
def test_draw_deltas_x_axis_are_positive(pb):
ax = _ax()
_draw_deltas(ax, pb["id"])
# All delta values between consecutive sorted numbers are positive
x_vals = [p.get_x() for p in ax.patches]
assert all(x >= 0 for x in x_vals)