05/23 Phase 18,19

This commit is contained in:
2026-05-23 16:31:55 -04:00
parent 7506e94d61
commit 2553406254
9 changed files with 674 additions and 5 deletions
+228
View File
@@ -0,0 +1,228 @@
"""
tests/test_importer.py
----------------------
Tests for core/importer.py — CSV draw import.
Powerball config: 5 main from 169, 1 bonus from 126.
"""
import os
import pytest
from db.models import get_game_by_name, add_game, get_draws_with_game
from core.importer import import_draws_csv, _parse_date
# ── _parse_date ───────────────────────────────────────────────────────────────
def test_parse_date_iso():
assert _parse_date("2024-01-15") == "2024-01-15"
def test_parse_date_us_slash():
assert _parse_date("01/15/2024") == "2024-01-15"
def test_parse_date_us_dash():
assert _parse_date("01-15-2024") == "2024-01-15"
def test_parse_date_invalid():
assert _parse_date("not-a-date") is None
def test_parse_date_header_text():
assert _parse_date("Date") is None
assert _parse_date("draw_date") is None
# ── Wide format (Date, N1, N2, ...) ──────────────────────────────────────────
def test_wide_no_header(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"2024-01-01,1,13,36,61,69,7\n"
"2024-01-03,2,7,22,45,61,15\n"
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
assert result["skipped"] == 0
assert result["errors"] == []
def test_wide_with_header(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"Date,Ball1,Ball2,Ball3,Ball4,Ball5,Bonus\n"
"2024-01-01,1,13,36,61,69,7\n"
"2024-01-03,2,7,22,45,61,15\n"
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
assert result["errors"] == []
def test_wide_no_bonus_column(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-01-01,1,13,36,61,69\n")
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 1
draws = get_draws_with_game(game_id=game["id"])
assert draws[0]["bonus"] is None
def test_wide_us_date_format(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("01/15/2024,5,14,22,36,69,7\n")
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 1
draws = get_draws_with_game(game_id=game["id"])
assert draws[0]["draw_date"] == "2024-01-15"
# ── Packed format (Date, "N1,N2,...", Bonus) ──────────────────────────────────
def test_packed_format(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text('2024-01-01,"1,13,36,61,69",7\n')
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 1
assert result["errors"] == []
def test_packed_with_header(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
'Date,Numbers,Bonus\n'
'2024-01-01,"1,13,36,61,69",7\n'
'2024-01-03,"2,7,22,45,61",15\n'
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
# ── LottoSight export format ──────────────────────────────────────────────────
def test_lottosight_export_format(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "export.csv"
csv_file.write_text(
"Game,Date,Numbers,Bonus,Multiplier,Source\n"
'Powerball,2024-01-01,"1,13,36,61,69",7,2x,powerball_ny\n'
'Powerball,2024-01-03,"2,7,22,45,61",15,3x,powerball_ny\n'
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
assert result["errors"] == []
# ── Duplicate detection ───────────────────────────────────────────────────────
def test_duplicate_skipped(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"2024-01-01,1,13,36,61,69,7\n"
"2024-01-01,1,13,36,61,69,7\n" # same date → duplicate
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 1
assert result["skipped"] == 1
def test_reimport_all_skipped(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-01-01,1,13,36,61,69,7\n")
import_draws_csv(game["id"], str(csv_file))
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 0
assert result["skipped"] == 1
# ── Validation errors ─────────────────────────────────────────────────────────
def test_wrong_number_count(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-01-01,1,13,36,61\n") # only 4 numbers
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 0
assert len(result["errors"]) == 1 # rejected — too few numbers to parse
def test_number_out_of_range(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-01-01,1,13,36,61,99,7\n") # 99 > 69
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 0
assert len(result["errors"]) == 1
def test_mixed_valid_invalid(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"2024-01-01,1,13,36,61,69,7\n"
"bad_date,1,2,3,4,5,6\n" # unparseable
"2024-01-03,2,7,22,45,61,15\n"
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
assert len(result["errors"]) == 1
# ── Edge cases ────────────────────────────────────────────────────────────────
def test_file_not_found(tmp_db):
game = get_game_by_name("Powerball")
result = import_draws_csv(game["id"], "/nonexistent/path/file.csv")
assert result["added"] == 0
assert len(result["errors"]) == 1
assert "not found" in result["errors"][0].lower()
def test_empty_file(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "empty.csv"
csv_file.write_text("")
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 0
assert result["errors"] == ["File is empty"]
def test_blank_lines_ignored(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"2024-01-01,1,13,36,61,69,7\n"
"\n"
"2024-01-03,2,7,22,45,61,15\n"
"\n"
)
result = import_draws_csv(game["id"], str(csv_file))
assert result["added"] == 2
assert result["errors"] == []
def test_unknown_game_id(tmp_db, tmp_path):
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-01-01,1,2,3,4,5\n")
result = import_draws_csv(99999, str(csv_file))
assert result["added"] == 0
assert len(result["errors"]) == 1
def test_custom_game_import(tmp_db, tmp_path):
gid = add_game("My Lotto", 6, 49, bonus_count=0, bonus_max=0)
csv_file = tmp_path / "draws.csv"
csv_file.write_text(
"2024-01-01,5,14,22,33,41,48\n"
"2024-01-08,3,17,28,35,44,49\n"
)
result = import_draws_csv(gid, str(csv_file))
assert result["added"] == 2
assert result["errors"] == []
def test_data_persisted_correctly(tmp_db, tmp_path):
game = get_game_by_name("Powerball")
csv_file = tmp_path / "draws.csv"
csv_file.write_text("2024-03-15,5,14,22,36,69,7\n")
import_draws_csv(game["id"], str(csv_file))
draws = get_draws_with_game(game_id=game["id"])
assert len(draws) == 1
assert draws[0]["draw_date"] == "2024-03-15"
nums = [int(n) for n in draws[0]["numbers"].split(",")]
assert sorted(nums) == [5, 14, 22, 36, 69]
assert str(draws[0]["bonus"]) == "7"