From 07351026d4cdc7fd7573f95d73dd341d10d2ac0a Mon Sep 17 00:00:00 2001 From: volt Date: Mon, 26 Oct 2026 20:05:13 +0000 Subject: [PATCH] volt: beam: Q82 -- test_json_canonical.py becomes 7 discoverable cells; lane gate Ran 191 -> 198 - the file was seven `test_*` functions that nothing called, plus a module-level `print("ALL PASS")`: running it printed a verdict with zero assertions, and `python3 -m unittest discover -s wizard-work/beam -p test_json_canonical.py` collected 0 (rc 5, NO TESTS RAN) while the import still printed ALL PASS. - the seven cells are now methods of one `unittest.TestCase`; discover collects 7, `python3 wizard-work/beam/test_json_canonical.py` runs 7 OK, and `bash wizard-work/beam/CHECK` moves Ran 191 -> Ran 198, rc 0, OK. - the ALL PASS print is deleted; there is no module-level verdict on import. - cells bite, measured against a mutant battery (harness /root/.hermes/profiles/volt/cache/scratch/q82/battery.py, rows in mutant_results.json, one tree per mutant under .../q82/mut/). Control 0/7 dead; `sort_keys=True` -> False: 2 dead (test_basic, test_nested); `allow_nan` allowed with `_normalize`'s non-finite guard removed: 1 dead (test_reject_nan); `ensure_ascii=True`: 1 dead (test_unicode); non-string-key guard removed: 1 dead (test_reject_nonstr_key); `canonical_bytes` returning str: 3 dead (test_bytes, test_roundtrip, test_unicode); bool serialised as "true"/"false": 2 dead (test_basic, test_roundtrip). All 7 cells have a named killer. - one equivalence measured, not counted as a kill: `allow_nan=True` alone is 0/7 dead, because `_normalize` raises CanonicalError on a non-finite float before `json.dumps` is reached. The `allow_nan=False` argument is defence in depth on this API, not a reachable behaviour; the mutant that removes the guard is what a cell can see. CHECK: bash wizard-work/beam/CHECK --- wizard-work/beam/test_json_canonical.py | 91 +++++++++++++++++-------- 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/wizard-work/beam/test_json_canonical.py b/wizard-work/beam/test_json_canonical.py index 4bec93b..2f42851 100644 --- a/wizard-work/beam/test_json_canonical.py +++ b/wizard-work/beam/test_json_canonical.py @@ -1,39 +1,70 @@ -import sys, os, json +#!/usr/bin/env python3 +"""Cells for json_canonical.py: sorted keys, compact separators, UTF-8 pass-through, +the rejection surface, and round-trip. + +Seven cells, one per behaviour the module claims in its docstring. They are +`unittest.TestCase` methods, so `unittest discover` collects them and the lane's +CHECK counts them; there is no module-level verdict printed at import. + +The module path resolves from this file's own directory, never a host path. +""" +import json +import os +import sys +import unittest + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -from json_canonical import canonical, canonical_bytes, CanonicalError +from json_canonical import canonical, canonical_bytes, CanonicalError # noqa: E402 -def test_basic(): - assert canonical({"b":2,"a":1}) == '{"a":1,"b":2}' - assert canonical([3,1,2]) == '[3,1,2]' - assert canonical(True) == 'true' - assert canonical(None) == 'null' - assert canonical("x") == '"x"' -def test_nested(): - assert canonical({"z":{"y":1,"x":2},"a":[1,2]}) == '{"a":[1,2],"z":{"x":2,"y":1}}' +class JsonCanonicalTest(unittest.TestCase): + # cell 1: sorted object keys, list order preserved, the three scalars + def test_basic(self): + self.assertEqual(canonical({"b": 2, "a": 1}), '{"a":1,"b":2}') + self.assertEqual(canonical([3, 1, 2]), "[3,1,2]") + self.assertEqual(canonical(True), "true") + self.assertEqual(canonical(False), "false") + self.assertEqual(canonical(None), "null") + self.assertEqual(canonical("x"), '"x"') -def test_unicode(): - assert canonical({"é":1}) == '{"é":1}' + # cell 2: sorting reaches nested objects and nothing is reordered inside lists + def test_nested(self): + self.assertEqual(canonical({"z": {"y": 1, "x": 2}, "a": [1, 2]}), + '{"a":[1,2],"z":{"x":2,"y":1}}') -def test_reject_nan(): - try: - canonical(float('nan')) - raise AssertionError("expected error") - except CanonicalError: - pass + # cell 3: ensure_ascii=False -- non-ASCII survives as UTF-8, not \u escapes + def test_unicode(self): + self.assertEqual(canonical({"é": "ü"}), '{"é":"ü"}') + self.assertEqual(canonical_bytes({"é": "ü"}), '{"é":"ü"}'.encode("utf-8")) + self.assertNotIn("\\u", canonical({"é": "ü"})) -def test_reject_nonstr_key(): - try: - canonical({1:2}) - raise AssertionError("expected error") - except CanonicalError: - pass + # cell 4: every non-finite float is refused, not serialised as NaN/Infinity + def test_reject_nan(self): + for bad in (float("nan"), float("inf"), float("-inf")): + with self.assertRaises(CanonicalError): + canonical(bad) + with self.assertRaises(CanonicalError): + canonical({"k": [bad]}) -def test_bytes(): - assert canonical_bytes({"a":1}) == b'{"a":1}' + # cell 5: a non-string key is refused wherever it sits, including nested + def test_reject_nonstr_key(self): + for bad in ({1: 2}, {None: 2}, {1.0: 2}, {"a": {2: 3}}): + with self.assertRaises(CanonicalError): + canonical(bad) -def test_roundtrip(): - o = {"a":[1,2,3],"b":{"c":True}} - assert json.loads(canonical(o)) == o + # cell 6: canonical_bytes is bytes, encoded once, byte-identical to the str form + def test_bytes(self): + out = canonical_bytes({"a": 1}) + self.assertIsInstance(out, bytes) + self.assertEqual(out, b'{"a":1}') + self.assertEqual(canonical_bytes([1.5, "é"]), canonical([1.5, "é"]).encode("utf-8")) -print("ALL PASS") + # cell 7: the output parses back to the input value + def test_roundtrip(self): + obj = {"a": [1, 2, 3], "b": {"c": True, "d": None}, "é": "ü", "f": 1.5} + self.assertEqual(json.loads(canonical(obj)), obj) + self.assertEqual(json.loads(canonical_bytes(obj).decode("utf-8")), obj) + + +if __name__ == "__main__": + unittest.main()