169 lines
5.6 KiB
Python
169 lines
5.6 KiB
Python
"""
|
|
tests/test_saved_predictions.py
|
|
--------------------------------
|
|
Tests for the saved-prediction model functions (delete_prediction,
|
|
delete_all_predictions) and the _count_matches helper in predictor_ui.
|
|
"""
|
|
|
|
import pytest
|
|
from db.models import (
|
|
get_game_by_name, insert_draw, insert_prediction,
|
|
get_predictions, delete_prediction, delete_all_predictions,
|
|
get_last_draw,
|
|
)
|
|
from ui.predictor_ui import _count_matches
|
|
|
|
|
|
# ── Fixtures ──────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.fixture
|
|
def pb(tmp_db):
|
|
return get_game_by_name("Powerball")
|
|
|
|
|
|
@pytest.fixture
|
|
def mm(tmp_db):
|
|
return get_game_by_name("Mega Millions")
|
|
|
|
|
|
@pytest.fixture
|
|
def with_predictions(pb, mm):
|
|
insert_draw(pb["id"], "2024-01-01", [1, 13, 36, 61, 69], bonus=7)
|
|
p1 = insert_prediction(pb["id"], "Hot Numbers", [1, 13, 36, 61, 69], bonus=7)
|
|
p2 = insert_prediction(pb["id"], "Due Numbers", [5, 10, 20, 30, 40], bonus=15)
|
|
p3 = insert_prediction(mm["id"], "Monte Carlo", [2, 14, 37, 62, 70], bonus=5)
|
|
return p1, p2, p3
|
|
|
|
|
|
# ── delete_prediction ─────────────────────────────────────────────────────────
|
|
|
|
def test_delete_prediction_removes_row(pb, with_predictions):
|
|
p1, p2, p3 = with_predictions
|
|
delete_prediction(p1)
|
|
ids = [p["id"] for p in get_predictions(limit=100_000)]
|
|
assert p1 not in ids
|
|
assert p2 in ids
|
|
|
|
|
|
def test_delete_prediction_leaves_others_intact(pb, with_predictions):
|
|
p1, p2, p3 = with_predictions
|
|
delete_prediction(p1)
|
|
remaining = get_predictions(limit=100_000)
|
|
assert len(remaining) == 2
|
|
|
|
|
|
def test_delete_nonexistent_prediction_no_error(tmp_db):
|
|
delete_prediction(99999) # should not raise
|
|
|
|
|
|
# ── delete_all_predictions ────────────────────────────────────────────────────
|
|
|
|
def test_delete_all_clears_everything(pb, with_predictions):
|
|
delete_all_predictions()
|
|
assert get_predictions(limit=100_000) == []
|
|
|
|
|
|
def test_delete_all_with_game_id_only_removes_that_game(pb, mm, with_predictions):
|
|
p1, p2, p3 = with_predictions
|
|
delete_all_predictions(game_id=pb["id"])
|
|
remaining = get_predictions(limit=100_000)
|
|
assert len(remaining) == 1
|
|
assert remaining[0]["id"] == p3
|
|
|
|
|
|
def test_delete_all_empty_db_no_error(tmp_db):
|
|
delete_all_predictions() # should not raise
|
|
|
|
|
|
def test_delete_all_game_id_no_match_no_error(pb, tmp_db):
|
|
delete_all_predictions(game_id=pb["id"]) # nothing to delete
|
|
|
|
|
|
# ── _count_matches ────────────────────────────────────────────────────────────
|
|
|
|
def test_count_matches_full_match(pb):
|
|
insert_draw(pb["id"], "2024-01-01", [1, 13, 36, 61, 69], bonus=7)
|
|
last = get_last_draw(pb["id"])
|
|
assert _count_matches("1,13,36,61,69", last) == "5/5"
|
|
|
|
|
|
def test_count_matches_partial(pb):
|
|
insert_draw(pb["id"], "2024-01-01", [1, 13, 36, 61, 69], bonus=7)
|
|
last = get_last_draw(pb["id"])
|
|
assert _count_matches("1,13,2,3,4", last) == "2/5"
|
|
|
|
|
|
def test_count_matches_zero(pb):
|
|
insert_draw(pb["id"], "2024-01-01", [1, 13, 36, 61, 69], bonus=7)
|
|
last = get_last_draw(pb["id"])
|
|
assert _count_matches("2,3,4,5,6", last) == "0/5"
|
|
|
|
|
|
def test_count_matches_no_last_draw(tmp_db):
|
|
pb = get_game_by_name("Powerball")
|
|
assert _count_matches("1,2,3,4,5", None) == "—"
|
|
|
|
|
|
# ── UI smoke tests ────────────────────────────────────────────────────────────
|
|
|
|
def _has_display():
|
|
try:
|
|
import tkinter as tk
|
|
r = tk.Tk(); r.withdraw(); r.destroy()
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
@pytest.mark.skipif(not _has_display(), reason="no display available")
|
|
def test_predictor_screen_saved_tab_loads(tmp_db):
|
|
import tkinter as tk
|
|
from ui.predictor_ui import PredictorScreen
|
|
|
|
root = tk.Tk(); root.withdraw()
|
|
try:
|
|
screen = PredictorScreen(root)
|
|
screen.refresh()
|
|
assert screen.winfo_exists()
|
|
finally:
|
|
root.destroy()
|
|
|
|
|
|
@pytest.mark.skipif(not _has_display(), reason="no display available")
|
|
def test_saved_tab_shows_predictions(tmp_db):
|
|
import tkinter as tk
|
|
from ui.predictor_ui import PredictorScreen
|
|
|
|
pb = get_game_by_name("Powerball")
|
|
insert_prediction(pb["id"], "Hot Numbers", [1, 13, 36, 61, 69], bonus=7)
|
|
|
|
root = tk.Tk(); root.withdraw()
|
|
try:
|
|
screen = PredictorScreen(root)
|
|
screen.refresh()
|
|
children = screen._saved_tree.get_children()
|
|
assert len(children) == 1
|
|
finally:
|
|
root.destroy()
|
|
|
|
|
|
@pytest.mark.skipif(not _has_display(), reason="no display available")
|
|
def test_saved_tab_delete_selected(tmp_db):
|
|
import tkinter as tk
|
|
from ui.predictor_ui import PredictorScreen
|
|
|
|
pb = get_game_by_name("Powerball")
|
|
pid = insert_prediction(pb["id"], "Hot Numbers", [1, 13, 36, 61, 69], bonus=7)
|
|
|
|
root = tk.Tk(); root.withdraw()
|
|
try:
|
|
screen = PredictorScreen(root)
|
|
screen.refresh()
|
|
iid = screen._saved_tree.get_children()[0]
|
|
screen._saved_tree.selection_set(iid)
|
|
screen._delete_selected()
|
|
assert len(screen._saved_tree.get_children()) == 0
|
|
assert get_predictions(limit=100_000) == []
|
|
finally:
|
|
root.destroy()
|