"""Tests für die Auslosungslogik. Laufen ohne Abhängigkeiten: python tests/test_draw.py (sind aber auch pytest-kompatibel) """ from __future__ import annotations import random import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from app.draw import draw_assignment def check_mapping(mapping, ids, exclusions): assert sorted(mapping.keys()) == sorted(ids), "jeder muss genau einmal geben" assert sorted(mapping.values()) == sorted(ids), "jeder muss genau einmal gezogen werden" for giver, receiver in mapping.items(): assert giver != receiver, "niemand darf sich selbst ziehen" assert (giver, receiver) not in exclusions, "Ausschlüsse müssen gelten" def test_basically(): ids = ["a", "b", "c", "d"] mapping = draw_assignment(ids, set()) assert mapping is not None check_mapping(mapping, ids, set()) def test_mindestgroesse(): assert draw_assignment([], set()) is None assert draw_assignment(["a"], set()) is None def test_ausschluesse_werden_respektiert(): ids = ["anna", "ben", "clara", "david"] # Ehepaar: Anna und Ben dürfen sich nicht gegenseitig ziehen. exclusions = {("anna", "ben"), ("ben", "anna")} rng = random.Random(42) for _ in range(300): mapping = draw_assignment(ids, exclusions, rng=rng) assert mapping is not None check_mapping(mapping, ids, exclusions) def test_unloesbar_zwei_personen_mit_ausschluss(): ids = ["a", "b"] assert draw_assignment(ids, {("a", "b")}) is None def test_unloesbar_kein_moeglicher_empfaenger(): # a darf weder b noch c ziehen → keine gültige Auslosung möglich. ids = ["a", "b", "c"] exclusions = {("a", "b"), ("a", "c")} assert draw_assignment(ids, exclusions) is None def test_zufall_variiert(): ids = [f"p{i}" for i in range(8)] exclusions = {("p0", "p1"), ("p2", "p3")} rng = random.Random(7) results = set() for _ in range(100): mapping = draw_assignment(ids, exclusions, rng=rng) assert mapping is not None check_mapping(mapping, ids, exclusions) results.add(tuple(sorted(mapping.items()))) assert len(results) > 1, "Auslosung soll zufällig variieren" if __name__ == "__main__": failures = 0 for name, fn in sorted(globals().items()): if name.startswith("test_") and callable(fn): try: fn() print(f" ✓ {name}") except AssertionError as e: failures += 1 print(f" ✗ {name}: {e}") print("ALLE TESTS OK" if failures == 0 else f"{failures} TEST(S) FEHLGESCHLAGEN") sys.exit(1 if failures else 0)