""" tests/test_importer.py ---------------------- Tests for core/importer.py — CSV draw import. Powerball config: 5 main from 1–69, 1 bonus from 1–26. """ 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"