Files
2026-09-24 17:57:54 +02:00

95 lines
3.2 KiB
Python

"""Tests für Namensbereinigung und Plausibilitätsprüfung (ohne Flask)."""
from __future__ import annotations
import pytest
from app.config import GAME_RULE_DEFAULTS
from app.validation import (
NAME_MAX_LENGTH,
PlausibilityRules,
ScoreSubmission,
SubmissionError,
check_plausibility,
parse_submission,
sanitize_name,
)
RULES = PlausibilityRules.from_config(GAME_RULE_DEFAULTS)
@pytest.mark.parametrize(
("raw", "expected"),
[
("Ada", "Ada"),
(" Max Muster ", "Max Muster"),
("Jürg Größli", "Jürg Größli"),
("Fullwidth", "Fullwidth"),
("Null\x00Byte", "NullByte"),
("Zero\u200bWidth", "ZeroWidth"),
("Bidi\u202eTrick", "BidiTrick"),
("Tab\tNeu\nZeile", "TabNeuZeile"),
("<script>alert(1)</script>", "scriptalert1script"),
("O'Neil-Test!?", "O'Neil-Test!?"),
("Emoji 🚀 Held", "Emoji Held"),
("", ""),
],
)
def test_sanitize_name(raw: str, expected: str) -> None:
assert sanitize_name(raw) == expected
def _payload(**overrides: object) -> dict:
payload: dict = {"name": "Ada", "score": 100, "wave": 2, "duration_s": 60, "run_token": "t"}
payload.update(overrides)
return payload
def test_parse_submission_valid() -> None:
submission = parse_submission(_payload(name=" Ada "), RULES)
assert submission == ScoreSubmission("Ada", 100, 2, 60, "t")
def test_parse_submission_name_exactly_max_length() -> None:
name = "N" * NAME_MAX_LENGTH
assert parse_submission(_payload(name=name), RULES).name == name
def test_parse_submission_collects_errors() -> None:
with pytest.raises(SubmissionError) as info:
parse_submission(_payload(name="", score=-1, wave=0), RULES)
assert set(info.value.fields) == {"name", "score", "wave"}
def _submission(score: int, wave: int, duration_s: int) -> ScoreSubmission:
return ScoreSubmission("Ada", score, wave, duration_s, "t")
def test_plausible_submission() -> None:
assert check_plausibility(_submission(2_000, 3, 120), elapsed_s=150, rules=RULES) is None
def test_duration_may_be_shorter_than_elapsed_because_of_pauses() -> None:
assert check_plausibility(_submission(500, 2, 60), elapsed_s=3_000, rules=RULES) is None
def test_duration_longer_than_elapsed_is_implausible() -> None:
assert check_plausibility(_submission(500, 2, 600), elapsed_s=100, rules=RULES) is not None
def test_duration_within_tolerance_is_accepted() -> None:
tolerance = RULES.duration_tolerance_seconds
assert check_plausibility(_submission(500, 2, 100 + tolerance), 100, RULES) is None
def test_score_ceiling_depends_on_duration() -> None:
ceiling = RULES.score_flat_allowance + 100 * RULES.score_max_points_per_second
assert check_plausibility(_submission(ceiling, 5, 100), 200, RULES) is None
assert check_plausibility(_submission(ceiling + 1, 5, 100), 200, RULES) is not None
def test_high_wave_needs_minimum_time() -> None:
assert check_plausibility(_submission(10, 50, 10), 500, RULES) is not None
min_time = 49 * RULES.wave_min_seconds
assert check_plausibility(_submission(10, 50, min_time), min_time + 10, RULES) is None