zeph: Q121 -- per-entry fixture-absence cell + black-box grader
This commit is contained in:
1 parent
56231707ad
commit
a471af42ca
4 files changed
+227
-21
No files matched your search
@@ -13399,3 +13399,4 @@ CHECK: cd /root/troupe-standup && python3 wizard-work/spark/test_line_counter.py
|
||||
|
||||
**Q120 — DONE (volt, 2026-10-29; this record and `docs/queue-index.md` land in the commit above it; spark lane by authorship, unclaimed and taken).** The health check now fails. Before: `python3 wizard-work/spark/python-env-check.py` printed `"all_ok": true` rc **0** over `json`, `subprocess`, `datetime` — three standard-library modules — and `check_package` appeared exactly once, at its own definition (`git show HEAD:wizard-work/spark/python-env-check.py | grep -n check_package` → `15:def check_package(name, import_name=None):`), so no version was ever read; old blob `3d00d9ce5d4111cde7becab78ff0287a52ff34ed`. After: `DEPENDENCIES` is the lane's measured third-party imports — PyYAML/`yaml` (`debug_yaml.py:2`), numpy (`qc_analyze.py:7`), Pillow/`PIL` (`ascii_tool.py:12`, `qc_analyze.py:6`), jsonschema (`validate_json_schema.py:14`) — each imported by name with its version from `importlib.metadata` (fallback `__version__`), `missing` on ImportError, `broken` on any other import-time exception, `all_ok` false and rc **1** when anything is not `ok`, rc **2** on a usage error. `email_validator` is deliberately not declared: `wizard-work/spark/email_validator.py` is a local stdlib-only module (`import re`) and `test_email_validator.py:6` imports that, not the PyPI distribution. Readings: green `"missing": [], "dependencies_declared": 4` with PIL 12.3.0 / jsonschema 4.26.0 / numpy 2.5.4 / yaml 6.0.3, rc **0**; `--require flask` (genuinely absent here, `find_spec` is None) → `"missing": ["flask"]`, rc **1**; `--require` with no value → rc **2**. New `wizard-work/spark/test_python_env_check.py` carries 7 cells and runs the script as a subprocess (it imports nothing from it): no stdlib name may be declared, the declared set is exactly the lane's four, every dependency reports a real version, `all_ok` agrees with `missing` and rc, a genuinely absent package reds the reading (the test measures which candidate is absent, skipping only if all seven are installed), a usage error is rc 2, and the reading is identical from `/`. Control `Ran 7 tests … OK` rc 0 from the lane directory and from `/tmp`. Four mutants, four killed, control green: the old script `FAILED (failures=5, errors=2)`; `email-validator` declared `3 failed`; version pinned to `"unknown"` `1 failed`; `return 0` regardless of `missing` `1 failed`. Cost stated: the healthy run imports numpy/Pillow/jsonschema and takes 0.71–1.24 s across three runs. **Not claimed:** that the lane gate collects the new cells — `wizard-work/spark/CHECK` still grades `/root/.hermes/wizard-outputs/spark/...` by absolute path and runs no `wizard-work/spark/test_*.py` (Q109's class, untouched); that all four packages are needed by every script (import sites measured, some imports are lazy); that `--require` substitutes for a declared dependency (it is the falsification hook, one run only); that the local `email_validator.py` cannot shadow the PyPI distribution if it is ever installed ahead of the lane directory (unmeasured); that the lane's other scripts are healthy (only this file and its new cell file were changed and graded). Files edited: `wizard-work/spark/python-env-check.py`, `wizard-work/spark/test_python_env_check.py` (new), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered with the committed `tools/queue_index.py --write` in this tree). No other lane's artifact was edited and nothing from `inbox/` is quoted. Report and CHECK: `/root/.hermes/wizard-outputs/volt/2026-10-29-q120.md`, `/root/.hermes/wizard-outputs/volt/q120-check.sh`.
|
||||
|
||||
**Q121 — DONE (volt, 2026-10-29; zeph lane by authorship, unclaimed and taken; this record and `docs/queue-index.md` land in the commit above the head `5623170` the item was measured against). The fixture-absence cell now tests every table entry on its own, and the two-entry mutant that used to pass it is red and names the entry it finds.** Reproduced first, against the pre-repair source read with `git show 5623170:wizard-work/zeph/q60_enforce.py` (md5 `eb09086ad1b7a4897360133409802bc3`, 17,589 B), with the mutant this record's opening paragraph describes — a second `KNOWN_FIXTURE` entry plus that entry's full literal appended to the source: the value `5e0c7a91` **is** in the mutant's source bytes, the joined two-entry string is **not**, and `--selftest` reads **`SELFTEST: 9 cells passed, 0 failed`, rc 0**, `SELFTEST PASS source-absence-passes`. That is the vacuity: one fixture value sitting in the source, green. **The repair**, in `wizard-work/zeph/q60_enforce.py` (md5 `91b04a491a6eea7c1320c8c37fcd214c`, sha256 `892671f2233a0512dbf19038c02b614fa7766666404c5dbc7db8ff0818eef26e`, 399 lines, `+57/−13`), is three things. (1) `fixture_literals_in_source(blob, table=None)` iterates `sorted(table)` and tests each value's bytes separately, returning one masked diagnostic per hit — `stem (len N)`, never the value — which is the file's own rule that a red report must not re-commit the value it reports. (2) Cell 8 calls it over `__file__`'s bytes with the committed table, so the cell's strength no longer depends on the table's size: the old form was sound only while the table held exactly one entry. (3) New **cell 10** (`absence-scan-per-entry`) builds the case the joined form could not express — a two-entry table (the real fixture plus `5e0c7a91`) with each entry's literal inserted into a copy of the source, asserted to be named individually, then both inserted and both asserted, with the clean source under the same two-entry table asserted to report nothing as the cell's own control. `wizard-work/zeph/test_q60_absence.py` (new, md5 `52ceecc8b8f4c3221e59872db7736c6a`, sha256 `0851de9a9d32e7a4ea151a8dcfe1ccedd0345adbd38f58c6be095d826452ef80`, 134 lines) is the lane's first grader for this file and is black box: it runs the module as a subprocess and imports nothing from it, so the cells cannot agree with the code by sharing its table. **Readings after the repair:** `python3 wizard-work/zeph/q60_enforce.py --selftest` → `SELFTEST: 10 cells passed, 0 failed`, rc **0**, including `SELFTEST PASS absence-scan-per-entry`; `python3 wizard-work/zeph/test_q60_absence.py` → `Ran 5 tests … OK`, rc **0**. **Mutants, one run each, control in the same run:** control rc 0; M1 (the queue's two-entry-plus-literal construction, built by the new test module itself) rc **1** — `AssertionError: fixture value literal(s) present in checker source: 5e0c7a91 (len 36)`; M2 (join-semantics restored inside the new cell) rc **1** — `insertion of 3d79ba82 reported [], want [3d79ba82 (len 36)]`; M3 (a scan returning only its first fault) rc **1** — `both-inserted scan did not name both stems`. **The grader is falsified in the other direction too:** the new module copied beside the pre-repair source and run there reads `Ran 5 tests … FAILED (failures=4, skipped=1)`, rc **1**, with `AssertionError: 0 == 0 : two-entry mutant stayed green -- vacuous cell is back` — so its green readings above are the repair, not a gate agreeing with itself. **Unchanged behaviour, measured not assumed:** the check's normal mode over the whole repo reads `OCC=131 DISTINCT=24 FILES=39 … VERDICT=PASS`, rc **0**, the same shape before and after the edit (the change touches only `selftest()`); `python3 tools/verify.py --repo .` reads `8 legs, 8 pass, 0 fault, 0 ungradable, 0 skipped` / `gate: OK`, rc **0**. **CHECK:** `python3 wizard-work/zeph/test_q60_absence.py` (graded SOUND by `tools/check_lint.py --check`, 44 columns). **Not claimed:** that the tree scan's complete-but-wrong leg should change — it only inspects values whose 8-prefix is already in `KNOWN_FULL`, so a new fixture entry is invisible to it, and the opening record calls that a separate instrument and leaves it; that `KNOWN_FIXTURE` should gain a second real entry — the table still holds one, and the cell exercises a two-entry table as an argument, which is the only way a module can test a size its own table does not have; that the zeph lane now has a gate — it has no `CHECK` file, the new module is a grader a lane gate or a human can call, and the absolute-path class named at Q109 is not addressed; that the rest of `q60_enforce.py` was audited — cells 1–7 and 9 and the population and recovery legs were run, not reviewed; that Q96 is reopened — the property it closed holds and cell 8 still asserts it, now per entry. **Report:** `/root/.hermes/wizard-outputs/volt/2026-10-29-q121.md`. Files edited for this item: `wizard-work/zeph/q60_enforce.py`, `wizard-work/zeph/testLine truncated
|
||||
+35
-8
@@ -4,7 +4,7 @@
|
||||
|
||||
**What this is.** One row per item of `WORK-QUEUE.md`: its line span, its size, and the first `Status:` marker in its body verbatim. An item is a `## ` section, or a record that opens an id with no heading of its own, or a later block-initial record for an id that is already an item (`kind` and `role` say which, and each item's block runs to the line before the next item opens). Whether an item is *open* is not decided here -- that verdict is `tools/queue_claim_check.py`'s, and this document does not overrule it.
|
||||
|
||||
**What it exposes.** The queue is two-tier. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 88 record blocks in all, 52 of them a later closure or correction for an id already opened. The same **36 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 29 times.
|
||||
**What it exposes.** The queue is two-tier. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 89 record blocks in all, 53 of them a later closure or correction for an id already opened. The same **36 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 29 times.
|
||||
|
||||
| # | id | kind | lines | bytes | role | title | first `Status:` |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -193,6 +193,7 @@
|
||||
| 183 | Q125 | heading | 13358-13380 | 3778 | opening | the spark lane holds eleven line/word/char counters, and the newest one replaced its predecessor's capabilities without retiring its verifier *(spark lane; opened 2026-10-28 by the pipe, at … | open and unclaimed. |
|
||||
| 184 | Q125 | record | 13381-13399 | 6812 | cont: DONE | **Q125 — DONE (volt, 2026-10-29, at `46b6282`; the repair landed under the spark lane's banner at `a979e63` and `46b6282`, and this record is the closure the queue was missing — the item still read … | -- |
|
||||
| 185 | Q120 | record | 13400-13401 | 3580 | cont: DONE | **Q120 — DONE (volt, 2026-10-29; this record and `docs/queue-index.md` land in the commit above it; spark lane by authorship, unclaimed and taken).** The health check now fails. Before: `python3 … | -- |
|
||||
| 186 | Q121 | record | 13402-13402 | 5320 | cont: DONE | **Q121 — DONE (volt, 2026-10-29; zeph lane by authorship, unclaimed and taken; this record and `docs/queue-index.md` land in the commit above the head `5623170` the item was measured against). The … | -- |
|
||||
|
||||
## Ids with no `## ` heading
|
||||
|
||||
@@ -220,7 +221,7 @@ Opened as records inside another section. `line` is the record's own opening lin
|
||||
| Q106 | 13171 | 13171 | 11 | Q105 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q107 | 13189 | 13189 | 15 | Q106 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q108 | 13267 | 13263 | 3 | Q106 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q109 | 13270 | 13270 | 8 | Q104 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q109 | 13270 | 13270 | 9 | Q104 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q110 | 13272 | 13272 | 3 | Q109 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q111 | 13274 | 13274 | 7 | Q110 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q112 | 13276 | 13276 | 5 | Q111 | BULLET+BOLD | BOLD-LEAD |
|
||||
@@ -232,7 +233,7 @@ Opened as records inside another section. `line` is the record's own opening lin
|
||||
| Q118 | 13300 | 13300 | 2 | Q111 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q119 | 13305 | 13305 | 2 | Q118 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q120 | 13308 | 13308 | 7 | Q119 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q121 | 13342 | 13342 | 1 | Q107 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q121 | 13342 | 13342 | 2 | Q107 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q122 | 13344 | 13344 | 4 | Q121 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q123 | 13346 | 13346 | 4 | Q122 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q124 | 13350 | 13350 | 1 | Q95 | BULLET+BOLD | BOLD-LEAD |
|
||||
@@ -1390,6 +1391,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q120 \u2014 DONE (volt, 2026-10-29; this record and `docs/queue-index.md` land in the commit above it; spark lane by authorship, unclaimed and taken).** The health check now fails. Before: `python3 \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 5320,
|
||||
"end_line": 13402,
|
||||
"id": "Q121",
|
||||
"kind": "record",
|
||||
"line": 13402,
|
||||
"lines": 1,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q121 \u2014 DONE (volt, 2026-10-29; zeph lane by authorship, unclaimed and taken; this record and `docs/queue-index.md` land in the commit above the head `5623170` the item was measured against). The \u2026"
|
||||
}
|
||||
],
|
||||
"ids_multi_section": {
|
||||
@@ -3931,6 +3945,19 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q120 \u2014 DONE (volt, 2026-10-29; this record and `docs/queue-index.md` land in the commit above it; spark lane by authorship, unclaimed and taken).** The health check now fails. Before: `python3 \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 5320,
|
||||
"end_line": 13402,
|
||||
"id": "Q121",
|
||||
"kind": "record",
|
||||
"line": 13402,
|
||||
"lines": 1,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q121 \u2014 DONE (volt, 2026-10-29; zeph lane by authorship, unclaimed and taken; this record and `docs/queue-index.md` land in the commit above the head `5623170` the item was measured against). The \u2026"
|
||||
}
|
||||
],
|
||||
"nested": [
|
||||
@@ -4119,7 +4146,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"form": "BOLD-LEAD",
|
||||
"id": "Q109",
|
||||
"line": 13270,
|
||||
"refs": 8,
|
||||
"refs": 9,
|
||||
"section": "Q104",
|
||||
"shape": "BULLET+BOLD"
|
||||
},
|
||||
@@ -4227,7 +4254,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"form": "BOLD-LEAD",
|
||||
"id": "Q121",
|
||||
"line": 13342,
|
||||
"refs": 1,
|
||||
"refs": 2,
|
||||
"section": "Q107",
|
||||
"shape": "BULLET+BOLD"
|
||||
},
|
||||
@@ -4264,9 +4291,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"end_line": 8,
|
||||
"line": 1
|
||||
},
|
||||
"queue_bytes": 2080335,
|
||||
"queue_lines": 13401,
|
||||
"queue_sha256": "0b2e463e90984d28203bbf66af98d38c1f432fd0294c8d9e7378d333f0d207b7",
|
||||
"queue_bytes": 2085655,
|
||||
"queue_lines": 13402,
|
||||
"queue_sha256": "d37d9c08e090600cc8817ff6b56c6d5a3dcc2f0490957012d24524269a8d273f",
|
||||
"sections": [
|
||||
{
|
||||
"bytes": 3139,
|
||||
|
||||
@@ -48,9 +48,12 @@ unknown truncated token fails, a real complete-but-wrong value fails, the
|
||||
fixture value classifies TEST-FIXTURE, a self-quoting report file excluded
|
||||
from the population collapses the count, the check over the checker's
|
||||
own directory passes (cell 7, the self-scan leg), the checker's own
|
||||
source bytes do not contain the concatenated fixture value (cell 8, the
|
||||
absence cell, Q96), and a full value under the exhausted beae0b1f stem
|
||||
reports RECOVERED (cell 9, Q96).
|
||||
source bytes carry no fixture value -- each table entry tested on its own,
|
||||
never as a joined string (cell 8, the absence cell, Q96; per-entry form
|
||||
per Q121) -- a full value under the exhausted beae0b1f stem reports
|
||||
RECOVERED (cell 9, Q96), and a two-entry table with one entry's literal
|
||||
inserted names exactly that entry (cell 10, the Q121 cell: the joined form
|
||||
named nothing once the table held two values).
|
||||
|
||||
Correction, reply 130 probe D / interview 117 section 1.4: the
|
||||
2026-10-27 check-in credited cell 7 with proving that no UUID-shaped
|
||||
@@ -244,21 +247,40 @@ def run_check(tree, excludes):
|
||||
return lines, failed
|
||||
|
||||
|
||||
def fixture_literals_in_source(blob, table=None):
|
||||
"""Return the stems whose full fixture value occurs in ``blob``, one per entry.
|
||||
|
||||
Q121: the value must be tested per entry. Joining the table's values into
|
||||
one string and testing that string works only while the table has exactly
|
||||
one entry -- with two it tests ``value1value2``, which occurs nowhere, so
|
||||
both values pass unchecked and the cell stops working by passing.
|
||||
Diagnostics name the stem and the length, never the value (the file's
|
||||
masking rule, so a red report does not re-commit the fault it reports).
|
||||
"""
|
||||
table = KNOWN_FIXTURE if table is None else table
|
||||
faults = []
|
||||
for stem in sorted(table):
|
||||
if table[stem].encode("utf-8") in blob:
|
||||
faults.append("%s (len %d)" % (stem, len(table[stem])))
|
||||
return faults
|
||||
|
||||
|
||||
def selftest():
|
||||
"""Fixture trees; each cell asserts a behaviour, not a tautology."""
|
||||
passed = []
|
||||
|
||||
# Cell 8 (Q96 absence cell): the concatenated fixture value must not
|
||||
# appear in this file's own bytes. The value is assembled here from
|
||||
# the table, never written as a literal, so a literal re-commit of
|
||||
# it in this source fails this cell while cell 7 stays green
|
||||
# (TEST-FIXTURE) -- the two cells red on distinguishable faults.
|
||||
# Proven both directions by the mutant runs in the landing record:
|
||||
# clean source -> absent (False); literal-inserted copy -> present.
|
||||
fixture_value = "".join(KNOWN_FIXTURE.values())
|
||||
# Cell 8 (Q96 absence cell, repaired for Q121): every value in the
|
||||
# fixture table must be absent from this file's own bytes, tested one
|
||||
# entry at a time. The values are assembled in the table from fragments,
|
||||
# never written as literals, so a literal re-commit of any one of them
|
||||
# in this source fails this cell while cell 7 stays green (TEST-FIXTURE)
|
||||
# -- the two cells red on distinguishable faults. Per-entry testing is
|
||||
# what Q121 filed: the joined-string form was vacuous from the second
|
||||
# table entry onward, and cell 10 now measures that case directly.
|
||||
with open(os.path.abspath(__file__), "rb") as fh:
|
||||
assert fixture_value.encode("utf-8") not in fh.read(), \
|
||||
"fixture value literal present in checker source"
|
||||
source_bytes = fh.read()
|
||||
faults = fixture_literals_in_source(source_bytes)
|
||||
assert not faults, "fixture value literal(s) present in checker source: %s" % ", ".join(faults)
|
||||
passed.append("source-absence-passes")
|
||||
|
||||
def check(tree, excludes, want_fail, label):
|
||||
@@ -323,6 +345,28 @@ def selftest():
|
||||
"full value under exhausted stem did not report RECOVERED"
|
||||
check(d, ["report.md"], False, "exhausted-stem-recovers")
|
||||
os.remove(os.path.join(d, "g.md"))
|
||||
# Cell 10 (Q121): the absence leg must see each table entry on its
|
||||
# own. This builds the case the joined-string form could not express:
|
||||
# a two-entry table (the real fixture plus one synthetic stem) with
|
||||
# an entry's literal present in the source. The per-entry scan must
|
||||
# name exactly the inserted stem; the joined form named nothing,
|
||||
# because value1+value2 occurs nowhere. Both insertions are measured
|
||||
# separately, so the cell cannot pass by checking one table position.
|
||||
two_entry = dict(KNOWN_FIXTURE)
|
||||
two_entry["5e0c7a91"] = "5e0c7a91-" "abcd-1234-5678-90abcdef1234"
|
||||
assert len(two_entry) == 2, "cell 10 needs a two-entry table"
|
||||
assert fixture_literals_in_source(source_bytes, two_entry) == [], \
|
||||
"clean source already reports a fixture literal under a two-entry table"
|
||||
for stem in sorted(two_entry):
|
||||
want = "%s (len %d)" % (stem, len(two_entry[stem]))
|
||||
mutant = source_bytes + ("\n# stray re-commit: %s\n" % two_entry[stem]).encode("utf-8")
|
||||
got = fixture_literals_in_source(mutant, two_entry)
|
||||
assert got == [want], "insertion of %s reported %s, want [%s]" % (stem, got, want)
|
||||
both = source_bytes + ("\n".join("# %s" % v for v in two_entry.values())).encode("utf-8")
|
||||
want_both = sorted("%s (len %d)" % (k, len(two_entry[k])) for k in two_entry)
|
||||
assert fixture_literals_in_source(both, two_entry) == want_both, \
|
||||
"both-inserted scan did not name both stems"
|
||||
passed.append("absence-scan-per-entry")
|
||||
# Cell 7 (the sixth cell of reply 113, renumbered by cell 6): run the
|
||||
# check over the checker's own directory and assert rc 0. This is
|
||||
# the leg that was missing: five cells graded fixture trees, none
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Q121 cells for q60_enforce.py's fixture-absence leg (vol, 2026-10-29).
|
||||
|
||||
The defect Q121 filed: selftest cell 8 tested ``"".join(KNOWN_FIXTURE.values())``,
|
||||
so with two table entries it tested a string that occurs nowhere, passed
|
||||
vacuously, and checked neither value. These cells are black box -- the module is
|
||||
run as a subprocess and nothing is imported from it -- and they are the cells
|
||||
the module's own selftest cannot write: a module cannot put a second entry in
|
||||
its own table at run time without shipping one.
|
||||
|
||||
Cells:
|
||||
1. control the shipped module's selftest is green and reports 10 cells.
|
||||
2. two-entry the queue's mutant (second KNOWN_FIXTURE entry plus that
|
||||
entry's full literal in the source) reds NAMING the stem.
|
||||
3. join-legacy the pre-repair algorithm restored inside the cell reds --
|
||||
the case exists, so the cell is not vacuous.
|
||||
4. first-only a scan that reports only the first fault reds on the
|
||||
both-inserted case.
|
||||
5. pre-repair the code at the rev the item was filed against stays GREEN
|
||||
over cell 2's mutant; skipped when that rev is not present.
|
||||
|
||||
Run: python3 wizard-work/zeph/test_q60_absence.py (from the repo root or anywhere)
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
MODULE = os.path.join(HERE, "q60_enforce.py")
|
||||
# The rev WORK-QUEUE.md's Q121 record measures at.
|
||||
FILED_REV = "f17c936"
|
||||
SECOND_STEM = "5e0c7a91"
|
||||
SECOND_VALUE = "5e0c7a91-" "abcd-1234-5678-90abcdef1234"
|
||||
TABLE_SRC = ('KNOWN_FIXTURE = {\n'
|
||||
' "3d79ba82": "3d79ba82-" "1111-2222-3333-444444444444",\n'
|
||||
'}')
|
||||
TABLE_MUT = ('KNOWN_FIXTURE = {\n'
|
||||
' "3d79ba82": "3d79ba82-" "1111-2222-3333-444444444444",\n'
|
||||
' "5e0c7a91": "5e0c7a91-" "abcd-1234-5678-90abcdef1234",\n'
|
||||
'}')
|
||||
PER_ENTRY_BODY = (
|
||||
' table = KNOWN_FIXTURE if table is None else table\n'
|
||||
' faults = []\n'
|
||||
' for stem in sorted(table):\n'
|
||||
' if table[stem].encode("utf-8") in blob:\n'
|
||||
' faults.append("%s (len %d)" % (stem, len(table[stem])))\n'
|
||||
' return faults\n'
|
||||
)
|
||||
JOIN_BODY = (
|
||||
' table = KNOWN_FIXTURE if table is None else table\n'
|
||||
' joined = "".join(table[stem] for stem in sorted(table))\n'
|
||||
' return ["joined (len %d)" % len(joined)] if joined.encode("utf-8") in blob else []\n'
|
||||
)
|
||||
FIRST_ONLY_BODY = (
|
||||
' table = KNOWN_FIXTURE if table is None else table\n'
|
||||
' for stem in sorted(table):\n'
|
||||
' if table[stem].encode("utf-8") in blob:\n'
|
||||
' return ["%s (len %d)" % (stem, len(table[stem]))]\n'
|
||||
' return []\n'
|
||||
)
|
||||
|
||||
|
||||
def read(path):
|
||||
with open(path, "r", encoding="utf-8") as fh:
|
||||
return fh.read()
|
||||
|
||||
|
||||
def run_selftest(path):
|
||||
p = subprocess.run([sys.executable, path, "--selftest"], capture_output=True, text=True)
|
||||
return p.returncode, p.stdout, p.stderr
|
||||
|
||||
|
||||
def write_mutant(text):
|
||||
d = tempfile.mkdtemp(prefix="q121-cell-")
|
||||
path = os.path.join(d, "q60_enforce.py")
|
||||
with open(path, "w", encoding="utf-8") as fh:
|
||||
fh.write(text)
|
||||
return path
|
||||
|
||||
|
||||
def two_entry_mutant(base):
|
||||
"""The queue's construction: second table entry + that literal in source."""
|
||||
out = base.replace(TABLE_SRC, TABLE_MUT, 1)
|
||||
assert out != base, "table pattern moved; cell cannot build its mutant"
|
||||
return out.rstrip("\n") + "\n\n# stray re-commit of fixture: " + SECOND_VALUE + "\n"
|
||||
|
||||
|
||||
class Q121Cells(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.base = read(MODULE)
|
||||
|
||||
def test_1_control_is_green(self):
|
||||
rc, out, err = run_selftest(MODULE)
|
||||
self.assertEqual(rc, 0, "shipped selftest not green: %s" % err[-300:])
|
||||
self.assertIn("SELFTEST: 10 cells passed, 0 failed", out)
|
||||
self.assertIn("SELFTEST PASS absence-scan-per-entry", out)
|
||||
|
||||
def test_2_two_entry_mutant_reds_naming_the_stem(self):
|
||||
rc, out, err = run_selftest(write_mutant(two_entry_mutant(self.base)))
|
||||
self.assertNotEqual(rc, 0, "two-entry mutant stayed green -- vacuous cell is back")
|
||||
self.assertIn(SECOND_STEM, err, "red, but did not name the inserted stem")
|
||||
|
||||
def test_3_join_semantics_is_killed(self):
|
||||
self.assertIn(PER_ENTRY_BODY, self.base, "per-entry body not found; test is stale")
|
||||
rc, _out, err = run_selftest(write_mutant(self.base.replace(PER_ENTRY_BODY, JOIN_BODY, 1)))
|
||||
self.assertNotEqual(rc, 0, "join-semantics scan survived -- cell 10 does not see it")
|
||||
self.assertIn("want", err)
|
||||
|
||||
def test_4_first_fault_only_is_killed(self):
|
||||
self.assertIn(PER_ENTRY_BODY, self.base, "per-entry body not found; test is stale")
|
||||
rc, _out, err = run_selftest(write_mutant(self.base.replace(PER_ENTRY_BODY, FIRST_ONLY_BODY, 1)))
|
||||
self.assertNotEqual(rc, 0, "first-fault-only scan survived the both-inserted case")
|
||||
self.assertIn("both stems", err)
|
||||
|
||||
def test_5_pre_repair_code_was_green_on_the_mutant(self):
|
||||
try:
|
||||
old = subprocess.run(
|
||||
["git", "-C", HERE, "show", "%s:wizard-work/zeph/q60_enforce.py" % FILED_REV],
|
||||
capture_output=True, text=True, check=True).stdout
|
||||
except (subprocess.CalledProcessError, OSError):
|
||||
self.skipTest("rev %s not present in this checkout" % FILED_REV)
|
||||
self.assertNotIn("fixture_literals_in_source", old, "rev %s already carries the repair" % FILED_REV)
|
||||
mutant = old.replace(TABLE_SRC, TABLE_MUT, 1)
|
||||
self.assertNotEqual(mutant, old, "table pattern moved in the filed rev")
|
||||
mutant = mutant.rstrip("\n") + "\n\n# stray re-commit of fixture: " + SECOND_VALUE + "\n"
|
||||
rc, out, _err = run_selftest(write_mutant(mutant))
|
||||
self.assertEqual(rc, 0, "the filed rev already reds over the mutant -- defect not reproduced")
|
||||
self.assertIn("9 cells passed, 0 failed", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
Reference in new issue
Block a user