193 lines
5.9 KiB
Python
193 lines
5.9 KiB
Python
"""
|
|
tests/test_custom_games.py
|
|
---------------------------
|
|
Tests for add_game() and delete_game() in db/models.py,
|
|
covering custom game management.
|
|
"""
|
|
|
|
import pytest
|
|
from db.models import (
|
|
add_game, delete_game, get_all_games, get_game_by_name,
|
|
get_game_by_id, insert_draw, _BUILTIN_GAMES,
|
|
)
|
|
|
|
|
|
# ── add_game ──────────────────────────────────────────────────────────────────
|
|
|
|
def test_add_game_creates_row(tmp_db):
|
|
gid = add_game("EuroMillions", 5, 50, bonus_count=2, bonus_max=12)
|
|
game = get_game_by_id(gid)
|
|
assert game is not None
|
|
assert game["name"] == "EuroMillions"
|
|
|
|
|
|
def test_add_game_returns_id(tmp_db):
|
|
gid = add_game("UK Lotto", 6, 59)
|
|
assert isinstance(gid, int)
|
|
assert gid > 0
|
|
|
|
|
|
def test_add_game_default_active(tmp_db):
|
|
gid = add_game("Test Game", 5, 45)
|
|
game = get_game_by_id(gid)
|
|
assert game["active"] == 1
|
|
|
|
|
|
def test_add_game_appears_in_get_all_games(tmp_db):
|
|
add_game("EuroMillions", 5, 50, bonus_count=2, bonus_max=12)
|
|
names = [g["name"] for g in get_all_games()]
|
|
assert "EuroMillions" in names
|
|
|
|
|
|
def test_add_game_parameters_stored_correctly(tmp_db):
|
|
gid = add_game("Custom", 6, 45, bonus_count=1, bonus_max=20)
|
|
game = get_game_by_id(gid)
|
|
assert game["main_count"] == 6
|
|
assert game["main_max"] == 45
|
|
assert game["bonus_count"] == 1
|
|
assert game["bonus_max"] == 20
|
|
|
|
|
|
def test_add_game_duplicate_name_raises(tmp_db):
|
|
add_game("Test Game", 5, 45)
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
add_game("Test Game", 6, 50)
|
|
|
|
|
|
def test_add_game_blank_name_raises(tmp_db):
|
|
with pytest.raises(ValueError, match="blank"):
|
|
add_game(" ", 5, 45)
|
|
|
|
|
|
def test_add_game_no_bonus(tmp_db):
|
|
gid = add_game("No Bonus Game", 6, 49, bonus_count=0, bonus_max=0)
|
|
game = get_game_by_id(gid)
|
|
assert game["bonus_count"] == 0
|
|
assert game["bonus_max"] == 0
|
|
|
|
|
|
def test_add_game_builtin_name_raises(tmp_db):
|
|
with pytest.raises(ValueError):
|
|
add_game("Powerball", 5, 69, 1, 26)
|
|
|
|
|
|
# ── delete_game ───────────────────────────────────────────────────────────────
|
|
|
|
def test_delete_custom_game_no_draws(tmp_db):
|
|
gid = add_game("Temp Game", 5, 45)
|
|
result = delete_game(gid)
|
|
assert result is True
|
|
assert get_game_by_id(gid) is None
|
|
|
|
|
|
def test_delete_custom_game_removed_from_list(tmp_db):
|
|
gid = add_game("Gone Game", 5, 45)
|
|
delete_game(gid)
|
|
names = [g["name"] for g in get_all_games()]
|
|
assert "Gone Game" not in names
|
|
|
|
|
|
def test_delete_game_with_draws_returns_false(tmp_db):
|
|
gid = add_game("Active Game", 5, 45)
|
|
insert_draw(gid, "2024-01-01", [1, 2, 3, 4, 5])
|
|
result = delete_game(gid)
|
|
assert result is False
|
|
assert get_game_by_id(gid) is not None
|
|
|
|
|
|
def test_delete_builtin_powerball_returns_false(tmp_db):
|
|
pb = get_game_by_name("Powerball")
|
|
result = delete_game(pb["id"])
|
|
assert result is False
|
|
assert get_game_by_name("Powerball") is not None
|
|
|
|
|
|
def test_delete_builtin_mega_millions_returns_false(tmp_db):
|
|
mm = get_game_by_name("Mega Millions")
|
|
result = delete_game(mm["id"])
|
|
assert result is False
|
|
|
|
|
|
def test_delete_nonexistent_game_returns_false(tmp_db):
|
|
result = delete_game(99999)
|
|
assert result is False
|
|
|
|
|
|
def test_delete_game_clears_predictions(tmp_db):
|
|
from db.models import insert_prediction, get_predictions
|
|
gid = add_game("Prediction Game", 5, 45)
|
|
insert_prediction(gid, "Hot Numbers", [1, 2, 3, 4, 5])
|
|
delete_game(gid)
|
|
preds = get_predictions(game_id=gid, limit=100)
|
|
assert preds == []
|
|
|
|
|
|
# ── integration: custom game works with existing features ─────────────────────
|
|
|
|
def test_custom_game_works_with_frequency_analysis(tmp_db):
|
|
from core.analyzer import frequency_analysis
|
|
gid = add_game("My Lottery", 6, 49, bonus_count=1, bonus_max=10)
|
|
insert_draw(gid, "2024-01-01", [1, 7, 14, 22, 35, 49])
|
|
insert_draw(gid, "2024-01-03", [1, 7, 15, 23, 36, 48])
|
|
freq = frequency_analysis(gid)
|
|
assert freq[1] == 2
|
|
assert freq[7] == 2
|
|
|
|
|
|
def test_custom_game_works_with_predictor(tmp_db):
|
|
from core.predictor import hot_numbers
|
|
gid = add_game("My Lottery", 6, 49, bonus_count=1, bonus_max=10)
|
|
insert_draw(gid, "2024-01-01", [1, 7, 14, 22, 35, 49], bonus=3)
|
|
insert_draw(gid, "2024-01-03", [1, 7, 15, 23, 36, 48], bonus=5)
|
|
result = hot_numbers(gid)
|
|
assert len(result["numbers"]) == 6
|
|
assert all(1 <= n <= 49 for n in result["numbers"])
|
|
|
|
|
|
# ── 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_settings_shows_add_button(tmp_db):
|
|
import tkinter as tk
|
|
from ui.settings import SettingsScreen
|
|
|
|
try:
|
|
root = tk.Tk()
|
|
root.withdraw()
|
|
except Exception:
|
|
pytest.skip("Tkinter init failed")
|
|
try:
|
|
screen = SettingsScreen(root)
|
|
screen.refresh()
|
|
assert screen.winfo_exists()
|
|
finally:
|
|
root.destroy()
|
|
|
|
|
|
@pytest.mark.skipif(not _has_display(), reason="no display available")
|
|
def test_settings_custom_game_shows_delete_button(tmp_db):
|
|
import tkinter as tk
|
|
from ui.settings import SettingsScreen
|
|
|
|
add_game("My Custom Lottery", 5, 50)
|
|
try:
|
|
root = tk.Tk()
|
|
root.withdraw()
|
|
except Exception:
|
|
pytest.skip("Tkinter init failed")
|
|
try:
|
|
screen = SettingsScreen(root)
|
|
screen.refresh()
|
|
assert screen.winfo_exists()
|
|
finally:
|
|
root.destroy()
|