"""Prüft Assets und Inhalte: Lizenzdokumentation vollständig, Verweise gültig, SVGs harmlos, keine Namen aus anderen Spielen oder Filmen.""" from __future__ import annotations import re import xml.etree.ElementTree as ET from pathlib import Path import pytest from app.config import PROJECT_ROOT STATIC = PROJECT_ROOT / "app" / "static" ASSETS = STATIC / "assets" ASSETS_DOC = PROJECT_ROOT / "docs" / "ASSETS.md" JS_ROOT = STATIC / "js" #: Begriffe aus Helldivers bzw. Starship Troopers, die im Spiel nicht vorkommen dürfen #: (Groß-/Kleinschreibung egal). Der allgemeine Tonfall darf inspiriert sein, Namen nicht. FORBIDDEN_TERMS = [ "helldiver", "super earth", "super-erde", "supererde", "stratagem", "hellpod", "terminid", "automaton", "illuminate", "managed democracy", "gelenkte demokratie", "liber-tea", "would you like to know more", "möchten sie mehr erfahren", "mobile infantry", "arachnid", "federation", "föderation", "service guarantees citizenship", "rico", "klendathu", ] def _asset_files() -> list[Path]: return sorted(p for p in ASSETS.rglob("*") if p.is_file()) def test_asset_folder_is_not_empty() -> None: assert _asset_files(), "Keine Assets gefunden" @pytest.mark.parametrize("path", _asset_files(), ids=lambda p: p.relative_to(ASSETS).as_posix()) def test_every_asset_is_documented(path: Path) -> None: documented = ASSETS_DOC.read_text(encoding="utf-8") relative = path.relative_to(ASSETS).as_posix() assert relative in documented, f"{relative} fehlt in docs/ASSETS.md" def test_referenced_asset_files_exist() -> None: manifest = (JS_ROOT / "systems" / "Assets.js").read_text(encoding="utf-8") referenced = re.findall(r"file: '([^']+)'", manifest) assert len(referenced) >= 15 missing = [f for f in referenced if not (ASSETS / f).is_file()] assert missing == [] @pytest.mark.parametrize("path", sorted(ASSETS.rglob("*.svg")), ids=lambda p: p.name) def test_svgs_are_well_formed_and_self_contained(path: Path) -> None: source = path.read_text(encoding="utf-8") root = ET.fromstring(source) # noqa: S314 – eigene, versionierte Dateien assert root.tag.endswith("svg") lowered = source.lower() # Keine Skripte, keine externen Verweise: SVGs sollen reine Grafik sein. assert " None: phaser = JS_ROOT / "lib" / "phaser.min.js" assert phaser.is_file() assert phaser.stat().st_size > 500_000 head = phaser.read_text(encoding="utf-8", errors="ignore")[:100_000] assert '"3.90.0"' in head or "3.90.0" in head assert (JS_ROOT / "lib" / "PHASER_LICENSE.md").is_file() def test_no_external_urls_in_page_or_scripts() -> None: """Das Spiel lädt nichts von fremden Servern (kein CDN, kein Tracking).""" offenders = [] for path in [*JS_ROOT.rglob("*.js"), *(PROJECT_ROOT / "app" / "templates").rglob("*.html")]: if "lib" in path.relative_to(STATIC if path.is_relative_to(STATIC) else PROJECT_ROOT).parts: continue text = path.read_text(encoding="utf-8") for match in re.findall(r"""(?:src|href)=["'](https?://[^"']+)""", text): offenders.append(f"{path.name}: {match}") if re.search(r"""\b(?:import|fetch)\s*\(?\s*["']https?://""", text): offenders.append(f"{path.name}: externer Import/Fetch") assert offenders == [] def test_no_names_from_other_games_or_films() -> None: sources = [ *JS_ROOT.rglob("*.js"), *(PROJECT_ROOT / "app" / "templates").rglob("*.html"), *ASSETS.rglob("*.svg"), ] hits = [] for path in sources: if "lib" in path.parts: continue text = path.read_text(encoding="utf-8").lower() for term in FORBIDDEN_TERMS: if re.search(rf"\b{re.escape(term)}\b", text): hits.append(f"{path.relative_to(PROJECT_ROOT).as_posix()}: {term}") assert hits == []