oficina / suite Public

Clone
git clone https://amadan.net/oficina/suite

Plain git — no account needed to clone.

Download

Download this file

1"""Re-run the six regressions the GPT-6 module review found surviving.
2
3Each mutation is applied to a copy of the tree, the suite is run, and the
4mutation must FAIL the suite. A survivor means the tests still cannot tell.
5"""
6import io, os, shutil, subprocess, sys, tempfile
7
8ROOT = os.path.dirname(os.path.abspath(__file__))
9CACHE = os.path.join(ROOT, ".gocache")
10
11MUTATIONS = [
12 ("11: non-2xx returns nothing instead of all-UNKNOWN", "s2.go",
13 "\tif status < 200 || status > 299 {\n\t\treturn allUnknown(len(asked))\n\t}",
14 "\tif status < 200 || status > 299 {\n\t\treturn nil\n\t}"),
15
16 ("12a: the revision is ignored when matching answers to questions", "s2.go",
17 "\t\tpair := ItemRevision{ItemID: *r.ItemID, Revision: *r.Revision}",
18 "\t\tpair := ItemRevision{ItemID: *r.ItemID}"),
19
20 ("12b: STALE is dropped from the closed vocabulary", "s2.go",
21 "\tcase VISIBLE, NOT_VISIBLE, STALE, UNKNOWN:",
22 "\tcase VISIBLE, NOT_VISIBLE, UNKNOWN:"),
23
24 ("13: the batch cap is doubled", "subject.go",
25 "const MaxS2Pairs = 256",
26 "const MaxS2Pairs = 512"),
27
28 ("14: a 403 loses its ErrContractBreach sentinel", "s3.go",
29 '\t\treturn nil, fmt.Errorf("%w: S3 answered 403 where the contract requires 404", ErrContractBreach)',
30 '\t\treturn nil, fmt.Errorf("S3 answered 403")'),
31
32 ("10: redirects are followed", "transport.go",
33 '\t\t\treturn fmt.Errorf("suite: refusing to follow a redirect to %q", req.URL.Host)',
34 "\t\t\treturn nil"),
35
36 ("1: the Host header override is not checked", "transport.go",
37 "\tif req.Host != \"\" {",
38 "\tif false {"),
39
40 ("2: duplicate JSON keys are not rejected in S2", "s2.go",
41 "\tif err := rejectAmbiguousJSON(body); err != nil {\n\t\treturn allUnknown(len(asked))\n\t}",
42 "\tif false {\n\t\treturn allUnknown(len(asked))\n\t}"),
43
44 ("9: hostname labels are not validated", "transport.go",
45 "\t\tif err := validLabel(label); err != nil {",
46 "\t\tif false {\n\t\t\t_ = label\n\t\tif err := error(nil); err != nil {"),
47]
48
49survivors = []
50for name, path, before, after in MUTATIONS:
51 work = tempfile.mkdtemp(prefix="mut-")
52 tree = os.path.join(work, "m")
53 # Only the module's own files: the worktree root also holds unreadable
54 # dotfiles that a whole-tree copy trips over.
55 os.makedirs(tree)
56 for entry in os.listdir(ROOT):
57 if entry.endswith(".go") or entry == "go.mod":
58 shutil.copy2(os.path.join(ROOT, entry), os.path.join(tree, entry))
59 shutil.copytree(os.path.join(ROOT, "fixtures"), os.path.join(tree, "fixtures"))
60 shutil.copytree(os.path.join(ROOT, "conformance"), os.path.join(tree, "conformance"))
61
62 target = os.path.join(tree, path)
63 src = io.open(target, encoding="utf-8").read()
64 if before not in src:
65 print("SKIP %s — anchor not found in %s" % (name, path))
66 shutil.rmtree(work)
67 continue
68 io.open(target, "w", encoding="utf-8").write(src.replace(before, after, 1))
69
70 env = dict(os.environ, GOCACHE=CACHE)
71 r = subprocess.run(["go", "test", "./..."], cwd=tree, capture_output=True, text=True, env=env)
72 shutil.rmtree(work)
73
74 if r.returncode == 0:
75 print("SURVIVED %s" % name)
76 survivors.append(name)
77 else:
78 print("caught %s" % name)
79
80print()
81if survivors:
82 print("%d mutation(s) survived:" % len(survivors))
83 for s in survivors:
84 print(" -", s)
85 sys.exit(1)
86print("all %d mutations caught" % len(MUTATIONS))
87