refactor(lotto): Phase 1 코드리뷰 반영 (로컬 RNG·write-once·가드·테스트 보강)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from app import backtest as bt
|
||||
from app.analyzer import build_analysis_cache, score_combination
|
||||
from app.analyzer import build_analysis_cache, build_number_weights, score_combination
|
||||
|
||||
|
||||
def _toy_draws(n=120):
|
||||
@@ -38,16 +38,17 @@ def test_grade_tickets_histogram_and_prizes():
|
||||
|
||||
def test_purchase_tickets_distinct_and_count():
|
||||
draws = _toy_draws()
|
||||
cache = bt.build_analysis_cache(draws)
|
||||
nw = bt.build_number_weights(cache)
|
||||
cache = build_analysis_cache(draws)
|
||||
nw = build_number_weights(cache)
|
||||
pool = bt.generate_pool(cache, nw, n=2000, seed=7)
|
||||
W = [0.25, 0.30, 0.20, 0.15, 0.10]
|
||||
bought = bt.purchase_tickets(pool, cache, W, k=50)
|
||||
assert len(bought) == 50
|
||||
assert len({tuple(t) for t in bought}) == 50 # distinct
|
||||
# W로 랭킹된 상위 → 평균 분석치가 풀 평균보다 높아야
|
||||
# W로 랭킹된 상위 k → 평균 점수가 풀 전체 평균 이상이어야
|
||||
avg_bought = sum(score_combination(t, cache, W)["score_total"] for t in bought) / 50
|
||||
assert avg_bought > 0
|
||||
avg_pool = sum(score_combination(t, cache, W)["score_total"] for t in pool) / len(pool)
|
||||
assert avg_bought >= avg_pool
|
||||
|
||||
|
||||
def test_random_null_and_coverage_distinct():
|
||||
@@ -57,3 +58,24 @@ def test_random_null_and_coverage_distinct():
|
||||
flat = {n for t in cov for n in t}
|
||||
assert len(cov) == 9 and len({tuple(t) for t in cov}) == 9
|
||||
assert len(flat) >= 40 # 커버리지 전략은 번호를 넓게 퍼뜨림
|
||||
|
||||
|
||||
def test_generate_pool_partial_fill(monkeypatch):
|
||||
"""weighted_sample_6이 항상 같은 조합만 반환하도록 패치 → cap에 먼저 걸려 len < n — 예외 없이 반환."""
|
||||
import random as _r
|
||||
_r.seed(42)
|
||||
tiny_draws = [(i, sorted(_r.sample(range(1, 46), 6))) for i in range(1, 10)]
|
||||
cache = build_analysis_cache(tiny_draws)
|
||||
nw = build_number_weights(cache)
|
||||
|
||||
# weighted_sample_6을 항상 동일한 하나의 조합만 반환하도록 패치
|
||||
# → 두 번째 시도부터 seen에 막혀 n개를 채울 수 없고 cap=n*4 이후 종료
|
||||
import app.backtest as _bt_mod
|
||||
monkeypatch.setattr(_bt_mod, "weighted_sample_6", lambda _w: [1, 2, 3, 4, 5, 6])
|
||||
|
||||
n = 50
|
||||
pool = bt.generate_pool(cache, nw, n=n, seed=0)
|
||||
# 예외 없이 반환해야 하고, 결과는 n 미만이어야 하며 모두 distinct
|
||||
assert isinstance(pool, list)
|
||||
assert len(pool) < n
|
||||
assert len({tuple(t) for t in pool}) == len(pool)
|
||||
|
||||
Reference in New Issue
Block a user