61 lines
2.0 KiB
Python
61 lines
2.0 KiB
Python
"""Architektur-Tests: Die Physik-Schicht bleibt frei von pygame und fremden Bibliotheken.
|
|
|
|
Anforderung: Die gesamte Physik darf nur das Standardmodul ``math`` verwenden
|
|
(zusätzlich ``typing``/``dataclasses`` für Typangaben und Datenstrukturen). Diese Tests
|
|
prüfen das statisch über den Syntaxbaum und zur Laufzeit in einem frischen Interpreter.
|
|
"""
|
|
|
|
import ast
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
SOURCE_ROOT = Path(__file__).resolve().parents[1] / "src" / "sandbox"
|
|
PHYSICS_FILES = sorted((SOURCE_ROOT / "physics").glob("*.py"))
|
|
PURE_FILES = [*PHYSICS_FILES, SOURCE_ROOT / "config.py"]
|
|
|
|
ALLOWED_STDLIB = {"__future__", "math", "typing", "dataclasses"}
|
|
ALLOWED_PROJECT = {"sandbox.config"}
|
|
|
|
|
|
def _imported_modules(path: Path) -> set[str]:
|
|
tree = ast.parse(path.read_text(encoding="utf-8"))
|
|
modules: set[str] = set()
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Import):
|
|
modules.update(alias.name for alias in node.names)
|
|
elif isinstance(node, ast.ImportFrom):
|
|
modules.add(node.module or "")
|
|
return modules
|
|
|
|
|
|
@pytest.mark.parametrize("path", PURE_FILES, ids=lambda path: path.name)
|
|
def test_physics_and_config_import_only_allowed_modules(path: Path) -> None:
|
|
forbidden = {
|
|
module
|
|
for module in _imported_modules(path)
|
|
if module not in ALLOWED_STDLIB
|
|
and module not in ALLOWED_PROJECT
|
|
and not module.startswith("sandbox.physics")
|
|
}
|
|
assert not forbidden, f"{path.name} importiert nicht erlaubte Module: {forbidden}"
|
|
|
|
|
|
def test_physics_files_were_found() -> None:
|
|
assert len(PHYSICS_FILES) >= 8
|
|
|
|
|
|
def test_importing_the_physics_package_does_not_load_pygame() -> None:
|
|
code = "import sys, sandbox.physics, sandbox.config; print('pygame' in sys.modules)"
|
|
result = subprocess.run(
|
|
[sys.executable, "-c", code],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
env={**os.environ, "PYTHONPATH": str(SOURCE_ROOT.parent)},
|
|
)
|
|
assert result.stdout.strip() == "False"
|