#!/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 # noqa: E402 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"') # 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}}') # 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({"é": "ü"})) # 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]}) # 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) # 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")) # 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()