"""Mutantenlauf gegen verbrauch_reihe.py: je Mutant genau eine Ersetzung in einer Kopie des Ordners, dann faelle_verbrauch_reihe.py. Jede Ersetzung muss genau einmal vorkommen, sonst bricht der Lauf mit Exit 2 ab (veralteter Mutant). Aufruf: python mutanten_reihe.py Exit 0, wenn jeder Mutant gefangen wird, 1 bei einem Ueberlebenden, 2 bei einem veralteten Muster. """ import shutil import subprocess import sys import tempfile from pathlib import Path HIER = Path(__file__).resolve().parent MUTANTEN = [ ("Reset nur bei gleichem Text", "if abs(rb - ra) > RESET_TOLERANZ or b[0] < a[0]:", "if a[1] != b[1] or b[0] < a[0]:"), ("Toleranz 6 Stunden", "RESET_TOLERANZ = timedelta(minutes=5)", "RESET_TOLERANZ = timedelta(hours=6)"), ("Toleranz 1 Sekunde", "RESET_TOLERANZ = timedelta(minutes=5)", "RESET_TOLERANZ = timedelta(seconds=1)"), ("Toleranz nur nach vorn", "if abs(rb - ra) > RESET_TOLERANZ or b[0] < a[0]:", "if rb - ra > RESET_TOLERANZ or b[0] < a[0]:"), ("fallender Wert kein Reset", "if abs(rb - ra) > RESET_TOLERANZ or b[0] < a[0]:", "if abs(rb - ra) > RESET_TOLERANZ:"), ("unlesbares resetsAt als gleich", " if ra is None or rb is None or (ra.tzinfo is None) != (rb.tzinfo is None):\n return \"unbekannt\"\n", ""), ("bool als Zahl", "isinstance(p, bool) or ", ""), ("ueber 100 als Fehler", "not math.isfinite(p) or p < 0", "not math.isfinite(p) or not 0 <= p <= 100"), ("erstes statt hoechstes 5-Stunden-Fenster", "if art == \"fuenf\" and (fuenf is None or p > fuenf[0]):", "if art == \"fuenf\" and fuenf is None:"), ("Ablesezeit Start statt Ende", "\"zeit\": spanne[1]", "\"zeit\": spanne[0]"), ("nur_ascii fehlt", "print(nur_ascii(f\"| {z", "print((f\"| {z"), ("Ende des Paars nicht gekappt", "min(g[\"ende\"], b[\"zeit\"])", "g[\"ende\"]"), ("Anfang des Paars nicht gekappt", "max(g[\"start\"], a[\"zeit\"])", "g[\"start\"]"), ("Absturz nicht gefangen", "except Exception as e: # Ein Absturz", "except ZeroDivisionError as e: # Ein Absturz"), ("kaputte Zeile bricht ab", " except ValueError:\n befunde.append(f\"{pfad.parent.name}/{pfad.name}: Zeile", " except KeyError:\n befunde.append(f\"{pfad.parent.name}/{pfad.name}: Zeile"), ("seit ignoriert", "ablesungen = [x for x in ablesungen if x[\"zeit\"] >= seit]", "pass"), ("Speicher fehlt still", " return 2\n seit = None", " return 0\n seit = None"), ("Familie aus vollem Namen fehlt", " if f in modell.lower():", " if f == modell.lower():"), ] def main() -> int: ueberlebt, veraltet = [], [] for name, alt, neu in MUTANTEN: with tempfile.TemporaryDirectory() as tmp: ziel = Path(tmp) / "w" ziel.mkdir() for datei in ("verbrauch_reihe.py", "faelle_verbrauch_reihe.py"): shutil.copy2(HIER / datei, ziel / datei) pfad = ziel / "verbrauch_reihe.py" text = pfad.read_text(encoding="utf-8") if text.count(alt) != 1: veraltet.append(name) print(f"VERALTET {name} (Muster {text.count(alt)}-mal)") continue pfad.write_text(text.replace(alt, neu), encoding="utf-8", newline="\n") lauf = subprocess.run([sys.executable, str(ziel / "faelle_verbrauch_reihe.py")], capture_output=True, text=True, encoding="utf-8", errors="replace") rot = [z for z in lauf.stdout.splitlines() if z.startswith("FEHLER")] if lauf.returncode == 0: ueberlebt.append(name) print(f"UEBERLEBT {name}") else: print(f"GEFANGEN {name} ({rot[0][7:80] if rot else 'Absturz'})") print(f"{len(MUTANTEN)} Mutanten, {len(ueberlebt)} ueberlebt, {len(veraltet)} veraltet") return 2 if veraltet else 1 if ueberlebt else 0 if __name__ == "__main__": sys.stdout.reconfigure(errors="replace") sys.exit(main())