Automatischer Push: 11 Datei(en) geändert
- .claude/agents/planer.md - .claude/workflows/plankritik.js - .vault-tools/plan-kopie/LIESMICH.md - .vault-tools/plan-kopie/mutanten_lauf.py - .vault-tools/plan-kopie/mutanten_lauf_ENTWURF.md - .vault-tools/plan-kopie/mutanten_lauf_kopie.sh - .vault-tools/plan-kopie/mutanten_lauf_treiber.py - .vault-tools/workflow-pruefung/faelle_workflows.mjs - .vault-tools/workflow-pruefung/mutanten_workflows.py - AI/Regelwerk/codeworkflow.md - CLAUDE.md Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
3b7128c9e1
commit
1be4f913aa
11 files changed
+2214
-10
No files matched your search
@@ -0,0 +1,964 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Treiber fuer mutanten_lauf.py: 34 Angriffsfaelle auf einer Wegwerfkopie.
|
||||
|
||||
Zweck: Baut in einem Temp-Ordner unter /tmp ein kleines Testprojekt, fuehrt
|
||||
mutanten_lauf.py je Fall mit einer eigenen mutanten.toml aus und vergleicht
|
||||
Exit-Code und ein Meldungsstueck gegen die Erwartung aus dem Entwurf,
|
||||
Abschnitt 6. Nach jedem Fall wird geprueft, dass jede Datei des kleinen
|
||||
Projekts wieder byte-gleich mit dem Ausgangsstand ist.
|
||||
|
||||
Aufruf: python mutanten_lauf_treiber.py
|
||||
Baut nichts ausserhalb von /tmp, geht nicht ins Netz, raeumt am Ende auf.
|
||||
|
||||
Spezifikation: .vault-tools/plan-kopie/mutanten_lauf_ENTWURF.md, Abschnitt 6.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
HIER = Path(__file__).resolve().parent
|
||||
LAEUFER = HIER / "mutanten_lauf.py"
|
||||
INTERPRETER = "/home/claude/venvs/trading/bin/python"
|
||||
|
||||
FEHLERLISTE = []
|
||||
|
||||
|
||||
def melde(fallname, ok, zusatz=""):
|
||||
if ok:
|
||||
print("{0} ok".format(fallname))
|
||||
else:
|
||||
print("{0} FEHLER: {1}".format(fallname, zusatz))
|
||||
FEHLERLISTE.append(fallname)
|
||||
|
||||
|
||||
def sha_von(pfad):
|
||||
return hashlib.sha256(pfad.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def snapshot(dateien):
|
||||
return {p: sha_von(p) for p in dateien}
|
||||
|
||||
|
||||
def pruefe_unveraendert(dateien, snap, fallname):
|
||||
for p in dateien:
|
||||
if not p.exists():
|
||||
melde(fallname + " (rueckstellung)", False, "Datei fehlt nach dem Lauf: {0}".format(p))
|
||||
return
|
||||
if sha_von(p) != snap[p]:
|
||||
melde(fallname + " (rueckstellung)", False, "Datei nicht byte-gleich zurueckgesetzt: {0}".format(p))
|
||||
return
|
||||
|
||||
|
||||
def starte_laeufer(basis, toml_pfad, zusatzargumente=None, bericht_pfad=None, zeitlimit=None):
|
||||
cmd = [INTERPRETER, str(LAEUFER), "--wurzel", str(basis), "--mutanten", str(toml_pfad)]
|
||||
if zeitlimit is not None:
|
||||
cmd += ["--zeitlimit", str(zeitlimit)]
|
||||
if bericht_pfad is not None:
|
||||
cmd += ["--bericht", str(bericht_pfad)]
|
||||
if zusatzargumente:
|
||||
cmd += zusatzargumente
|
||||
return subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
||||
|
||||
|
||||
def schreibe_toml(pfad, text):
|
||||
pfad.write_text(text, encoding="utf-8")
|
||||
|
||||
|
||||
def enthaelt(text, teilstueck):
|
||||
return teilstueck in (text or "")
|
||||
|
||||
|
||||
# --- Projektaufbau ----------------------------------------------------
|
||||
|
||||
def baue_projekt(basis):
|
||||
(basis / "paket").mkdir(parents=True)
|
||||
(basis / "tests").mkdir(parents=True)
|
||||
|
||||
(basis / "paket" / "__init__.py").write_text("", encoding="utf-8")
|
||||
|
||||
(basis / "paket" / "modul.py").write_text(
|
||||
"def f1(x):\n"
|
||||
" if x > 0:\n"
|
||||
" return True\n"
|
||||
" return False\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def f2(y):\n"
|
||||
" if y >= 10:\n"
|
||||
" return \"gross\"\n"
|
||||
" return \"klein\"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def f3(z):\n"
|
||||
" if z == 0:\n"
|
||||
" pass # platzhalter\n"
|
||||
" return z\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def f4(w):\n"
|
||||
" if w == 1:\n"
|
||||
" pass # platzhalter\n"
|
||||
" return w\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def f5(a, b):\n"
|
||||
" resultat = a + b\n"
|
||||
" return resultat\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "paket" / "modul_syntax.py").write_text(
|
||||
"def f6(n):\n"
|
||||
" return n * 2\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "paket" / "modul_zeit.py").write_text(
|
||||
"def f7(n):\n"
|
||||
" return n + 1\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "paket" / "modul_crlf.py").write_bytes(
|
||||
b"def f8(n):\r\n return n\r\n",
|
||||
)
|
||||
|
||||
(basis / "paket" / "modul_binaer.py").write_bytes(
|
||||
b"\xff\xfe nicht utf-8 \x80\x81\n",
|
||||
)
|
||||
|
||||
(basis / "tests" / "__init__.py").write_text("", encoding="utf-8")
|
||||
|
||||
(basis / "tests" / "test_modul.py").write_text(
|
||||
"from paket.modul import f1, f2, f5\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f1_positiv():\n"
|
||||
" assert f1(5) is True\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f1_negativ():\n"
|
||||
" assert f1(-3) is False\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f2_gross():\n"
|
||||
" assert f2(15) == \"gross\"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f2_klein():\n"
|
||||
" assert f2(1) == \"klein\"\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f5_summe():\n"
|
||||
" assert f5(2, 3) == 5\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "tests" / "test_modul_syntax.py").write_text(
|
||||
"from paket.modul_syntax import f6\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f6():\n"
|
||||
" assert f6(3) == 6\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "tests" / "test_zeit.py").write_text(
|
||||
"from paket.modul_zeit import f7\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_f7():\n"
|
||||
" assert f7(1) == 2\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "tests" / "test_faelle.py").write_text(
|
||||
"import pytest\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_immer_rot():\n"
|
||||
" assert False\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_immer_uebersprungen():\n"
|
||||
" pytest.skip(\"fuer den Treiber-Fall 14\")\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"@pytest.mark.integration\n"
|
||||
"def test_wird_abgewaehlt():\n"
|
||||
" assert True\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "tests" / "test_abdichtung.py").write_text(
|
||||
"import os\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"def test_abdichtung_home_und_proxy():\n"
|
||||
" home = os.environ.get(\"HOME\", \"\")\n"
|
||||
" proxy = os.environ.get(\"https_proxy\", \"\")\n"
|
||||
" assert \"mutanten_lauf_home_\" in home and proxy == \"http://127.0.0.1:9\"\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
(basis / "pyproject.toml").write_text(
|
||||
"[tool.pytest.ini_options]\n"
|
||||
"addopts = '-m \"not integration\"'\n"
|
||||
"markers = [\n"
|
||||
" \"integration: wird vom Treiber absichtlich abgewaehlt\",\n"
|
||||
"]\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
getrackte_dateien = [
|
||||
basis / "pyproject.toml",
|
||||
basis / "paket" / "__init__.py",
|
||||
basis / "paket" / "modul.py",
|
||||
basis / "paket" / "modul_syntax.py",
|
||||
basis / "paket" / "modul_zeit.py",
|
||||
basis / "paket" / "modul_crlf.py",
|
||||
basis / "paket" / "modul_binaer.py",
|
||||
basis / "tests" / "__init__.py",
|
||||
basis / "tests" / "test_modul.py",
|
||||
basis / "tests" / "test_modul_syntax.py",
|
||||
basis / "tests" / "test_zeit.py",
|
||||
basis / "tests" / "test_faelle.py",
|
||||
basis / "tests" / "test_abdichtung.py",
|
||||
]
|
||||
return getrackte_dateien
|
||||
|
||||
|
||||
# --- TOML-Bausteine -----------------------------------------------------
|
||||
|
||||
def kopf(python=INTERPRETER, zusatz=""):
|
||||
return "format = 1\npython = \"{0}\"\n{1}\n".format(python, zusatz)
|
||||
|
||||
|
||||
def mutant_d1_d2():
|
||||
return (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"D1\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
"\n"
|
||||
"[[mutant]]\n"
|
||||
"id = \"D2\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return \"gross\"\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return \"klein\"\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f2_gross\"]\n"
|
||||
)
|
||||
|
||||
|
||||
def mutant_luecke(id_, rot_bei_liste):
|
||||
rot_bei_text = ", ".join('"{0}"'.format(x) for x in rot_bei_liste)
|
||||
return (
|
||||
"[[mutant]]\n"
|
||||
"id = \"{0}\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [{1}]\n"
|
||||
).format(id_, rot_bei_text)
|
||||
|
||||
|
||||
def mutant_korrekt(id_):
|
||||
return (
|
||||
"[[mutant]]\n"
|
||||
"id = \"{0}\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return \"gross\"\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return \"klein\"\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f2_gross\"]\n"
|
||||
).format(id_)
|
||||
|
||||
|
||||
# --- Faelle ---------------------------------------------------------------
|
||||
|
||||
def fall_01(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_d1_d2())
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = (
|
||||
ergebnis.returncode == 0
|
||||
and ergebnis.stdout.count(" OK ") >= 2
|
||||
and "D1 OK" in ergebnis.stdout
|
||||
and "D2 OK" in ergebnis.stdout
|
||||
)
|
||||
melde("Fall 1", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_02(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("L1", ["tests/test_modul.py::test_f2_gross", "tests/test_modul.py::test_f1_positiv"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "L1 LUECKE" in ergebnis.stdout
|
||||
melde("Fall 2", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_03(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("L2", ["tests/test_modul.py::test_f1_positiv", "tests/test_modul.py::test_f2_gross"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "L2 LUECKE" in ergebnis.stdout
|
||||
melde("Fall 3", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_04(basis, projektpfad):
|
||||
toml_a = projektpfad / "mutanten_4a.toml"
|
||||
schreibe_toml(toml_a, kopf() + mutant_luecke("L3", ["tests/test_modul.py::test_f2_gross", "tests/test_modul.py::test_f1_positiv"]) + "\n" + mutant_korrekt("K3"))
|
||||
ergebnis_a = starte_laeufer(basis, toml_a)
|
||||
ok_a = (
|
||||
ergebnis_a.returncode == 1
|
||||
and "L3 LUECKE" in ergebnis_a.stdout
|
||||
and "K3 OK" in ergebnis_a.stdout
|
||||
)
|
||||
|
||||
toml_b = projektpfad / "mutanten_4b.toml"
|
||||
schreibe_toml(toml_b, kopf() + mutant_korrekt("K4") + "\n" + mutant_luecke("L4", ["tests/test_modul.py::test_f2_gross", "tests/test_modul.py::test_f1_positiv"]))
|
||||
ergebnis_b = starte_laeufer(basis, toml_b)
|
||||
ok_b = (
|
||||
ergebnis_b.returncode == 1
|
||||
and "L4 LUECKE" in ergebnis_b.stdout
|
||||
and "K4 OK" in ergebnis_b.stdout
|
||||
)
|
||||
|
||||
melde("Fall 4", ok_a and ok_b, "a: exit={0}\n{1}\nb: exit={2}\n{3}".format(
|
||||
ergebnis_a.returncode, ergebnis_a.stdout, ergebnis_b.returncode, ergebnis_b.stdout))
|
||||
|
||||
|
||||
def fall_05(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M5\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return None\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "M5 MUSTER" in ergebnis.stdout and "Trefferzahl=0" in ergebnis.stdout
|
||||
melde("Fall 5", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_06(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M6\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" pass # platzhalter\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" pass\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "M6 MUSTER" in ergebnis.stdout and "Trefferzahl=2" in ergebnis.stdout
|
||||
melde("Fall 6", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_07(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M7\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "M7 MUSTER" in ergebnis.stdout and "Trefferzahl=0" in ergebnis.stdout
|
||||
melde("Fall 7", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_08(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M8\"\n"
|
||||
"datei = \"paket/modul_crlf.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return n\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return 0\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 1 and "M8 MUSTER" in ergebnis.stdout and "Datei hat CR" in ergebnis.stdout
|
||||
melde("Fall 8", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_09(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M9\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" if y >= 10:\n"
|
||||
" return \"gross\"\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" if y >= 10:\n"
|
||||
" return \"mittel\"\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f2_gross\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 0 and "M9 OK" in ergebnis.stdout
|
||||
melde("Fall 9", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_10(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M10\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" resultat = a + b\n"
|
||||
"'''\n"
|
||||
"wird = \"\"\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f5_summe\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 0 and "M10 OK" in ergebnis.stdout
|
||||
melde("Fall 10", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_11(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M11\"\n"
|
||||
"datei = \"paket/modul_syntax.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return n * 2\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return n *\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul_syntax.py::test_f6\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = (
|
||||
ergebnis.returncode == 0
|
||||
and "M11 OK" in ergebnis.stdout
|
||||
and "Sammelfehler" in ergebnis.stdout
|
||||
)
|
||||
melde("Fall 11", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_12(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M12\"\n"
|
||||
"datei = \"paket/modul_zeit.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return n + 1\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" while True:\n"
|
||||
" pass\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_zeit.py::test_f7\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml, zeitlimit=5)
|
||||
ok = ergebnis.returncode == 1 and "M12 ZEIT" in ergebnis.stdout
|
||||
melde("Fall 12", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_13(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_luecke("M13", ["tests/test_faelle.py::test_immer_rot"]))
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("M13", ["tests/test_faelle.py::test_immer_rot"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 13", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_14(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("M14", ["tests/test_faelle.py::test_immer_uebersprungen"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 14", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_15(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("M15", ["tests/test_faelle.py::test_wird_abgewaehlt"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ausgabe = ergebnis.stdout + ergebnis.stderr
|
||||
ok = ergebnis.returncode == 2 and ("abgew" in ausgabe.lower() or "ABGEWAEHLT" in ausgabe)
|
||||
melde("Fall 15", ok, "exit={0}\n{1}".format(ergebnis.returncode, ausgabe))
|
||||
|
||||
|
||||
def fall_16(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("M16", ["tests/test_modul.py::test_gibt_es_nicht"]))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 16", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_17(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_d1_d2())
|
||||
|
||||
git_ordner = basis / ".git"
|
||||
git_ordner.mkdir()
|
||||
ergebnis_ordner = starte_laeufer(basis, toml)
|
||||
git_ordner.rmdir()
|
||||
ok_ordner = ergebnis_ordner.returncode == 2
|
||||
|
||||
git_datei = basis / ".git"
|
||||
git_datei.write_text("kein echtes repo", encoding="utf-8")
|
||||
ergebnis_datei = starte_laeufer(basis, toml)
|
||||
git_datei.unlink()
|
||||
ok_datei = ergebnis_datei.returncode == 2
|
||||
|
||||
melde("Fall 17", ok_ordner and ok_datei, "ordner exit={0}, datei exit={1}".format(
|
||||
ergebnis_ordner.returncode, ergebnis_datei.returncode))
|
||||
|
||||
|
||||
def fall_18(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf(zusatz="ohne = [\"geheim/geheimnis.toml\"]\n") + mutant_d1_d2().split("\n", 2)[-1])
|
||||
|
||||
geheim_ordner = basis / "geheim"
|
||||
geheim_ordner.mkdir()
|
||||
(geheim_ordner / "geheimnis.toml").write_text("x = 1\n", encoding="utf-8")
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
shutil.rmtree(geheim_ordner)
|
||||
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 18", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_19(basis, projektpfad):
|
||||
toml_a = projektpfad / "mutanten_19a.toml"
|
||||
schreibe_toml(toml_a, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M19a\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rotbei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis_a = starte_laeufer(basis, toml_a)
|
||||
ok_a = ergebnis_a.returncode == 2
|
||||
|
||||
toml_b = projektpfad / "mutanten_19b.toml"
|
||||
schreibe_toml(toml_b, "unbekannt = 1\n" + mutant_d1_d2())
|
||||
ergebnis_b = starte_laeufer(basis, toml_b)
|
||||
ok_b = ergebnis_b.returncode == 2
|
||||
|
||||
melde("Fall 19", ok_a and ok_b, "a exit={0}, b exit={1}".format(ergebnis_a.returncode, ergebnis_b.returncode))
|
||||
|
||||
|
||||
def fall_20(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + mutant_korrekt("GLEICH") + "\n" + mutant_korrekt("GLEICH"))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 20", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_21(basis, projektpfad):
|
||||
toml_a = projektpfad / "mutanten_21a.toml"
|
||||
schreibe_toml(toml_a, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M21a\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = []\n"
|
||||
))
|
||||
ergebnis_a = starte_laeufer(basis, toml_a)
|
||||
ok_a = ergebnis_a.returncode == 2
|
||||
|
||||
toml_b = projektpfad / "mutanten_21b.toml"
|
||||
schreibe_toml(toml_b, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M21b\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = \"tests/test_modul.py::test_f1_positiv\"\n"
|
||||
))
|
||||
ergebnis_b = starte_laeufer(basis, toml_b)
|
||||
ok_b = ergebnis_b.returncode == 2
|
||||
|
||||
melde("Fall 21", ok_a and ok_b, "a exit={0}, b exit={1}".format(ergebnis_a.returncode, ergebnis_b.returncode))
|
||||
|
||||
|
||||
def fall_22(basis, projektpfad):
|
||||
varianten = {
|
||||
"22a (..)": "paket/../paket/modul.py",
|
||||
"22b (absolut)": "/etc/passwd",
|
||||
"22c (fehlt)": "paket/existiert_nicht.py",
|
||||
}
|
||||
alle_ok = True
|
||||
zusatz = []
|
||||
for name, datei in varianten.items():
|
||||
toml = projektpfad / "mutanten_{0}.toml".format(name.split()[0])
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M22\"\n"
|
||||
"datei = \"{0}\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
).format(datei))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("{0}: exit={1}".format(name, ergebnis.returncode))
|
||||
melde("Fall 22", alle_ok, "; ".join(zusatz))
|
||||
|
||||
|
||||
def fall_23(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M23\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"UNBEKANNT::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 23", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_24(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M24\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" return True\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 24", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_25(basis, projektpfad):
|
||||
zusatz = []
|
||||
alle_ok = True
|
||||
|
||||
toml = projektpfad / "mutanten_25a.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M25a\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = \"\"\n"
|
||||
"wird = '''\n"
|
||||
" return False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
e = starte_laeufer(basis, toml)
|
||||
ok = e.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("aus leer: exit={0}".format(e.returncode))
|
||||
|
||||
toml = projektpfad / "mutanten_25b.toml"
|
||||
schreibe_toml(toml, "format = 2\npython = \"{0}\"\n\n".format(INTERPRETER) + mutant_korrekt("M25b"))
|
||||
e = starte_laeufer(basis, toml)
|
||||
ok = e.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("format=2: exit={0}".format(e.returncode))
|
||||
|
||||
toml = projektpfad / "mutanten_25c.toml"
|
||||
schreibe_toml(toml, "python = \"{0}\"\n\n".format(INTERPRETER) + mutant_korrekt("M25c"))
|
||||
e = starte_laeufer(basis, toml)
|
||||
ok = e.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("format fehlt: exit={0}".format(e.returncode))
|
||||
|
||||
toml = projektpfad / "mutanten_25d.toml"
|
||||
schreibe_toml(toml, "format = 1\npython = \"bin/python\"\n\n" + mutant_korrekt("M25d"))
|
||||
e = starte_laeufer(basis, toml)
|
||||
ok = e.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("python relativ: exit={0}".format(e.returncode))
|
||||
|
||||
toml = projektpfad / "mutanten_25e.toml"
|
||||
schreibe_toml(toml, "format = 1\npython = \"/nicht/vorhanden/python\"\n\n" + mutant_korrekt("M25e"))
|
||||
e = starte_laeufer(basis, toml)
|
||||
ok = e.returncode == 2
|
||||
alle_ok = alle_ok and ok
|
||||
zusatz.append("python existiert nicht: exit={0}".format(e.returncode))
|
||||
|
||||
melde("Fall 25", alle_ok, "; ".join(zusatz))
|
||||
|
||||
|
||||
def fall_26(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, "format = 1\npython = \"{0}\"\n[[mutant\n".format(INTERPRETER))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 26", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_27(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, kopf() + "mutant = []\n")
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 27", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_28(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_d1_d2())
|
||||
ergebnis = starte_laeufer(basis, toml, zusatzargumente=["--nur", "UNBEKANNTEID"])
|
||||
ok = ergebnis.returncode == 2
|
||||
melde("Fall 28", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_29(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_d1_d2())
|
||||
ergebnis = starte_laeufer(basis, toml, zusatzargumente=["--nur", "D1"])
|
||||
ok = (
|
||||
ergebnis.returncode == 0
|
||||
and "D1 OK" in ergebnis.stdout
|
||||
and "D2" not in ergebnis.stdout.replace("mutanten gesamt: 2, ausgewaehlt: 1", "")
|
||||
)
|
||||
melde("Fall 29", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_30(basis, projektpfad):
|
||||
toml_sauber = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml_sauber, mutant_d1_d2())
|
||||
e1 = starte_laeufer(basis, toml_sauber, zusatzargumente=["--nur-muster"])
|
||||
ok1 = e1.returncode == 0
|
||||
|
||||
toml_luecke = projektpfad / "mutanten_6.toml"
|
||||
schreibe_toml(toml_luecke, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M6\"\n"
|
||||
"datei = \"paket/modul.py\"\n"
|
||||
"aus = '''\n"
|
||||
" pass # platzhalter\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" pass\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
e2 = starte_laeufer(basis, toml_luecke, zusatzargumente=["--nur-muster"])
|
||||
ok2 = e2.returncode == 1
|
||||
|
||||
melde("Fall 30", ok1 and ok2, "sauber exit={0}, fall6 exit={1}".format(e1.returncode, e2.returncode))
|
||||
|
||||
|
||||
def fall_31(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M31\"\n"
|
||||
"datei = \"paket/modul_binaer.py\"\n"
|
||||
"aus = '''\n"
|
||||
" irrelevant\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" irrelevant2\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_modul.py::test_f1_positiv\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ausgabe = ergebnis.stdout + ergebnis.stderr
|
||||
ok = ergebnis.returncode in (1, 2) and ("UTF-8" in ausgabe or "utf-8" in ausgabe)
|
||||
melde("Fall 31", ok, "exit={0}\n{1}".format(ergebnis.returncode, ausgabe))
|
||||
|
||||
|
||||
def fall_32(basis, projektpfad):
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf() +
|
||||
"[[mutant]]\n"
|
||||
"id = \"M32\"\n"
|
||||
"datei = \"tests/test_abdichtung.py\"\n"
|
||||
"aus = '''\n"
|
||||
" assert \"mutanten_lauf_home_\" in home and proxy == \"http://127.0.0.1:9\"\n"
|
||||
"'''\n"
|
||||
"wird = '''\n"
|
||||
" assert False\n"
|
||||
"'''\n"
|
||||
"rot_bei = [\"tests/test_abdichtung.py::test_abdichtung_home_und_proxy\"]\n"
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 0 and "M32 OK" in ergebnis.stdout
|
||||
melde("Fall 32", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
|
||||
|
||||
def fall_33(basis, projektpfad):
|
||||
import json as jsonmod
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, mutant_luecke("L1", ["tests/test_modul.py::test_f2_gross", "tests/test_modul.py::test_f1_positiv"]))
|
||||
schreibe_toml(toml, kopf() + mutant_luecke("L1", ["tests/test_modul.py::test_f2_gross", "tests/test_modul.py::test_f1_positiv"]))
|
||||
bericht_pfad = projektpfad / "bericht_33.json"
|
||||
ergebnis = starte_laeufer(basis, toml, bericht_pfad=bericht_pfad)
|
||||
ok = ergebnis.returncode == 1
|
||||
if ok:
|
||||
try:
|
||||
daten = jsonmod.loads(bericht_pfad.read_text(encoding="utf-8"))
|
||||
ok = (
|
||||
isinstance(daten, dict)
|
||||
and any(m.get("id") == "L1" and m.get("status") == "LUECKE" for m in daten.get("mutanten", []))
|
||||
)
|
||||
except (ValueError, OSError) as exc:
|
||||
ok = False
|
||||
ergebnis = subprocess.CompletedProcess(ergebnis.args, ergebnis.returncode, ergebnis.stdout + "\nJSON-Fehler: " + str(exc), ergebnis.stderr)
|
||||
melde("Fall 33", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
try:
|
||||
bericht_pfad.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def fall_34(basis, projektpfad):
|
||||
# Ein blosser Symlink auf die Python-Binaerdatei bricht die
|
||||
# Venv-Erkennung (site.py sucht pyvenv.cfg im Verzeichnis des
|
||||
# Symlinks, nicht im Zielverzeichnis) - pytest waere dann nicht
|
||||
# importierbar. Deshalb wird das ganze Venv-Verzeichnis verlinkt.
|
||||
alt_python_dir = Path(tempfile.mkdtemp(prefix="mutanten_lauf_fall34_"))
|
||||
venv_verzeichnis = Path(INTERPRETER).parent.parent
|
||||
venv_link = alt_python_dir / "venv_alt"
|
||||
alt_python = venv_link / "bin" / "python"
|
||||
try:
|
||||
os.symlink(venv_verzeichnis, venv_link)
|
||||
toml = projektpfad / "mutanten.toml"
|
||||
schreibe_toml(toml, (
|
||||
kopf(zusatz="\n[python_je_datei]\n\"tests/test_modul.py\" = \"{0}\"\n".format(alt_python)) +
|
||||
mutant_d1_d2().split("\n", 2)[-1]
|
||||
))
|
||||
ergebnis = starte_laeufer(basis, toml)
|
||||
ok = ergebnis.returncode == 0 and "D1 OK" in ergebnis.stdout and "D2 OK" in ergebnis.stdout
|
||||
melde("Fall 34", ok, "exit={0}\n{1}".format(ergebnis.returncode, ergebnis.stdout))
|
||||
finally:
|
||||
shutil.rmtree(alt_python_dir, ignore_errors=True)
|
||||
|
||||
|
||||
FAELLE = [
|
||||
fall_01, fall_02, fall_03, fall_04, fall_05, fall_06, fall_07, fall_08, fall_09, fall_10,
|
||||
fall_11, fall_12, fall_13, fall_14, fall_15, fall_16, fall_17, fall_18, fall_19, fall_20,
|
||||
fall_21, fall_22, fall_23, fall_24, fall_25, fall_26, fall_27, fall_28, fall_29, fall_30,
|
||||
fall_31, fall_32, fall_33, fall_34,
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
basis = Path(tempfile.mkdtemp(prefix="mutanten_lauf_treiber_"))
|
||||
projektpfad = basis
|
||||
try:
|
||||
getrackte_dateien = baue_projekt(basis)
|
||||
snap = snapshot(getrackte_dateien)
|
||||
|
||||
for funktion in FAELLE:
|
||||
vor_lauf = len(FEHLERLISTE)
|
||||
try:
|
||||
funktion(basis, projektpfad)
|
||||
except Exception as exc:
|
||||
melde(funktion.__name__, False, "Ausnahme: {0}".format(exc))
|
||||
pruefe_unveraendert(getrackte_dateien, snap, funktion.__name__)
|
||||
|
||||
anzahl_fehler = len(FEHLERLISTE)
|
||||
print("gerechnete Fehler: {0}".format(anzahl_fehler))
|
||||
return 0 if anzahl_fehler == 0 else 1
|
||||
finally:
|
||||
shutil.rmtree(basis, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user