init
This commit is contained in:
114
backend/tests/test_viewer.py
Normal file
114
backend/tests/test_viewer.py
Normal file
@@ -0,0 +1,114 @@
|
||||
"""Viewer-Service: Parser, Drift, Doku-Ordnung, Projektliste."""
|
||||
from pathlib import Path
|
||||
|
||||
import config
|
||||
import projekte
|
||||
import viewer
|
||||
|
||||
MINI = Path(__file__).parent / "fixtures" / "mini_repo"
|
||||
|
||||
|
||||
def test_lese_einheiten_mit_entscheidungen():
|
||||
text = """# Einheiten: a.py
|
||||
stand: abc
|
||||
|
||||
## a.py::eins
|
||||
beschreibung: Macht eins.
|
||||
input: x
|
||||
output: y
|
||||
entscheidungen:
|
||||
- Erste Entscheidung.
|
||||
beleg: "code hier"
|
||||
- Zweite mit Umbruch
|
||||
und Fortsetzung.
|
||||
kanten:
|
||||
- ruft-auf: a.py::zwei
|
||||
|
||||
## b.py
|
||||
beschreibung: Datei-Einheit.
|
||||
"""
|
||||
e = viewer.lese_einheiten(text)
|
||||
eins = e["a.py::eins"]
|
||||
assert eins["entscheidungen"] == ["Erste Entscheidung.", "Zweite mit Umbruch und Fortsetzung."]
|
||||
assert eins["kanten"] == [{"typ": "ruft-auf", "ziel": "a.py::zwei"}]
|
||||
assert (eins["input"], eins["output"]) == ("x", "y")
|
||||
assert e["b.py"]["beschreibung"] == "Datei-Einheit."
|
||||
|
||||
|
||||
def test_lese_kern_und_pruefung():
|
||||
kern = viewer.lese_kern("# Kern: demo\nZwei Sätze.\n\ntragende-einheiten: a.py::x, b.py::y\n")
|
||||
assert kern["titel"] == "demo" and kern["tragende_einheiten"] == ["a.py::x", "b.py::y"]
|
||||
pr = viewer.lese_pruefung("# Prüfung: demo\ntests: make test\nlint: (keins vorhanden)\n"
|
||||
"start: make dev\nhinweise:\n- Vorsicht.\n")
|
||||
assert pr["tests"] == "make test" and pr["hinweise"] == ["Vorsicht."]
|
||||
|
||||
|
||||
def test_lese_features_architektur_flows():
|
||||
b = viewer.lese_features("# Bereich: rechnen\nbeschreibung: Rechnet.\n\n"
|
||||
"## Feature: Addieren [kern]\nbeschreibung: Summen.\n\n"
|
||||
"### Kann addieren\neinheiten: a.py::eins\n")
|
||||
assert b["features"][0]["flag"] == "kern"
|
||||
assert b["features"][0]["teilfeatures"][0]["einheiten"] == ["a.py::eins"]
|
||||
a = viewer.lese_architektur("# Architektur: demo\n\n## Komponente: kernstück\n"
|
||||
"beschreibung: Trägt.\neinheiten: a.py::eins\n"
|
||||
"beziehungen:\n- nutzt: anzeige\n")
|
||||
assert a[0]["beziehungen"] == [{"typ": "nutzt", "ziel": "anzeige"}]
|
||||
f = viewer.lese_flows("# Flows: demo\n\n## Flow: ablauf\n1. Schritt eins — a.py::eins\n"
|
||||
"2. Schritt ohne Referenz\n")
|
||||
assert f[0]["schritte"][0]["einheiten"] == ["a.py::eins"]
|
||||
assert f[0]["schritte"][1]["einheiten"] == []
|
||||
|
||||
|
||||
def test_code_extrahieren():
|
||||
assert "return a + b" in viewer.code_extrahieren(MINI, "rechner.py::addiere")
|
||||
assert viewer.code_extrahieren(MINI, "rechner.py::BASIS").startswith("BASIS = 10")
|
||||
assert viewer.code_extrahieren(MINI, "rechner.py::gibtsnicht") == ""
|
||||
assert viewer.code_extrahieren(MINI, "wegdatei.py::x") == ""
|
||||
assert "def merke" in viewer.code_extrahieren(MINI, "rechner.py::Speicher.merke")
|
||||
|
||||
|
||||
async def test_lade_projekt_und_drift(gescanntes_repo):
|
||||
wurzel, git = gescanntes_repo
|
||||
projekt = viewer.lade_projekt(wurzel)
|
||||
assert "rechner.py::addiere" in projekt["einheiten"]
|
||||
assert projekt["kern"]["titel"] == "mini"
|
||||
assert projekt["staende"]["rechner.py"]
|
||||
assert viewer.drift(wurzel, projekt["staende"])["veraltet"] == []
|
||||
|
||||
(wurzel / "rechner.py").write_text((wurzel / "rechner.py").read_text() + "\nX2 = 2\n")
|
||||
git("add", "-A")
|
||||
git("commit", "-m", "aenderung")
|
||||
d = viewer.drift(wurzel, projekt["staende"])
|
||||
assert d["veraltet"] == ["rechner.py"] # anzeige.py unverändert
|
||||
|
||||
|
||||
def test_doku_ordnung_mit_zyklus():
|
||||
projekt = {
|
||||
"bereiche": [
|
||||
{"name": "oben", "features": [{"teilfeatures": [{"einheiten": ["a.py::x"]}]}]},
|
||||
{"name": "unten", "features": [{"teilfeatures": [{"einheiten": ["b.py::y"]}]}]},
|
||||
],
|
||||
"einheiten": {
|
||||
"a.py::x": {"kanten": [{"typ": "ruft-auf", "ziel": "b.py::y"}]},
|
||||
"b.py::y": {"kanten": []},
|
||||
},
|
||||
}
|
||||
assert viewer.doku_ordnung(projekt) == ["unten", "oben"] # Fundament zuerst
|
||||
# Zyklus: beide nutzen einander → deterministisch, beide enthalten
|
||||
projekt["einheiten"]["b.py::y"]["kanten"] = [{"typ": "nutzt", "ziel": "a.py::x"}]
|
||||
ordnung = viewer.doku_ordnung(projekt)
|
||||
assert sorted(ordnung) == ["oben", "unten"] and len(ordnung) == 2
|
||||
|
||||
|
||||
def test_projektliste(tmp_path, monkeypatch):
|
||||
echt = tmp_path / "echt"
|
||||
echt.mkdir()
|
||||
(tmp_path / "kopie").mkdir()
|
||||
datei = tmp_path / "projekte.txt"
|
||||
datei.write_text(f"# Kommentar\n{echt}\n{tmp_path}/weg\n{tmp_path}/kopie\n{echt}\n")
|
||||
monkeypatch.setattr(config, "PROJEKTE_DATEI", datei)
|
||||
liste = projekte.lade()
|
||||
assert [p.get("fehler") is None for p in liste] == [True, False, True, False]
|
||||
assert "existiert nicht" in liste[1]["fehler"]
|
||||
assert "Namenskollision" in liste[3]["fehler"]
|
||||
assert projekte.finde("echt") == echt and projekte.finde("weg") is None
|
||||
Reference in New Issue
Block a user