import json from pathlib import Path import subprocess import sys import unittest from check import MAX_BYTES, inspect class Cases(unittest.TestCase): def test_duplicate_nested_and_escaped_keys(self): for raw in [b'{"a":1,"a":2}', b'{"x":{"a":1,"a":2}}', b'{"a":1,"\\u0061":2}']: with self.subTest(raw=raw): self.assertEqual(inspect(raw)["errors"][0]["code"], "duplicate_key") def test_same_key_in_different_objects(self): self.assertTrue(inspect(b'[{"id":1},{"id":2}]')["ok"]) def test_nonfinite_constants(self): for raw in [b"NaN", b"Infinity", b"-Infinity"]: self.assertEqual(inspect(raw)["errors"][0]["code"], "non_json_number_constant") def test_large_valid_numbers_are_not_float_converted(self): self.assertTrue(inspect(b'[9007199254740993,1e400,' + b'9' * 5000 + b']')["ok"]) def test_top_level_scalars(self): for raw in [b"null", b"true", b"17", b'"text"']: self.assertTrue(inspect(raw)["ok"]) def test_syntax_and_trailing_data(self): for raw in [b'{"a":}', b"{}{}", b"01", b'"literal\nnewline"']: self.assertEqual(inspect(raw)["errors"][0]["code"], "json_syntax") def test_jsonl_crlf_and_optional_final_lf(self): for raw in [b'null\r\n17\r\n', b'null\n17']: result = inspect(raw, True) self.assertTrue(result["ok"]) self.assertEqual(result["documents"], 2) def test_jsonl_blank_record(self): result = inspect(b'{}\n\nnull\n', True) self.assertEqual(result["errors"], [{"line": 2, "code": "blank_jsonl_line"}]) def test_jsonl_unicode_separator_inside_string(self): self.assertTrue(inspect('"a\u2028b\u0085c"\n'.encode(), True)["ok"]) def test_invalid_utf8_and_bom(self): self.assertEqual(inspect(b'"\xff"')["errors"][0]["code"], "invalid_utf8") self.assertEqual(inspect(b'\xef\xbb\xbf{}')["errors"][0]["code"], "utf8_bom_not_allowed") def test_surrogate_policy(self): self.assertEqual(inspect(b'"\\ud800"')["errors"][0]["code"], "unpaired_surrogate") self.assertTrue(inspect(b'"\\ud834\\udd1e"')["ok"]) def test_input_and_depth_limits(self): self.assertEqual(inspect(b' ' * (MAX_BYTES + 1))["errors"][0]["code"], "input_too_large") self.assertEqual(inspect(b'[' * 129 + b'0' + b']' * 129)["errors"][0]["code"], "input_nesting_limit") self.assertTrue(inspect(b'"' + b'[' * 2000 + b'"')["ok"]) def test_bounded_diagnostics(self): result = inspect(b'\n' * 120, True) self.assertEqual((result["error_count"], len(result["errors"]), result["errors_truncated"]), (120, 100, True)) def test_cli_reports_failure_without_rewriting_input(self): result = subprocess.run([sys.executable, str(Path(__file__).with_name("check.py"))], input=b'{"secret":1,"secret":2}', capture_output=True) self.assertEqual(result.returncode, 1) self.assertNotIn(b"secret", result.stdout) self.assertFalse(json.loads(result.stdout)["ok"]) if __name__ == "__main__": unittest.main()