Files
Projektwissen/tests/test_pruefe_prozesse.py
T
DanielandClaude Opus 5.5 31131cc5c3 Prozessbibliothek als eigenes Repository auslagern (#9)
- ADR 0004 ersetzt ADR 0003: Die Prozessmodelle liegen im Repository
  AG_Prozesse/Prozessbibliothek, geklont nach Prozessbibliothek/ (neuer
  Eintrag in workspace.toml, .gitignore). prozesse/ ist entfernt; das
  Ablageformat (Ordner je Prozess, drei Dateien, Status) bleibt.
- pruefe_prozesse.py prüft den Klon (Ort über setup_workspace.repos_root),
  lässt Punkt-Ordner wie .git aus und erlaubt in der Wurzel nur die
  Repo-Dateien. Fehlt der Klon, gibt es einen Hinweis statt eines Befunds;
  pytest warnt dann.
- einlesen.py sucht den Bestand in der Bibliothek und nennt Treffer als
  Prozessbibliothek/<name>/, auch wenn der Klon woanders liegt.
- Regeln aus prozesse/README.md nach docs/leitfaden/08_prozessbibliothek.md,
  inklusive Ablauf bei Konverteränderungen (zwei Pull Requests).
- Verweise in AGENTS.md, README, Skills, Leitfäden, Vorlagen, Fallstricken
  und STATUS nachgezogen.
- Tests: python -m pytest -q -> 88 bestanden, 1 xfail (#8), 1 Warnung
  (Bibliothek noch nicht geklont).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 09:40:52 +02:00

147 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests für scripts/pruefe_prozesse.py und für den Bestand der Prozessbibliothek – reines Python/pytest."""
import sys
import warnings
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))
import pruefe_prozesse as pp # noqa: E402
MODELL = """Prozess: Testprozess
S1 Start: Beginn
S2 Task: Etwas tun
S3 Ende: Fertig
"""
STECKBRIEF = """# Testprozess
| | |
|---|---|
| Status | {status} |
| Stand | 2026-09-23 |
"""
def lege_prozess_an(wurzel, name="test-prozess", status="Entwurf"):
ordner = wurzel / name
ordner.mkdir()
md = ordner / f"{name}.md"
md.write_text(MODELL, encoding="utf-8")
(ordner / f"{name}.bpmn").write_bytes(pp.erzeuge_bpmn(md))
(ordner / "README.md").write_text(STECKBRIEF.format(status=status), encoding="utf-8")
return ordner
def test_bestand_der_bibliothek_und_beispiele_ist_konsistent():
"""Prüft, dass alle Prozessordner der geklonten Prozessbibliothek und die Skill-Beispiele ohne Befund sind."""
if not pp.BIBLIOTHEK.is_dir():
warnings.warn(f"Prozessbibliothek nicht geklont ({pp.BIBLIOTHEK}) – nur die Skill-Beispiele geprüft. "
"Klonen mit: python scripts/setup_workspace.py")
assert pp.pruefe_alles() == []
def test_bibliothek_liegt_als_klon_neben_projektwissen():
"""Prüft, dass die Prozessbibliothek unter dem Klon-Ordner aus workspace.toml/workspace.local.toml gesucht wird."""
import setup_workspace
assert pp.BIBLIOTHEK == setup_workspace.repos_root() / "Prozessbibliothek"
def test_prozessordner_ohne_punktordner(tmp_path):
"""Prüft, dass .git und andere Punkt-Ordner im Bibliotheks-Klon nicht als Prozess gelten."""
lege_prozess_an(tmp_path)
(tmp_path / ".git").mkdir()
(tmp_path / ".gitea").mkdir()
assert [o.name for o in pp.prozessordner(tmp_path)] == ["test-prozess"]
def test_fremde_datei_in_der_bibliothekswurzel_wird_gemeldet(tmp_path):
"""Prüft, dass in der Wurzel der Bibliothek nur die Repo-Dateien erlaubt sind und alles andere gemeldet wird."""
lege_prozess_an(tmp_path)
for erlaubt in ("README.md", "AGENTS.md", "CLAUDE.md", ".gitattributes", ".gitignore"):
(tmp_path / erlaubt).write_text("", encoding="utf-8")
(tmp_path / "antrag.bpmn").write_text("", encoding="utf-8")
befunde = pp.pruefe_bibliothek(tmp_path)
assert len(befunde) == 1 and "antrag.bpmn" in befunde[0]
def test_fehlende_bibliothek_ist_kein_befund_aber_ein_hinweis(tmp_path):
"""Prüft, dass eine nicht geklonte Bibliothek keinen Befund, aber einen Hinweis auf setup_workspace.py ergibt."""
fehlt = tmp_path / "Prozessbibliothek"
assert pp.pruefe_bibliothek(fehlt) == []
assert "setup_workspace.py" in pp.hinweis_bibliothek(fehlt)
fehlt.mkdir()
assert pp.hinweis_bibliothek(fehlt) == ""
def test_es_gibt_mindestens_ein_beispiel():
"""Prüft, dass der Abgleich .md/.bpmn wenigstens an den Skill-Beispielen tatsächlich greift."""
assert pp.beispiele(), "keine Beispiele in .agents/skills/sn-bpmn/beispiele/"
def test_gueltiger_prozessordner_hat_keine_befunde(tmp_path):
"""Prüft, dass ein vollständiger Ordner mit aktueller .bpmn und gültigem Status durchgeht."""
assert pp.pruefe_ordner(lege_prozess_an(tmp_path)) == []
def test_status_abgenommen_ist_gueltig(tmp_path):
"""Prüft, dass der Status 'abgenommen' akzeptiert wird."""
assert pp.pruefe_ordner(lege_prozess_an(tmp_path, status="abgenommen")) == []
def test_unbekannter_status_wird_gemeldet(tmp_path):
"""Prüft, dass ein Status außerhalb von Entwurf/abgenommen gemeldet wird."""
befunde = pp.pruefe_ordner(lege_prozess_an(tmp_path, status="fertig"))
assert any("Status 'fertig' unbekannt" in b for b in befunde)
def test_fehlende_statuszeile_wird_gemeldet(tmp_path):
"""Prüft, dass ein Steckbrief ohne Statuszeile gemeldet wird."""
ordner = lege_prozess_an(tmp_path)
(ordner / "README.md").write_text("# Testprozess\n", encoding="utf-8")
assert any("Status | … |' fehlt" in b for b in pp.pruefe_ordner(ordner))
def test_ungueltiger_ordnername_wird_gemeldet(tmp_path):
"""Prüft, dass Großbuchstaben oder Unterstriche im Ordnernamen gemeldet werden."""
befunde = pp.pruefe_ordner(lege_prozess_an(tmp_path, name="Antrag_Pruefen"))
assert any("Ordnername" in b for b in befunde)
def test_fehlende_bpmn_wird_gemeldet(tmp_path):
"""Prüft, dass ein Ordner ohne erzeugte .bpmn gemeldet wird."""
ordner = lege_prozess_an(tmp_path)
(ordner / "test-prozess.bpmn").unlink()
befunde = pp.pruefe_ordner(ordner)
assert any("test-prozess.bpmn fehlt" in b for b in befunde)
def test_fremde_datei_im_prozessordner_wird_gemeldet(tmp_path):
"""Prüft, dass zusätzliche Dateien (etwa eine Original-PDF) im Prozessordner gemeldet werden."""
ordner = lege_prozess_an(tmp_path)
(ordner / "quelle.pdf").write_bytes(b"%PDF")
assert any("quelle.pdf gehört nicht hierher" in b for b in pp.pruefe_ordner(ordner))
def test_veraltete_bpmn_wird_gemeldet(tmp_path):
"""Prüft, dass eine .bpmn gemeldet wird, die nach einer Änderung der .md nicht neu erzeugt wurde."""
ordner = lege_prozess_an(tmp_path)
md = ordner / "test-prozess.md"
md.write_text(MODELL.replace("Etwas tun", "Etwas anderes tun"), encoding="utf-8")
assert any("passt nicht zu test-prozess.md" in b for b in pp.pruefe_ordner(ordner))
def test_zeilenenden_der_bpmn_spielen_keine_rolle(tmp_path):
"""Prüft, dass eine unter Windows mit CRLF ausgecheckte .bpmn nicht als veraltet gilt."""
ordner = lege_prozess_an(tmp_path)
bpmn = ordner / "test-prozess.bpmn"
bpmn.write_bytes(bpmn.read_bytes().replace(b"\n", b"\r\n"))
assert pp.pruefe_ordner(ordner) == []
def test_nicht_umwandelbare_md_wird_gemeldet(tmp_path):
"""Prüft, dass eine .md mit Syntaxfehler (doppelte Schritt-ID) als Befund statt als Absturz endet."""
ordner = lege_prozess_an(tmp_path)
(ordner / "test-prozess.md").write_text(MODELL + "S2 Task: Noch einmal S2\n", encoding="utf-8")
assert any("lässt sich nicht umwandeln" in b for b in pp.pruefe_ordner(ordner))