"""Meisterschaftsberechnung (AP 3) — mit PLATZHALTER-Punktetabelle (O-1 offen).""" from datetime import date from decimal import Decimal from sqlalchemy import select from oamc.meisterschaft.berechnung import ( PLATZHALTER_PUNKTETABELLE, berechne_stand, gewertete_laeufe, punkte_fuer_platz, ) from oamc.models import Meisterschaft from oamc.models.enums import VeranstaltungStatus from tests import factories as f def test_punkte_fuer_platz_platzhalter(): assert punkte_fuer_platz(1) == Decimal(25) assert punkte_fuer_platz(10) == Decimal(6) assert punkte_fuer_platz(99) == Decimal(1) assert punkte_fuer_platz(None) == Decimal(0) def test_streichresultate_tabelle(): tab = {"12": 8, "9": 7, "4": 2} assert gewertete_laeufe(12, tab) == 8 assert gewertete_laeufe(10, tab) == 7 # naechstkleinerer Schluessel (9) assert gewertete_laeufe(3, tab) == 3 # unterhalb der Tabelle: kein Streichresultat def _lauf(db, k, ergebnisse, *, datum, zaehlt=True): """ergebnisse = [(fahrer, platz), ...]""" v = f.veranstaltung(db, datum=datum, status=VeranstaltungStatus.FINAL) t = f.turnier(db, v, zaehlt_meisterschaft=zaehlt) for i, (fahrer, platz) in enumerate(ergebnisse, start=1): s = f.start(db, t, fahrer, k, startnummer=i) e = f.ergebnis(db, s, zeit=Decimal("100"), fehler=0) e.platzierung = platz db.flush() return t def test_stand_summiert_punkte_und_zaehlt_siege(seed_2026): db = seed_2026 k = f.klasse(db, "J 3") a = f.fahrer(db, "Sieger", "Sina", 2014) b = f.fahrer(db, "Zweite", "Zoe", 2014) _lauf(db, k, [(a, 1), (b, 2)], datum=date(2026, 4, 1)) _lauf(db, k, [(a, 1), (b, 2)], datum=date(2026, 5, 1)) m = db.scalars( select(Meisterschaft).where(Meisterschaft.bezeichnung == "HTH Jugend J 3 2026") ).one() bericht = berechne_stand(db, m.id) zeilen = {z.fahrer_id: z for z in bericht.zeilen} assert zeilen[a.id].platz == 1 assert zeilen[a.id].punkte_gesamt == Decimal(50) # 2x Platz 1 = 2x25 assert zeilen[a.id].anzahl_siege == 2 assert bericht.hinweise # O-1 Platzhalter-Warnung def test_tie_break_majoritaet_der_siege(seed_2026): db = seed_2026 k = f.klasse(db, "J 3") a = f.fahrer(db, "Aaa", "A", 2014) b = f.fahrer(db, "Bbb", "B", 2014) # beide sammeln gleich viele Punkte, aber A hat mehr Siege _lauf(db, k, [(a, 1), (b, 6)], datum=date(2026, 4, 1)) # A:25 B:10 _lauf(db, k, [(b, 1), (a, 6)], datum=date(2026, 5, 1)) # B:25 A:10 _lauf(db, k, [(a, 1), (b, 1)], datum=date(2026, 6, 1)) # beide 25, beide Sieg _lauf(db, k, [(a, 1), (b, 4)], datum=date(2026, 6, 15)) # A:25 (Sieg) B:13 m = db.scalars( select(Meisterschaft).where(Meisterschaft.bezeichnung == "HTH Jugend J 3 2026") ).one() bericht = berechne_stand(db, m.id) assert bericht.zeilen[0].fahrer_id == a.id assert bericht.zeilen[0].anzahl_siege > bericht.zeilen[1].anzahl_siege def test_laeufe_ohne_meisterschaft_zaehlen_nicht(seed_2026): db = seed_2026 k = f.klasse(db, "J 3") a = f.fahrer(db, "Solo", "S", 2014) _lauf(db, k, [(a, 1)], datum=date(2026, 4, 1), zaehlt=False) m = db.scalars( select(Meisterschaft).where(Meisterschaft.bezeichnung == "HTH Jugend J 3 2026") ).one() bericht = berechne_stand(db, m.id) assert bericht.laeufe_gesamt == 0 assert bericht.zeilen == []