# backend/tests/test_purchase_manager.py import sys, os sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "app")) import sqlite3 import pytest from unittest.mock import patch, MagicMock # ":memory:" 공유 커넥션 — 각 테스트에서 독립적으로 생성 def _make_mem_conn(): conn = sqlite3.connect(":memory:") conn.row_factory = sqlite3.Row return conn def test_purchase_history_has_new_columns(): """purchase_history 테이블에 신규 컬럼이 존재하는지 검증""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() cols = {r["name"] for r in mem.execute("PRAGMA table_info(purchase_history)").fetchall()} assert "numbers" in cols assert "is_real" in cols assert "source_strategy" in cols assert "source_detail" in cols assert "checked" in cols assert "results" in cols assert "total_prize" in cols # 기존 컬럼도 유지 assert "draw_no" in cols assert "amount" in cols assert "sets" in cols assert "prize" in cols assert "note" in cols mem.close() def test_strategy_performance_table_exists(): """strategy_performance 테이블이 생성되는지 검증""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() cols = {r["name"] for r in mem.execute("PRAGMA table_info(strategy_performance)").fetchall()} assert "strategy" in cols assert "draw_no" in cols assert "sets_count" in cols assert "total_correct" in cols assert "avg_score" in cols mem.close() def test_strategy_weights_table_exists(): """strategy_weights 테이블이 생성되고 초기값이 있는지 검증""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() rows = mem.execute("SELECT * FROM strategy_weights ORDER BY strategy").fetchall() strategies = {r["strategy"] for r in rows} assert strategies == {"combined", "simulation", "heatmap", "manual", "custom"} # 가중치 합이 1.0 total_weight = sum(r["weight"] for r in rows) assert abs(total_weight - 1.0) < 0.01 mem.close() def test_add_purchase_with_numbers(): """번호 포함 구매 등록""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() result = db.add_purchase( draw_no=1150, amount=5000, sets=5, numbers=[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]], is_real=False, source_strategy="simulation", source_detail={"run_id": 42}, ) assert result["draw_no"] == 1150 assert result["amount"] == 5000 assert result["is_real"] == 0 assert result["source_strategy"] == "simulation" assert result["numbers"] == [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]] assert result["source_detail"] == {"run_id": 42} mem.close() def test_get_purchases_filter_is_real(): """is_real 필터 동작""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() db.add_purchase(draw_no=1150, amount=5000, sets=5, is_real=True) db.add_purchase(draw_no=1150, amount=1000, sets=1, is_real=False) real_only = db.get_purchases(is_real=True) virtual_only = db.get_purchases(is_real=False) assert len(real_only) == 1 assert real_only[0]["is_real"] == 1 assert len(virtual_only) == 1 assert virtual_only[0]["is_real"] == 0 mem.close() def test_get_purchase_stats_by_type(): """실제/가상 분리 통계""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() db.add_purchase(draw_no=1150, amount=5000, sets=5, is_real=True, source_strategy="manual") db.add_purchase(draw_no=1150, amount=1000, sets=1, is_real=False, source_strategy="simulation") stats = db.get_purchase_stats() assert "total" in stats assert "real" in stats assert "virtual" in stats assert "by_strategy" in stats assert stats["total"]["sets"] == 6 assert stats["real"]["sets"] == 5 assert stats["virtual"]["sets"] == 1 assert "manual" in stats["by_strategy"] assert "simulation" in stats["by_strategy"] # 하위호환 필드 assert "total_records" in stats assert stats["total_records"] == 2 mem.close() def test_upsert_strategy_performance(): """전략 성과 upsert""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() # 최초 insert db.upsert_strategy_performance( strategy="simulation", draw_no=1150, sets_count=10, total_correct=30, max_correct=5, prize_total=5000, avg_score=3.0, ) rows = db.get_strategy_performance(strategy="simulation") assert len(rows) == 1 assert rows[0]["sets_count"] == 10 assert rows[0]["avg_score"] == 3.0 # upsert (동일 strategy+draw_no) db.upsert_strategy_performance( strategy="simulation", draw_no=1150, sets_count=20, total_correct=60, max_correct=6, prize_total=10000, avg_score=4.5, ) rows = db.get_strategy_performance(strategy="simulation") assert len(rows) == 1 # 중복 없이 1개 assert rows[0]["sets_count"] == 20 assert rows[0]["avg_score"] == 4.5 mem.close() def test_update_strategy_weight(): """전략 가중치 업데이트""" import db mem = _make_mem_conn() with patch("db._conn", return_value=mem): db.init_db() # 초기값 확인 weights_before = db.get_strategy_weights() combined_before = next(w for w in weights_before if w["strategy"] == "combined") original_weight = combined_before["weight"] # 업데이트 db.update_strategy_weight( strategy="combined", weight=0.5, ema_score=0.75, total_sets=100, total_hits_3plus=20, ) weights_after = db.get_strategy_weights() combined_after = next(w for w in weights_after if w["strategy"] == "combined") assert combined_after["weight"] == 0.5 assert combined_after["ema_score"] == 0.75 assert combined_after["total_sets"] == 100 assert combined_after["total_hits_3plus"] == 20 mem.close()