34 lines
2.8 KiB
Python
34 lines
2.8 KiB
Python
# mutate.py <id>: apply one named mutant (each edit exact text, must match once). Run from the tree root.
|
|
import sys
|
|
C = "packages/conversation/"
|
|
NOPROBE = (C + "tests/claim.test.mjs", " // The force stop leaves the probe's shim running: nothing sends `release`.\n reap(probe);\n", "")
|
|
M = {
|
|
"Mr": [(C + "src/terminal.mjs", " holds = this.held !== null;\n", " holds = false;\n")],
|
|
"noprobe": [NOPROBE],
|
|
"now13": [(C + "tests/claim.test.mjs", " // The force stop leaves the shim running: nothing sends `release`.\n reap(fx);\n", "")],
|
|
"afterleak": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " const left")],
|
|
# The sweep alone, with no records: noprobe, and after doesn't reap the fixtures.
|
|
"sweeponly": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " killShims();\n const left")],
|
|
# The sweep kills by PID only, no scope kill: noprobe and after without reap.
|
|
"sweeppid": [NOPROBE, (C + "tests/claim.test.mjs", " for (const fx of reaped) reap(fx);\n killShims();\n const left", " killShims();\n const left"),
|
|
(C + "tests/harness.mjs", " if (s.unit) spawnSync(\"systemctl\", [\"--user\", \"kill\", \"--signal=SIGKILL\", `${s.unit}.scope`], { stdio: \"ignore\", timeout: 5000 });\n", "")],
|
|
# K19 leaves its scope: no kill, no release.
|
|
"k19leak": [(C + "tests/cohort.test.mjs",
|
|
" const killed = await shimRequest(socketPath, \"kill\", { timeoutMs: 5000 }, 8000);\n const released = killed.ok ? await shimRequest(socketPath, \"release\") : killed;\n if (!released.ok) spawnSync(\"systemctl\", [\"--user\", \"kill\", \"--signal=SIGKILL\", `${unitName}.scope`], { stdio: \"ignore\", timeout: 5000 });\n await proc.exited;\n assert.equal(killed.ok, true, JSON.stringify(killed));\n assert.equal(released.ok, true, JSON.stringify(released));\n",
|
|
" void proc;\n")],
|
|
# H23 doesn't reap its fixture.
|
|
"h23noreap": [(C + "tests/races.test.mjs", " await b.exited;\n reap(fx);\n});\n\n// Last in the file.", " await b.exited;\n});\n\n// Last in the file.")],
|
|
# H22 (a scope, force-stopped, then relaunched) doesn't reap its fixture.
|
|
"h22noreap": [(C + "tests/races.test.mjs", " await b.exited;\n reap(fx);\n});\n\ntest(\"H23", " await b.exited;\n});\n\ntest(\"H23")],
|
|
# reap() without the sweep: the backstop alone.
|
|
"reapnosweep": [(C + "tests/harness.mjs", " // calls above didn't reach: neither result is checked.\n killShims(fx.base);\n", " // calls above didn't reach: neither result is checked.\n")],
|
|
}
|
|
if "--files" in sys.argv:
|
|
print(" ".join(sorted({f for f, _, _ in M[sys.argv[1]]}))); sys.exit(0)
|
|
for f, old, new in M[sys.argv[1]]:
|
|
s = open(f).read()
|
|
n = s.count(old)
|
|
if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
|
|
open(f, "w").write(s.replace(old, new))
|
|
print(f)
|