import json from pathlib import Path import subprocess import sys import unittest from check import MAX_BYTES, MAX_FIELD_CHARACTERS, audit class Cases(unittest.TestCase): def test_quoted_delimiter_and_doubled_quote(self): self.assertTrue(audit(b'id,note\n001,"a,b"\n002,"a""b"\n')["ok"]) def test_multiline_record_and_physical_error_span(self): result = audit(b'id,note\r\n001,"line1\r\nline2",extra\r\n') self.assertEqual(result["errors"][0], {"code": "column_count", "record": 2, "physical_line_start": 2, "physical_line_end": 3, "expected": 2, "actual": 3}) def test_duplicate_and_empty_header(self): self.assertEqual(audit(b'id,id\n001,002\n')["errors"][0]["code"], "duplicate_header") self.assertEqual(audit(b'id, \n001,x\n')["errors"][0]["code"], "empty_header") def test_missing_and_extra_fields(self): result = audit(b'a,b\n1\n1,2,3\n') self.assertEqual([error["actual"] for error in result["errors"]], [1, 3]) def test_blank_record_differs_from_quoted_empty_field(self): self.assertFalse(audit(b'a\n\n')["ok"]) self.assertTrue(audit(b'a\n""\n')["ok"]) def test_trailing_empty_field(self): self.assertTrue(audit(b'a,b\n001,\n')["ok"]) def test_explicit_delimiter_and_no_header(self): result = audit(b'001\t002\n003\t004\n', '\t', False) self.assertEqual((result["ok"], result["columns"], result["data_rows"], result["header"]), (True, 2, 2, None)) def test_dialect_is_not_guessed(self): result = audit(b'a;b\n1;2\n') self.assertEqual(result["columns"], 1) self.assertTrue(result["ok"]) def test_no_type_inference_or_formula_execution(self): result = audit(b'001,=SUM(A1:A2)\n0002,formula\n') self.assertEqual(result["header"], ['001', '=SUM(A1:A2)']) def test_unterminated_quote(self): self.assertEqual(audit(b'a,b\n1,"unterminated')["errors"][0]["code"], "csv_parse_error") def test_not_a_complete_rfc_validator(self): self.assertTrue(audit(b'a,b\n1,ab"cd\n')["ok"]) def test_utf8_bom_and_invalid_utf8(self): self.assertEqual(audit(b'\xef\xbb\xbfa,b\n1,2\n')["header"], ['a', 'b']) self.assertEqual(audit(b'a\n\xff\n')["errors"][0]["code"], "invalid_utf8") def test_resource_limits_and_empty_file(self): self.assertEqual(audit(b'a' * (MAX_BYTES + 1))["errors"][0]["code"], "input_too_large") self.assertEqual(audit(b'a\n' + b'x' * (MAX_FIELD_CHARACTERS + 1))["errors"][0]["code"], "field_too_large") self.assertEqual(audit(b'')["errors"][0]["code"], "empty_input") def test_bounded_diagnostics(self): result = audit(b'a,b\n' + b'1\n' * 120) self.assertEqual((result["error_count"], len(result["errors"]), result["errors_truncated"]), (120, 100, True)) def test_cli_error_exit(self): result = subprocess.run([sys.executable, str(Path(__file__).with_name("check.py"))], input=b'id,id\n1,2\n', capture_output=True) self.assertEqual(result.returncode, 1) self.assertFalse(json.loads(result.stdout)["ok"]) if __name__ == "__main__": unittest.main()