Files
volt 36ce415842 volt: beam: Q79 -- test_manifest.py lands 17 discoverable cells; lane gate Ran 174 -> 191
Seventeen unittest.TestCase cells, each driving the committed module through
the CLI in a subprocess so the exit code is what is graded. MOD resolves from
this file's own directory, not a host path.

Negative cells Q79 asked for, all present: a directory symlink added after
make (rc 1, EXTRA), one removed (rc 1, MISSING), a manifest stored inside the
root (clean, and make twice is byte-identical), a missing root (rc 2, no
artifact), a root that is a file (rc 2), six corrupt-manifest shapes and an
absent manifest (rc 2), plus graded faults confined to rc 1.

Bite measured, not asserted: the same suite against edac5cf's manifest.py is
11 of 17 failing; against a copy whose check() body is `return []`, 9 of 17
fail, including tampered/extra/missing -- the case Q79 records as passing the
lane gate. `bash wizard-work/beam/CHECK` -> Ran 191 tests, OK, rc 0.

CHECK: python3 wizard-work/beam/test_manifest.py
2026-10-26 17:58:45 +00:00

244 lines
9.3 KiB
Python

#!/usr/bin/env python3
"""Cells for manifest.py: the 0/1/2 contract, dir symlinks, and self-skip.
Every cell runs the committed module through the CLI in a subprocess, so the
exit code is the thing under test, not an in-process return value. The module
path resolves from this file's own directory, never a host path.
"""
import json
import os
import shutil
import subprocess
import sys
import tempfile
import unittest
MOD = os.path.join(os.path.dirname(os.path.abspath(__file__)), "manifest.py")
FILES = {
"a.txt": b"hello",
"sub/b.bin": b"\x00\x01\x02",
"c.txt": b"world",
}
class ManifestTest(unittest.TestCase):
def setUp(self):
self.tmp = []
def tearDown(self):
for d in self.tmp:
shutil.rmtree(d, ignore_errors=True)
def _scratch(self, prefix="manifest-test-"):
d = tempfile.mkdtemp(prefix=prefix)
self.tmp.append(d)
return d
def _tree(self):
d = self._scratch("manifest-tree-")
for rel, data in FILES.items():
full = os.path.join(d, rel)
os.makedirs(os.path.dirname(full), exist_ok=True)
with open(full, "wb") as f:
f.write(data)
return d
def _run(self, *args):
return subprocess.run([sys.executable, MOD, *args],
capture_output=True, text=True)
def _manifest(self, root):
out = os.path.join(self._scratch("manifest-out-"), "m.json")
r = self._run("make", root, out)
self.assertEqual(r.returncode, 0, r.stderr + r.stdout)
return out
# -- 0: clean ---------------------------------------------------------
def test_roundtrip_is_clean(self):
root = self._tree()
man = self._manifest(root)
r = self._run("check", root, man)
self.assertEqual(r.returncode, 0, r.stderr + r.stdout)
self.assertIn("OK: manifest matches", r.stdout)
def test_make_counts_every_file(self):
root = self._tree()
man = self._manifest(root)
with open(man) as f:
doc = json.load(f)
self.assertEqual(sorted(e["path"] for e in doc["entries"]), sorted(FILES))
self.assertTrue(all(e["type"] == "file" for e in doc["entries"]))
# -- 1: graded fault --------------------------------------------------
def test_tampered_content_exits_1(self):
root = self._tree()
man = self._manifest(root)
with open(os.path.join(root, "a.txt"), "wb") as f:
f.write(b"tampered")
r = self._run("check", root, man)
self.assertEqual(r.returncode, 1, r.stderr)
self.assertIn("HASH_MISMATCH: a.txt", r.stdout)
def test_extra_file_exits_1(self):
root = self._tree()
man = self._manifest(root)
with open(os.path.join(root, "extra.txt"), "w") as f:
f.write("x")
r = self._run("check", root, man)
self.assertEqual(r.returncode, 1, r.stderr)
self.assertIn("EXTRA: extra.txt", r.stdout)
def test_missing_file_exits_1(self):
root = self._tree()
man = self._manifest(root)
os.remove(os.path.join(root, "sub", "b.bin"))
r = self._run("check", root, man)
self.assertEqual(r.returncode, 1, r.stderr)
self.assertIn("MISSING: sub/b.bin", r.stdout)
# -- 1: directory symlinks are entries, not invisible ------------------
def test_dir_symlink_added_after_make_exits_1(self):
root = self._tree()
man = self._manifest(root)
outside = self._scratch("manifest-outside-")
with open(os.path.join(outside, "secret.txt"), "w") as f:
f.write("not in the manifest")
os.symlink(outside, os.path.join(root, "linked_dir"))
r = self._run("check", root, man)
self.assertEqual(r.returncode, 1, r.stderr)
self.assertIn("EXTRA: linked_dir", r.stdout)
self.assertNotIn("secret.txt", r.stdout)
def test_dir_symlink_removed_after_make_exits_1(self):
root = self._tree()
os.symlink(self._scratch("manifest-outside-"), os.path.join(root, "linked_dir"))
man = self._manifest(root)
os.remove(os.path.join(root, "linked_dir"))
r = self._run("check", root, man)
self.assertEqual(r.returncode, 1, r.stderr)
self.assertIn("MISSING: linked_dir", r.stdout)
def test_dir_symlink_recorded_with_target(self):
root = self._tree()
outside = self._scratch("manifest-outside-")
os.symlink(outside, os.path.join(root, "linked_dir"))
man = self._manifest(root)
with open(man) as f:
doc = json.load(f)
row = [e for e in doc["entries"] if e["path"] == "linked_dir"]
self.assertEqual(len(row), 1)
self.assertEqual(row[0]["type"], "symlink")
self.assertEqual(row[0]["target"], outside)
r = self._run("check", root, man)
self.assertEqual(r.returncode, 0, r.stderr + r.stdout)
def test_dir_symlink_is_not_descended(self):
root = self._tree()
os.symlink(os.path.join(root, "sub"), os.path.join(root, "looplink"))
man = self._manifest(root)
with open(man) as f:
doc = json.load(f)
paths = [e["path"] for e in doc["entries"]]
self.assertIn("looplink", paths)
self.assertFalse([p for p in paths if p.startswith("looplink" + os.sep)])
r = self._run("check", root, man)
self.assertEqual(r.returncode, 0, r.stderr + r.stdout)
# -- 0: a manifest stored inside its own root -------------------------
def test_manifest_inside_root_is_not_an_entry(self):
root = self._tree()
man = os.path.join(root, "MANIFEST.json")
r = self._run("make", root, man)
self.assertEqual(r.returncode, 0, r.stderr)
with open(man) as f:
first = json.load(f)
self.assertNotIn("MANIFEST.json", [e["path"] for e in first["entries"]])
self.assertEqual(len(first["entries"]), len(FILES))
# A second make must not grow the entry set, nor change a byte.
with open(man, "rb") as f:
before = f.read()
r = self._run("make", root, man)
self.assertEqual(r.returncode, 0, r.stderr)
with open(man, "rb") as f:
self.assertEqual(f.read(), before)
with open(man) as f:
self.assertEqual(len(json.load(f)["entries"]), len(FILES))
def test_manifest_inside_root_checks_clean(self):
root = self._tree()
man = os.path.join(root, "MANIFEST.json")
self._run("make", root, man)
r = self._run("check", root, man)
self.assertEqual(r.returncode, 0, r.stderr + r.stdout)
self.assertIn("OK: manifest matches", r.stdout)
# -- 2: ungradable ----------------------------------------------------
def test_missing_root_make_exits_2_and_writes_nothing(self):
out = os.path.join(self._scratch("manifest-out-"), "m.json")
r = self._run("make", "/nonexistent-root-manifest-test", out)
self.assertEqual(r.returncode, 2, r.stderr + r.stdout)
self.assertIn("ungradable:", r.stderr)
self.assertFalse(os.path.exists(out))
def test_missing_root_check_exits_2(self):
root = self._tree()
man = self._manifest(root)
r = self._run("check", "/nonexistent-root-manifest-test", man)
self.assertEqual(r.returncode, 2, r.stderr + r.stdout)
self.assertIn("ungradable:", r.stderr)
def test_root_that_is_a_file_exits_2(self):
file_root = os.path.join(self._scratch("manifest-out-"), "not-a-dir")
with open(file_root, "w") as f:
f.write("x")
out = os.path.join(self._scratch("manifest-out-"), "m.json")
r = self._run("make", file_root, out)
self.assertEqual(r.returncode, 2, r.stderr + r.stdout)
self.assertFalse(os.path.exists(out))
root = self._tree()
man = self._manifest(root)
r = self._run("check", file_root, man)
self.assertEqual(r.returncode, 2, r.stderr + r.stdout)
def test_corrupt_manifest_exits_2(self):
root = self._tree()
bad = self._scratch("manifest-bad-")
cases = {
"not-json.json": "{not json",
"empty-object.json": "{}",
"entries-not-list.json": '{"entries": "nope"}',
"unknown-type.json": '{"entries": [{"path": "a.txt", "type": "weird"}]}',
"file-without-hash.json": '{"entries": [{"path": "a.txt", "type": "file"}]}',
"entry-not-object.json": '{"entries": ["a.txt"]}',
}
for name, body in cases.items():
path = os.path.join(bad, name)
with open(path, "w") as f:
f.write(body)
r = self._run("check", root, path)
self.assertEqual(r.returncode, 2, "%s -> %d: %s" % (name, r.returncode, r.stdout))
def test_unreadable_manifest_exits_2(self):
root = self._tree()
r = self._run("check", root, os.path.join(self._scratch(), "no-such.json"))
self.assertEqual(r.returncode, 2, r.stderr + r.stdout)
self.assertIn("ungradable:", r.stderr)
def test_bad_usage_exits_2(self):
r = self._run()
self.assertEqual(r.returncode, 2)
self.assertIn("usage:", r.stderr)
r = self._run("frobnicate", self._tree(), os.path.join(self._scratch(), "m.json"))
self.assertEqual(r.returncode, 2)
self.assertIn("unknown command", r.stderr)
if __name__ == "__main__":
unittest.main(verbosity=2)