This commit is contained in:
Team3
2026-07-26 13:06:45 +02:00
parent 92889711a0
commit 714307f93e
11 changed files with 459 additions and 117 deletions

View File

@@ -1,8 +1,9 @@
"""Zerlegt den rohen Feature-Text in Sektionen — nur für die Anzeige.
Format: titel (eine Zeile), ziel, dann wiederholbare <!-- funktion -->-Blöcke,
denen <!-- regel -->-Blöcke zugeordnet werden, zuletzt sonstiges.
Präambel, unbekannte Marker und Regeln ohne Funktion landen in `sonstiges`.
Format: titel (eine Zeile), art, ziel, dann wiederholbare <!-- funktion -->-Blöcke;
<!-- regel -->- und <!-- flow -->-Blöcke gehören zur davorstehenden Funktion.
Präambel, unbekannte Marker und verwaiste regel/flow-Blöcke landen in `sonstiges`
(wird nicht angezeigt, aber beim Speichern erhalten).
Trennzeilen aus Bindestrichen (---) sind reine Optik und werden ignoriert.
"""
@@ -46,27 +47,24 @@ def zerlege(roh: str) -> dict:
elif schluessel == "ziel":
ziel.append(text)
elif schluessel == "funktion":
funktionen.append({"text": text, "regeln": []})
funktionen.append({"text": text, "regeln": [], "flow": []})
elif schluessel == "regel" and funktionen:
funktionen[-1]["regeln"].append(text)
else: # Präambel, unbekannter Marker, regel ohne funktion
elif schluessel == "flow" and funktionen:
funktionen[-1]["flow"].append(text)
else: # Präambel, unbekannter Marker, regel/flow ohne funktion
sonstiges.append(text)
for f in funktionen:
f["flow"] = "\n".join(f["flow"])
# Titel ist eine Zeile: erste nicht-leere
titel_zeilen = [z.strip() for t in titel for z in t.splitlines() if z.strip()]
# Funktionen-Bereich mit Markern rekonstruiert — für das Editor-Feld
teile = []
for f in funktionen:
teile.append(f"<!-- funktion -->\n{f['text']}")
for r in f["regeln"]:
teile.append(f"<!-- regel -->\n{r}")
return {
"titel": titel_zeilen[0] if titel_zeilen else "",
"art": "optional" if art and art[0].strip().lower() == "optional" else "kern",
"ziel": "\n\n".join(ziel),
"funktionen": funktionen,
"funktionen_roh": "\n".join(teile),
"sonstiges": "\n\n".join(sonstiges),
}

View File

@@ -3,6 +3,9 @@ from parser import zerlege
VOLL = """<!-- titel -->
Login
----------------------------------------
<!-- art -->
kern
----------------------------------------
<!-- ziel -->
Nutzer können sich anmelden.
----------------------------------------
@@ -12,33 +15,32 @@ Anmeldung mit E-Mail
Passwort nie loggen
<!-- regel -->
Sperre nach 5 Fehlversuchen
<!-- flow -->
- Formular öffnen
- Daten eingeben
<!-- funktion -->
Abmeldung
----------------------------------------
<!-- sonstiges -->
Offen: 2FA.
"""
def test_alle_sektionen():
s = zerlege(VOLL)
assert s["titel"] == "Login"
assert s["art"] == "kern"
assert s["ziel"] == "Nutzer können sich anmelden."
assert s["funktionen"] == [
{"text": "Anmeldung mit E-Mail", "regeln": ["Passwort nie loggen", "Sperre nach 5 Fehlversuchen"]},
{"text": "Abmeldung", "regeln": []},
{
"text": "Anmeldung mit E-Mail",
"regeln": ["Passwort nie loggen", "Sperre nach 5 Fehlversuchen"],
"flow": "- Formular öffnen\n- Daten eingeben",
},
{"text": "Abmeldung", "regeln": [], "flow": ""},
]
assert s["sonstiges"] == "Offen: 2FA."
def test_funktionen_roh_rekonstruiert_marker():
s = zerlege(VOLL)
assert s["funktionen_roh"] == (
"<!-- funktion -->\nAnmeldung mit E-Mail\n"
"<!-- regel -->\nPasswort nie loggen\n"
"<!-- regel -->\nSperre nach 5 Fehlversuchen\n"
"<!-- funktion -->\nAbmeldung"
)
def test_mehrere_flow_bloecke_werden_verbunden():
s = zerlege("<!-- funktion -->\nX\n<!-- flow -->\n- a\n<!-- flow -->\n- b\n")
assert s["funktionen"][0]["flow"] == "- a\n- b"
def test_trenner_zeilen_werden_ignoriert():
@@ -57,10 +59,10 @@ def test_unbekannter_marker_landet_in_sonstiges():
assert s["sonstiges"] == "Geheim"
def test_regel_ohne_funktion_landet_in_sonstiges():
s = zerlege("<!-- regel -->\nverwaist\n")
def test_regel_und_flow_ohne_funktion_landen_in_sonstiges():
s = zerlege("<!-- regel -->\nverwaist\n<!-- flow -->\n- auch\n")
assert s["funktionen"] == []
assert s["sonstiges"] == "verwaist"
assert s["sonstiges"] == "verwaist\n\n- auch"
def test_doppelter_marker_wird_konkateniert():
@@ -70,7 +72,7 @@ def test_doppelter_marker_wird_konkateniert():
def test_leerer_text():
s = zerlege("")
assert s == {"titel": "", "art": "kern", "ziel": "", "funktionen": [], "funktionen_roh": "", "sonstiges": ""}
assert s == {"titel": "", "art": "kern", "ziel": "", "funktionen": [], "sonstiges": ""}
def test_art_optional():