- beispiele/referenz_gewannenfestlegung.md/.bpmn: aus dem ersten echten Einlese-Durchgang (input/Gewannenvermessung.md), als „Test“ markiert, fachlich nicht abgenommen. 4 Lanes, externer Pool, 14 Gateways, verschachtelte Varianten; Byte-Vergleich über pruefe_prozesse.py. - tests/test_referenzmodelle.py: je Referenzmodell keine Lane „Nicht zugeordnet“, höchstens vier Kanten je Gateway, keine Kante durch eine Raute (Geometrie aus test_md_to_bpmn.py übernommen). - Gefunden: Kante S12→S13 läuft durch die Raute von S13 – als xfail(strict=True) mit Verweis auf #8. AGENTS.md regelt, dass xfail nur für so erfasste Konverterfehler an Referenzmodellen zulässig ist. - Anleitung, Fallstricke (zwei Einträge), STATUS. - Tests: python -m pytest -q -> 82 bestanden, 1 xfail (#8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
3.0 KiB
Python
66 lines
3.0 KiB
Python
"""Strukturtests für die Referenzmodelle (.agents/skills/sn-bpmn/beispiele/referenz_*.md) – reines Python/pytest.
|
||
|
||
Die Referenzmodelle sind echte, größere Prozesse. Der Byte-Vergleich in test_pruefe_prozesse.py meldet jede
|
||
Änderung an der Ausgabe von md_to_bpmn.py; diese Tests prüfen zusätzlich, ob das Ergebnis danach noch den
|
||
Modellierregeln und den Grenzen von PICTURE genügt – auch wenn die .bpmn bewusst neu erzeugt wurde.
|
||
"""
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
SKILL = ROOT / ".agents" / "skills" / "sn-bpmn"
|
||
sys.path.insert(0, str(SKILL))
|
||
|
||
import md_to_bpmn as m # noqa: E402
|
||
from test_md_to_bpmn import _kante_kreuzt_gateway # noqa: E402 (dieselbe Geometrieprüfung wie dort)
|
||
|
||
REFERENZEN = sorted((SKILL / "beispiele").glob("referenz_*.md"))
|
||
GATEWAYS = ("exclusiveGateway", "inclusiveGateway", "parallelGateway", "eventBasedGateway")
|
||
|
||
# Bekannte, noch nicht behobene Konverterfehler je Referenzmodell. strict=True: Sobald der Fehler behoben ist,
|
||
# schlägt der Test als XPASS fehl – dann den Eintrag hier entfernen. Nie verwenden, um neue Fehler zu verstecken.
|
||
BEKANNTE_KANTEN_DURCH_GATEWAY = {
|
||
"referenz_gewannenfestlegung": "Issue #8: Kante S12→S13 (Ja) läuft senkrecht durch die Raute von S13",
|
||
}
|
||
|
||
|
||
def mit_bekannten_fehlern(bekannt):
|
||
return [pytest.param(md, id=md.stem, marks=pytest.mark.xfail(reason=bekannt[md.stem], strict=True))
|
||
if md.stem in bekannt else pytest.param(md, id=md.stem) for md in REFERENZEN]
|
||
|
||
|
||
def baue(md):
|
||
meta, steps, order, externals = m.parse_markdown(md.read_text(encoding="utf-8"))
|
||
return m.build_bpmn(meta, steps, order, externals)
|
||
|
||
|
||
def test_es_gibt_mindestens_ein_referenzmodell():
|
||
"""Prüft, dass die Strukturtests tatsächlich an einem Referenzmodell laufen."""
|
||
assert REFERENZEN
|
||
|
||
|
||
@pytest.mark.parametrize("md", REFERENZEN, ids=lambda p: p.stem)
|
||
def test_jedes_element_hat_eine_zustaendigkeit(md):
|
||
"""Prüft, dass im Referenzmodell kein Element in der Lane 'Nicht zugeordnet' landet."""
|
||
lanes = [lane.get("name") for lane in baue(md).iter(f"{{{m.NS['bpmn']}}}lane")]
|
||
assert lanes, "Referenzmodell ohne Lanes"
|
||
assert m.UNASSIGNED_LANE not in lanes
|
||
|
||
|
||
@pytest.mark.parametrize("md", REFERENZEN, ids=lambda p: p.stem)
|
||
def test_kein_gateway_hat_mehr_als_vier_kanten(md):
|
||
"""Prüft Modellierregel 4: kein Gateway im Referenzmodell braucht mehr als die vier Anschlusspunkte von PICTURE."""
|
||
defs = baue(md)
|
||
for tag in GATEWAYS:
|
||
for gateway in defs.iter(f"{{{m.NS['bpmn']}}}{tag}"):
|
||
kanten = gateway.findall(f"{{{m.NS['bpmn']}}}incoming") + gateway.findall(f"{{{m.NS['bpmn']}}}outgoing")
|
||
assert len(kanten) <= 4, f"{gateway.get('id')} hat {len(kanten)} Kanten"
|
||
|
||
|
||
@pytest.mark.parametrize("md", mit_bekannten_fehlern(BEKANNTE_KANTEN_DURCH_GATEWAY))
|
||
def test_keine_kante_fuehrt_durchs_innere_eines_gateways(md):
|
||
"""Prüft, dass im Referenzmodell keine Kante quer durch eine Raute läuft (Fallstrick Gateway-Kantenführung)."""
|
||
assert _kante_kreuzt_gateway(baue(md), m.NS) is None
|