from app.selection import score_candidates NOW = "2026-06-11T00:00:00Z" def _cand(kid, kw, cat, score, suggested_at): return {"id": kid, "keyword": kw, "category": cat, "score": score, "suggested_at": suggested_at} def test_dedup_excludes_recent_issued(): cands = [_cand(1, "금리", "economy", 0.9, "2026-06-11T00:00:00Z")] issued = [{"keyword": "금리", "category": "economy"}] out = score_candidates(cands, issued, prefs={}, claude_scores=None, threshold=0.0, now_iso=NOW) assert out[0]["eligible"] is False def test_freshness_recent_higher(): fresh = _cand(1, "A", "economy", 0.5, "2026-06-11T00:00:00Z") stale = _cand(2, "B", "economy", 0.5, "2026-06-04T00:00:00Z") out = {c["id"]: c for c in score_candidates([fresh, stale], [], {}, None, threshold=0.0, now_iso=NOW)} assert out[1]["breakdown"]["freshness"] > out[2]["breakdown"]["freshness"] def test_account_fit_uses_weight(): cands = [_cand(1, "A", "economy", 0.8, NOW), _cand(2, "B", "psychology", 0.8, NOW)] prefs = {"economy": 2.0, "psychology": 1.0} out = {c["id"]: c for c in score_candidates(cands, [], prefs, None, threshold=0.0, now_iso=NOW)} assert out[1]["breakdown"]["account_fit"] > out[2]["breakdown"]["account_fit"] def test_threshold_gate(): cands = [_cand(1, "A", "economy", 0.1, "2026-06-01T00:00:00Z")] out = score_candidates(cands, [], {}, None, threshold=0.6, now_iso=NOW) assert out[0]["eligible"] is False def test_claude_missing_renormalizes(): cands = [_cand(1, "A", "economy", 1.0, NOW)] out = score_candidates(cands, [], {"economy": 1.0}, None, threshold=0.0, now_iso=NOW) assert out[0]["breakdown"]["claude"] is None assert 0.0 <= out[0]["final_score"] <= 1.0 def test_claude_included_when_provided(): cands = [_cand(1, "A", "economy", 0.5, NOW)] out = score_candidates(cands, [], {"economy": 1.0}, {1: 1.0}, threshold=0.0, now_iso=NOW) assert out[0]["breakdown"]["claude"] == 1.0 def test_all_zero_prefs_no_crash(): cands = [{"id": 1, "keyword": "A", "category": "economy", "score": 0.8, "suggested_at": "2026-06-11T00:00:00Z"}] prefs = {"economy": 0.0, "psychology": 0.0} out = score_candidates(cands, [], prefs, None, threshold=0.0, now_iso="2026-06-11T00:00:00Z") assert out[0]["breakdown"]["account_fit"] == 0.0 # 0가중 → fit 0, 크래시 없음