96 lines
3.1 KiB
Python
96 lines
3.1 KiB
Python
"""Schneller Selbsttest der Kern-Engine (ohne Framework, ohne pytest).
|
||
|
||
Aufruf: python tests/test_engine.py
|
||
"""
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||
|
||
from app import engine
|
||
|
||
SCHEMA = {
|
||
"slug": "test-stationen",
|
||
"title": "Test-Stationen",
|
||
"columns": [
|
||
{"key": "nr", "label": "Nr.", "type": "number"},
|
||
{"key": "titel", "label": "Titel", "type": "text"},
|
||
{"key": "link", "label": "Link", "type": "url"},
|
||
{"key": "bewertung", "label": "Bewertung", "type": "rating_5"},
|
||
],
|
||
}
|
||
|
||
|
||
def test_slugify():
|
||
assert engine.slugify("Projekttage Straßenfotografie 2026!") == "projekttage-strassenfotografie-2026"
|
||
assert engine.column_key("Nr.") == "nr"
|
||
|
||
|
||
def test_parse_semikolon_bom():
|
||
raw = "Nr.;Titel;Link;Bewertung\r\n1;Kamera hält;https://example.org/a;4\r\n".encode("utf-8-sig")
|
||
header, rows = engine.parse_csv(raw)
|
||
assert header == ["Nr.", "Titel", "Link", "Bewertung"]
|
||
assert rows == [["1", "Kamera hält", "https://example.org/a", "4"]]
|
||
|
||
|
||
def test_parse_cp1252_komma():
|
||
raw = "Nr.,Titel,Link,Bewertung\n2,Straße üben,https://example.org/b,5\n".encode("cp1252")
|
||
header, rows = engine.parse_csv(raw)
|
||
assert rows[0][1] == "Straße üben"
|
||
|
||
|
||
def test_validate_ok_und_fehler():
|
||
header = ["Nr.", "Titel", "Link", "Bewertung"]
|
||
records, errors, warnings = engine.validate_and_map(
|
||
SCHEMA, header, [["1", "A", "https://example.org", "3"], ["2", "B", "", ""]]
|
||
)
|
||
assert not errors and len(records) == 2
|
||
|
||
_, errors, _ = engine.validate_and_map(
|
||
SCHEMA, header, [["x", "A", "example.org", "7"]]
|
||
)
|
||
assert len(errors) == 3 # Zahl, URL, Bewertung
|
||
|
||
_, errors, _ = engine.validate_and_map(SCHEMA, ["Nr.", "Titel"], [])
|
||
assert any("fehlt" in e for e in errors)
|
||
|
||
|
||
def test_warnung_unbekannte_spalte():
|
||
header = ["Nr.", "Titel", "Link", "Bewertung", "Notizen"]
|
||
_, errors, warnings = engine.validate_and_map(SCHEMA, header, [["1", "A", "", ""]])
|
||
assert not errors
|
||
assert any("Notizen" in w for w in warnings)
|
||
|
||
|
||
def test_render():
|
||
records, errors, _ = engine.validate_and_map(
|
||
SCHEMA,
|
||
["Nr.", "Titel", "Link", "Bewertung"],
|
||
[["1", "Goldener Schnitt", "https://youtu.be/abc123", "4"]],
|
||
)
|
||
assert not errors
|
||
html = engine.render_page(SCHEMA, records, version_label="2026-07-05 12:00")
|
||
assert "<svg" in html # QR-Code eingebettet
|
||
assert "Test-Stationen" in html
|
||
assert "★★★★☆" in html
|
||
assert "https://youtu.be/abc123" in html
|
||
|
||
|
||
def test_template_csv():
|
||
raw = engine.template_csv(SCHEMA)
|
||
assert raw.startswith("".encode("utf-8")) # BOM fuer Excel
|
||
assert b"Nr.;Titel;Link;Bewertung" in raw
|
||
|
||
|
||
if __name__ == "__main__":
|
||
failed = 0
|
||
for name, fn in sorted(globals().items()):
|
||
if name.startswith("test_") and callable(fn):
|
||
try:
|
||
fn()
|
||
print(f"OK {name}")
|
||
except AssertionError as exc:
|
||
failed += 1
|
||
print(f"FAIL {name}: {exc}")
|
||
sys.exit(1 if failed else 0)
|