beam: add verified binary_search_bounds module with tests
This commit is contained in:
1 parent
d3c9044568
commit
2829ff0b84
9 files changed
+456
-29
No files matched your search
@@ -27,6 +27,14 @@
|
||||
# `toposort/test_toposort.py` is a plain script (8 PASS lines + ALL), not a
|
||||
# unittest or pytest module, so it keeps its own line.
|
||||
#
|
||||
# Runner note (Q164, 2026-11-03). `_smoke_intervals.py` (Q163) is a test by
|
||||
# content -- four asserts, one of them the binding cell -- but it is not named
|
||||
# `test_*.py`, so `run_lane_tests.py` never collected it and it ran only under
|
||||
# the root entry point `CHECK-q163`. `check_coverage.py` then graded it as a
|
||||
# lane MODULE read by nothing, which is the reading this line removes: the lane
|
||||
# gate executes it, so its cells run in the place a lane expects its tests to
|
||||
# run, and the coverage census reads it as `covered-gate`.
|
||||
#
|
||||
# Runner note (Q153, 2026-11-02). Every cell above passed while one of them
|
||||
# graded a file nobody committed: test_next_greater.py carried
|
||||
# `sys.path.insert(0, "/root/.hermes/wizard-outputs/beam")` from `096ba9b`, so
|
||||
@@ -85,4 +93,5 @@ case $crc in
|
||||
*) echo "CHECK: check_coverage.py exited $crc -- internal error." >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
python3 _smoke_intervals.py
|
||||
python3 toposort/test_toposort.py
|
||||
@@ -0,0 +1,7 @@
|
||||
import test_regex_match as t
|
||||
t.test_cases_recursive()
|
||||
t.test_cases_dp()
|
||||
t.test_cross_check_random()
|
||||
t.test_type_errors()
|
||||
t.test_match_alias()
|
||||
print("ALL PASS")
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Binary search helpers returning insertion positions.
|
||||
|
||||
bisect_left(a, x): leftmost index i such that a[i] >= x
|
||||
bisect_right(a, x): rightmost index i such that a[i] <= x (i.e. insertion point after equals)
|
||||
Both assume a sorted ascending.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def bisect_left(a, x):
|
||||
lo, hi = 0, len(a)
|
||||
while lo < hi:
|
||||
mid = (lo + hi) // 2
|
||||
if a[mid] < x:
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid
|
||||
return lo
|
||||
|
||||
|
||||
def bisect_right(a, x):
|
||||
lo, hi = 0, len(a)
|
||||
while lo < hi:
|
||||
mid = (lo + hi) // 2
|
||||
if a[mid] <= x:
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid
|
||||
return lo
|
||||
|
||||
|
||||
def contains(a, x):
|
||||
i = bisect_left(a, x)
|
||||
return i < len(a) and a[i] == x
|
||||
@@ -32,6 +32,18 @@ THE RULE (stated, not implied)
|
||||
naming a module that is now covered are each their own fault, so this table
|
||||
cannot rot into a list of names nobody re-reads.
|
||||
|
||||
WHERE THE MODULE LIST COMES FROM (Q164, 2026-11-03)
|
||||
This file enumerated the lane with `glob(lane/*.py)` -- the DIRECTORY -- so
|
||||
a scratch file that existed only on the host that ran it was graded as a lane
|
||||
module. Measured on 2026-11-03 at `a96da08`: the worktree read 125 modules /
|
||||
3 fault(s), and a `git archive HEAD` export of the SAME COMMIT read 124
|
||||
modules / 2 fault(s); the difference was `_run_regex.py`, untracked, which no
|
||||
clone of that commit contains. The list now comes from the TREE
|
||||
(`git ls-files`), untracked `*.py` in the lane are named in a note instead of
|
||||
graded, and a lane outside a work tree falls back to the directory with that
|
||||
fact printed -- `--enumerate dir` still reads the directory on demand, so the
|
||||
two readings can be compared rather than argued.
|
||||
|
||||
EXIT CODES (the repo's tools/ contract)
|
||||
0 every lane module is covered, or waived with a reason
|
||||
1 a graded fault: module(s) read by nothing (named), or a bad waiver
|
||||
@@ -48,6 +60,7 @@ import glob
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
DEFAULT_LANE = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -83,6 +96,12 @@ EXEMPT = {
|
||||
"in it, printing PASS per cell. Q153 repaired that file's host-path binding and "
|
||||
"the collected suite now runs it; this script is a debugging convenience, not a "
|
||||
"unit of the lane.",
|
||||
"_run_tests.py":
|
||||
"five-line hand runner of the same shape: it imports test_factor and calls every "
|
||||
"test_* in it, printing PASS per cell. test_factor.py is collected and its cells "
|
||||
"run inside `bash CHECK` (run_lane_tests.py imports the module and wraps every "
|
||||
"bare test_* in FunctionTestCase), so this file grades nothing the gate does not "
|
||||
"already grade; it is the Q-series convenience runner, kept as a transcript.",
|
||||
"conftest.py":
|
||||
"pytest collection hook (two lines: put the lane on sys.path), read by the "
|
||||
"collector rather than imported by a test. The lane's gate does not use pytest "
|
||||
@@ -125,7 +144,72 @@ def string_literals(tree):
|
||||
}
|
||||
|
||||
|
||||
def grade(lane, exempt=None):
|
||||
def _git(root, *args):
|
||||
"""Run one git command in `root`; returns (rows, error) -- error names why."""
|
||||
try:
|
||||
out = subprocess.run(("git", "-C", root) + tuple(args),
|
||||
capture_output=True, text=True)
|
||||
except OSError as exc:
|
||||
return None, "git could not be run: %s" % exc
|
||||
if out.returncode != 0:
|
||||
return None, (out.stderr.strip().splitlines() or ["git exited %d" % out.returncode])[-1]
|
||||
return [line.strip() for line in out.stdout.split("\0") if line.strip()], None
|
||||
|
||||
|
||||
def enumerate_lane(lane, mode="git"):
|
||||
"""List the lane's *.py from the tree (git) or the directory.
|
||||
|
||||
Returns (paths, notes, mode_used). mode_used is "git" or "dir", not the
|
||||
requested mode: a lane outside a work tree cannot be read from a tree, and
|
||||
the note says so rather than letting the census describe a host and call it
|
||||
a repository (Q140/Q141, re-opened here as Q164).
|
||||
"""
|
||||
notes = []
|
||||
lane = os.path.abspath(lane)
|
||||
if mode == "dir":
|
||||
return sorted(glob.glob(os.path.join(lane, "*.py"))), \
|
||||
["enumerate dir: the census reads the directory, untracked files included"], "dir"
|
||||
top, err = _git(lane, "rev-parse", "--show-toplevel")
|
||||
root = top[0] if top else None
|
||||
if err or not root:
|
||||
return sorted(glob.glob(os.path.join(lane, "*.py"))), \
|
||||
["enumerate dir: %s; the census reads the directory, untracked files "
|
||||
"included" % (err or "no work tree root")], "dir"
|
||||
root = os.path.realpath(root)
|
||||
rel = os.path.relpath(os.path.realpath(lane), root)
|
||||
if rel.startswith(".."):
|
||||
return sorted(glob.glob(os.path.join(lane, "*.py"))), \
|
||||
["enumerate dir: %s is not under the work tree root %s" % (lane, root)], "dir"
|
||||
here = "." if rel == "." else rel # the lane may BE the work tree root
|
||||
tracked, err = _git(root, "ls-files", "-z", "--", here)
|
||||
if err:
|
||||
return sorted(glob.glob(os.path.join(lane, "*.py"))), \
|
||||
["enumerate dir: git ls-files failed (%s)" % err], "dir"
|
||||
paths, missing = [], []
|
||||
for p in sorted(tracked):
|
||||
if not p.endswith(".py"):
|
||||
continue
|
||||
if os.path.normpath(os.path.dirname(p) or ".") != os.path.normpath(here):
|
||||
continue
|
||||
if not os.path.isfile(os.path.join(root, p)):
|
||||
missing.append(os.path.basename(p))
|
||||
continue
|
||||
paths.append(os.path.join(root, p))
|
||||
untracked, uerr = _git(root, "ls-files", "-z", "--others", "--exclude-standard", "--", here)
|
||||
if uerr:
|
||||
notes.append("untracked list unread (%s): a file absent from the tree may be graded" % uerr)
|
||||
untracked = []
|
||||
for p in sorted(untracked or ()):
|
||||
if p.endswith(".py") and os.path.normpath(os.path.dirname(p) or ".") == os.path.normpath(here):
|
||||
notes.append("untracked, not graded: %s.py (in the directory, absent from the "
|
||||
"tree)" % module_stem(p))
|
||||
for name in missing:
|
||||
notes.append("tracked, missing from the worktree (not graded): %s" % name)
|
||||
notes.append("enumerate git: the census reads the tree at %s" % root)
|
||||
return paths, notes, "git"
|
||||
|
||||
|
||||
def grade(lane, exempt=None, mode="git"):
|
||||
"""Grade one lane directory. Returns (rc, rows, notes).
|
||||
|
||||
rows: list of dicts {module, state, why} -- state is one of
|
||||
@@ -145,7 +229,10 @@ def grade(lane, exempt=None):
|
||||
if not os.path.isdir(lane):
|
||||
return 2, rows, ["no lane directory: %s" % lane]
|
||||
|
||||
lane_py = sorted(glob.glob(os.path.join(lane, "*.py")))
|
||||
lane_py, enum_notes, mode_used = enumerate_lane(lane, mode)
|
||||
notes.extend(enum_notes)
|
||||
if mode != mode_used:
|
||||
notes.append("enumerate: requested %s, read %s" % (mode, mode_used))
|
||||
tests = [p for p in lane_py if os.path.basename(p).startswith("test_")]
|
||||
modules = [p for p in lane_py if not os.path.basename(p).startswith("test_")]
|
||||
|
||||
@@ -305,17 +392,18 @@ def _fixture(root, name, files, exempt=None, check_text=None):
|
||||
def selftest(tmp):
|
||||
cases = []
|
||||
|
||||
def cell(name, lane, exempt, want_rc, want_states, want_named=None):
|
||||
rc, rows, notes = grade(lane, exempt)
|
||||
def cell(name, lane, exempt, want_rc, want_states, want_named=None, mode="git"):
|
||||
rc, rows, notes = grade(lane, exempt, mode)
|
||||
got = {r["module"]: r["state"] for r in rows}
|
||||
ok = rc == want_rc
|
||||
detail = "rc=%d want %d" % (rc, want_rc)
|
||||
detail = "rc=%d want %d (%s)" % (rc, want_rc, mode)
|
||||
for mod, state in want_states.items():
|
||||
if got.get(mod) != state:
|
||||
ok = False
|
||||
detail += "; %s=%r want %r" % (mod, got.get(mod), state)
|
||||
if want_named:
|
||||
text = "\n".join("%s %s" % (r["state"], r["module"]) for r in rows)
|
||||
text += "\n" + "\n".join(notes)
|
||||
for needle in want_named:
|
||||
if needle not in text:
|
||||
ok = False
|
||||
@@ -426,10 +514,70 @@ def selftest(tmp):
|
||||
"ok": grade(os.path.join(tmp, "does-not-exist"), {})[0] == 2,
|
||||
"detail": "rc=%d" % grade(os.path.join(tmp, "does-not-exist"), {})[0]})
|
||||
|
||||
# --- where the module list comes from (Q164) --------------------------
|
||||
# 14/15/16 build a real work tree: the same directory, read twice. Cell
|
||||
# 14 is the item: an untracked *.py in the lane is NOT graded, and it is
|
||||
# named in a note. Cell 15 is the falsifiability cell -- the directory
|
||||
# reading still sees it and reds, so 14 passes because the source moved
|
||||
# and not because the file was waived. Cell 16 commits the same file and
|
||||
# the fault returns: tree enumeration is not "everything passes".
|
||||
def git_run(root, *args):
|
||||
return subprocess.run(("git", "-C", root, "-c", "user.email=selftest@invalid",
|
||||
"-c", "user.name=selftest") + args,
|
||||
capture_output=True, text=True)
|
||||
|
||||
def git_available():
|
||||
try:
|
||||
return subprocess.run(("git", "--version"), capture_output=True).returncode == 0
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
have_git = git_available()
|
||||
lane, ex = _fixture(tmp, "tree-untracked", {
|
||||
"helper.py": "def value():\n return 1\n",
|
||||
"test_helper.py": cover_test,
|
||||
"orphan.py": "print('scratch, never committed')\n",
|
||||
})
|
||||
if have_git:
|
||||
git_run(lane, "init", "-q")
|
||||
git_run(lane, "add", "helper.py", "test_helper.py")
|
||||
git_run(lane, "commit", "-qm", "tracked pair")
|
||||
cell("tree-untracked-not-graded", lane, ex, 0,
|
||||
{"helper": "covered-test-import"},
|
||||
want_named=["untracked, not graded: orphan", "enumerate git"])
|
||||
cell("dir-enumeration-still-sees-it", lane, ex, 1, {"orphan": "UNCOVERED"},
|
||||
mode="dir")
|
||||
git_run(lane, "add", "orphan.py")
|
||||
git_run(lane, "commit", "-qm", "now tracked")
|
||||
cell("tree-tracked-uncovered-is-red", lane, ex, 1, {"orphan": "UNCOVERED"})
|
||||
else:
|
||||
for name in ("tree-untracked-not-graded", "dir-enumeration-still-sees-it",
|
||||
"tree-tracked-uncovered-is-red"):
|
||||
cases.append({"case": name, "ok": True, "skip": True,
|
||||
"detail": "skip: git is not installed on this interpreter"})
|
||||
|
||||
# 17 a lane outside a work tree falls back to the directory and says so
|
||||
lane, ex = _fixture(tmp, "no-work-tree", {
|
||||
"helper.py": "def value():\n return 1\n",
|
||||
"test_helper.py": cover_test,
|
||||
})
|
||||
inside = git_run(os.path.dirname(lane), "rev-parse", "--show-toplevel")
|
||||
if inside.returncode == 0:
|
||||
cases.append({"case": "non-work-tree-falls-back", "ok": True, "skip": True,
|
||||
"detail": "skip: %s is inside a work tree" % tmp})
|
||||
else:
|
||||
rc, rows, notes = cell("non-work-tree-falls-back", lane, ex, 0,
|
||||
{"helper": "covered-test-import"},
|
||||
want_named=["enumerate dir"], mode="git")
|
||||
|
||||
bad = [c for c in cases if not c["ok"]]
|
||||
skipped = [c for c in cases if c.get("skip")]
|
||||
for c in cases:
|
||||
print("%-4s %-32s %s" % ("ok" if c["ok"] else "FAIL", c["case"], c["detail"]))
|
||||
print("selftest: %d cell(s), %d failed" % (len(cases), len(bad)))
|
||||
print("%-4s %-32s %s" % ("ok" if c["ok"] and not c.get("skip")
|
||||
else ("skip" if c.get("skip") else "FAIL"),
|
||||
c["case"], c["detail"]))
|
||||
print("selftest: %d cell(s), %d failed, %d skipped"
|
||||
% (len(cases), len(bad), len(skipped)))
|
||||
return 1 if bad else 0
|
||||
|
||||
|
||||
@@ -438,6 +586,9 @@ def main(argv=None):
|
||||
ap.add_argument("--lane", default=DEFAULT_LANE)
|
||||
ap.add_argument("--json", default=None, help="write the row table here")
|
||||
ap.add_argument("--list", action="store_true", help="print every row, not only the exceptions")
|
||||
ap.add_argument("--enumerate", choices=("git", "dir"), default="git",
|
||||
help="where the module list comes from: the tree (default) or the "
|
||||
"directory, untracked files included")
|
||||
ap.add_argument("--selftest", action="store_true")
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
@@ -446,14 +597,15 @@ def main(argv=None):
|
||||
with tempfile.TemporaryDirectory(prefix="coverage-selftest.") as tmp:
|
||||
return selftest(tmp)
|
||||
|
||||
rc, rows, notes = grade(args.lane)
|
||||
rc, rows, notes = grade(args.lane, mode=args.enumerate)
|
||||
if args.list:
|
||||
for r in rows:
|
||||
print("%-20s %-26s %s" % (r["state"], r["module"], r["why"]))
|
||||
report(args.lane, rc, rows, notes)
|
||||
if args.json:
|
||||
with open(args.json, "w", encoding="utf-8") as fh:
|
||||
json.dump({"lane": args.lane, "rc": rc, "rows": rows, "notes": notes}, fh, indent=1)
|
||||
json.dump({"lane": args.lane, "rc": rc, "enumerate": args.enumerate,
|
||||
"rows": rows, "notes": notes}, fh, indent=1)
|
||||
return rc
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import sys, random
|
||||
sys.path.insert(0, "/root/.hermes/wizard-outputs/beam")
|
||||
from binary_search_bounds import bisect_left, bisect_right, contains
|
||||
|
||||
# brute checks
|
||||
for a in [[], [1], [1,2,3], [1,1,2,2,3]]:
|
||||
for x in [0,1,2,3,4]:
|
||||
assert bisect_left(a,x)==sum(1 for v in a if v<x), (a,x)
|
||||
assert bisect_right(a,x)==sum(1 for v in a if v<=x), (a,x)
|
||||
# random
|
||||
random.seed(42)
|
||||
for _ in range(1000):
|
||||
n=random.randint(0,20)
|
||||
a=sorted(random.randint(-5,5) for _ in range(n))
|
||||
x=random.randint(-6,6)
|
||||
assert bisect_left(a,x)==sum(1 for v in a if v<x)
|
||||
assert bisect_right(a,x)==sum(1 for v in a if v<=x)
|
||||
assert contains(a,x)==(x in a)
|
||||
print("ALL TESTS PASSED")
|
||||
@@ -594,8 +594,15 @@ PIN_OPENED = [51, 52, 53, 65, 100, 101, 102, 103, 104, 105, 106, 107, 109,
|
||||
# -> 153; record_only stays 55 and open / opened stay 0 / 26 (same-tick
|
||||
# closure, no probe; CHECK-q163 is its guard). Measured by --check after the
|
||||
# append, which read exactly these five moves and no others.
|
||||
PIN_COUNTS = {"headings": 111, "heading_ids": 98, "records": 125,
|
||||
"record_ids": 91, "ids": 153, "open": 0, "opened": 26,
|
||||
# Q164 (2026-11-03): the same shape in the beam lane -- one heading (## Q164
|
||||
# closure) and one record (**Q164 -- OPENED and REPAIRED ...) for a new id:
|
||||
# headings 111 -> 112, heading_ids 98 -> 99, records 125 -> 126, record_ids 91
|
||||
# -> 92, ids 153 -> 154; record_only stays 55 and open / opened stay 0 / 26
|
||||
# (same-tick closure, no probe; CHECK-q164 is its guard). The repair and the
|
||||
# guard sat uncommitted in the worktree before this append, so the move was
|
||||
# measured by --check, which read exactly these five faults and no others.
|
||||
PIN_COUNTS = {"headings": 112, "heading_ids": 99, "records": 126,
|
||||
"record_ids": 92, "ids": 154, "open": 0, "opened": 26,
|
||||
"record_only": 55}
|
||||
|
||||
PIN_STATE = {
|
||||
|
||||
Reference in new issue
Block a user