from pesis import db, demo, simulate def _conn(): conn = db.connect(":memory:") demo.build_demo(conn, seed=13, years=(2026,), matches_per_season=24) return conn def _season(conn): return conn.execute("SELECT id FROM seasons").fetchone()[0] def test_standings_conserve_games_and_points(): conn = _conn() table = simulate.standings(conn, _season(conn)) assert len(table) == 10 matches = conn.execute("SELECT COUNT(*) FROM matches").fetchone()[0] assert sum(t["games"] for t in table) == 2 * matches assert sum(t["points"] for t in table) == 2 * matches assert sum(t["run_diff"] for t in table) == 0 def test_playoff_odds_are_sane_and_deterministic(): conn = _conn() sid = _season(conn) cutoff = "2026-06-15" a = simulate.playoff_odds(conn, sid, as_of=cutoff, sims=500, seed=42) b = simulate.playoff_odds(conn, sid, as_of=cutoff, sims=500, seed=42) assert [t["odds"] for t in a] == [t["odds"] for t in b] assert any(t["remaining"] > 0 for t in a), "cutoff left no games to simulate" total = sum(t["odds"] for t in a) assert abs(total - 100 * simulate.PLAYOFF_SPOTS) < 1e-6 # the current leader should not be an underdog to the current last place assert a[0]["odds"] > a[-1]["odds"] def test_period_points_rule_3_2_1_0(): """The real rule, validated against official 2026 result boards: 3 = clean 2-0; 2 = any other win; 1 = loss with tiebreak played; 0 = loss without tiebreak. All shapes below occur in real data.""" from pesis import db as db_, ingest conn = db_.connect(":memory:") sid = ingest.upsert_season(conn, 2026, "Testisarja") matches = [ # (id, ph, pa, tiebreak, home runs, away runs, A pts, B pts) (1, 2, 0, 0, 8, 3, 3, 0), # clean win (2, 2, 1, 1, 6, 9, 2, 1), # tiebreak win DESPITE fewer runs (3, 1, 2, 1, 5, 5, 1, 2), # B wins tiebreak on equal runs (4, 1, 0, 0, 7, 7, 2, 0), # drawn period, no tiebreak: 1-0 (x-x, y odds resolve to 100/0 finals = sorted((v[-1] for v in hist["teams"].values()), reverse=True) assert finals[:simulate.PLAYOFF_SPOTS] == [100.0] * simulate.PLAYOFF_SPOTS assert set(finals[simulate.PLAYOFF_SPOTS:]) == {0.0}