mirror of
https://github.com/python/cpython.git
synced 2024-11-24 17:47:13 +01:00
e6b25e9a09
This allows to identify the source of the error.
241 lines
9.9 KiB
Python
241 lines
9.9 KiB
Python
from test.test_json import PyTest, CTest
|
|
|
|
# 2007-10-05
|
|
JSONDOCS = [
|
|
# https://json.org/JSON_checker/test/fail1.json
|
|
'"A JSON payload should be an object or array, not a string."',
|
|
# https://json.org/JSON_checker/test/fail2.json
|
|
'["Unclosed array"',
|
|
# https://json.org/JSON_checker/test/fail3.json
|
|
'{unquoted_key: "keys must be quoted"}',
|
|
# https://json.org/JSON_checker/test/fail4.json
|
|
'["extra comma",]',
|
|
# https://json.org/JSON_checker/test/fail5.json
|
|
'["double extra comma",,]',
|
|
# https://json.org/JSON_checker/test/fail6.json
|
|
'[ , "<-- missing value"]',
|
|
# https://json.org/JSON_checker/test/fail7.json
|
|
'["Comma after the close"],',
|
|
# https://json.org/JSON_checker/test/fail8.json
|
|
'["Extra close"]]',
|
|
# https://json.org/JSON_checker/test/fail9.json
|
|
'{"Extra comma": true,}',
|
|
# https://json.org/JSON_checker/test/fail10.json
|
|
'{"Extra value after close": true} "misplaced quoted value"',
|
|
# https://json.org/JSON_checker/test/fail11.json
|
|
'{"Illegal expression": 1 + 2}',
|
|
# https://json.org/JSON_checker/test/fail12.json
|
|
'{"Illegal invocation": alert()}',
|
|
# https://json.org/JSON_checker/test/fail13.json
|
|
'{"Numbers cannot have leading zeroes": 013}',
|
|
# https://json.org/JSON_checker/test/fail14.json
|
|
'{"Numbers cannot be hex": 0x14}',
|
|
# https://json.org/JSON_checker/test/fail15.json
|
|
'["Illegal backslash escape: \\x15"]',
|
|
# https://json.org/JSON_checker/test/fail16.json
|
|
'[\\naked]',
|
|
# https://json.org/JSON_checker/test/fail17.json
|
|
'["Illegal backslash escape: \\017"]',
|
|
# https://json.org/JSON_checker/test/fail18.json
|
|
'[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]',
|
|
# https://json.org/JSON_checker/test/fail19.json
|
|
'{"Missing colon" null}',
|
|
# https://json.org/JSON_checker/test/fail20.json
|
|
'{"Double colon":: null}',
|
|
# https://json.org/JSON_checker/test/fail21.json
|
|
'{"Comma instead of colon", null}',
|
|
# https://json.org/JSON_checker/test/fail22.json
|
|
'["Colon instead of comma": false]',
|
|
# https://json.org/JSON_checker/test/fail23.json
|
|
'["Bad value", truth]',
|
|
# https://json.org/JSON_checker/test/fail24.json
|
|
"['single quote']",
|
|
# https://json.org/JSON_checker/test/fail25.json
|
|
'["\ttab\tcharacter\tin\tstring\t"]',
|
|
# https://json.org/JSON_checker/test/fail26.json
|
|
'["tab\\ character\\ in\\ string\\ "]',
|
|
# https://json.org/JSON_checker/test/fail27.json
|
|
'["line\nbreak"]',
|
|
# https://json.org/JSON_checker/test/fail28.json
|
|
'["line\\\nbreak"]',
|
|
# https://json.org/JSON_checker/test/fail29.json
|
|
'[0e]',
|
|
# https://json.org/JSON_checker/test/fail30.json
|
|
'[0e+]',
|
|
# https://json.org/JSON_checker/test/fail31.json
|
|
'[0e+-1]',
|
|
# https://json.org/JSON_checker/test/fail32.json
|
|
'{"Comma instead if closing brace": true,',
|
|
# https://json.org/JSON_checker/test/fail33.json
|
|
'["mismatch"}',
|
|
# https://code.google.com/archive/p/simplejson/issues/3
|
|
'["A\u001FZ control characters in string"]',
|
|
]
|
|
|
|
SKIPS = {
|
|
1: "why not have a string payload?",
|
|
18: "spec doesn't specify any nesting limitations",
|
|
}
|
|
|
|
class TestFail:
|
|
def test_failures(self):
|
|
for idx, doc in enumerate(JSONDOCS):
|
|
idx = idx + 1
|
|
if idx in SKIPS:
|
|
self.loads(doc)
|
|
continue
|
|
try:
|
|
self.loads(doc)
|
|
except self.JSONDecodeError:
|
|
pass
|
|
else:
|
|
self.fail(f"Expected failure for fail{idx}.json: {doc!r}")
|
|
|
|
def test_non_string_keys_dict(self):
|
|
data = {'a' : 1, (1, 2) : 2}
|
|
with self.assertRaisesRegex(TypeError,
|
|
'keys must be str, int, float, bool or None, not tuple'):
|
|
self.dumps(data)
|
|
|
|
def test_not_serializable(self):
|
|
import sys
|
|
with self.assertRaisesRegex(TypeError,
|
|
'Object of type module is not JSON serializable') as cm:
|
|
self.dumps(sys)
|
|
self.assertFalse(hasattr(cm.exception, '__notes__'))
|
|
|
|
with self.assertRaises(TypeError) as cm:
|
|
self.dumps([1, [2, 3, sys]])
|
|
self.assertEqual(cm.exception.__notes__,
|
|
['when serializing list item 2',
|
|
'when serializing list item 1'])
|
|
|
|
with self.assertRaises(TypeError) as cm:
|
|
self.dumps((1, (2, 3, sys)))
|
|
self.assertEqual(cm.exception.__notes__,
|
|
['when serializing tuple item 2',
|
|
'when serializing tuple item 1'])
|
|
|
|
with self.assertRaises(TypeError) as cm:
|
|
self.dumps({'a': {'b': sys}})
|
|
self.assertEqual(cm.exception.__notes__,
|
|
["when serializing dict item 'b'",
|
|
"when serializing dict item 'a'"])
|
|
|
|
def test_truncated_input(self):
|
|
test_cases = [
|
|
('', 'Expecting value', 0),
|
|
('[', 'Expecting value', 1),
|
|
('[42', "Expecting ',' delimiter", 3),
|
|
('[42,', 'Expecting value', 4),
|
|
('["', 'Unterminated string starting at', 1),
|
|
('["spam', 'Unterminated string starting at', 1),
|
|
('["spam"', "Expecting ',' delimiter", 7),
|
|
('["spam",', 'Expecting value', 8),
|
|
('{', 'Expecting property name enclosed in double quotes', 1),
|
|
('{"', 'Unterminated string starting at', 1),
|
|
('{"spam', 'Unterminated string starting at', 1),
|
|
('{"spam"', "Expecting ':' delimiter", 7),
|
|
('{"spam":', 'Expecting value', 8),
|
|
('{"spam":42', "Expecting ',' delimiter", 10),
|
|
('{"spam":42,', 'Expecting property name enclosed in double quotes', 11),
|
|
]
|
|
test_cases += [
|
|
('"', 'Unterminated string starting at', 0),
|
|
('"spam', 'Unterminated string starting at', 0),
|
|
]
|
|
for data, msg, idx in test_cases:
|
|
with self.assertRaises(self.JSONDecodeError) as cm:
|
|
self.loads(data)
|
|
err = cm.exception
|
|
self.assertEqual(err.msg, msg)
|
|
self.assertEqual(err.pos, idx)
|
|
self.assertEqual(err.lineno, 1)
|
|
self.assertEqual(err.colno, idx + 1)
|
|
self.assertEqual(str(err),
|
|
'%s: line 1 column %d (char %d)' %
|
|
(msg, idx + 1, idx))
|
|
|
|
def test_unexpected_data(self):
|
|
test_cases = [
|
|
('[,', 'Expecting value', 1),
|
|
('{"spam":[}', 'Expecting value', 9),
|
|
('[42:', "Expecting ',' delimiter", 3),
|
|
('[42 "spam"', "Expecting ',' delimiter", 4),
|
|
('[42,]', "Illegal trailing comma before end of array", 3),
|
|
('{"spam":[42}', "Expecting ',' delimiter", 11),
|
|
('["]', 'Unterminated string starting at', 1),
|
|
('["spam":', "Expecting ',' delimiter", 7),
|
|
('["spam",]', "Illegal trailing comma before end of array", 7),
|
|
('{:', 'Expecting property name enclosed in double quotes', 1),
|
|
('{,', 'Expecting property name enclosed in double quotes', 1),
|
|
('{42', 'Expecting property name enclosed in double quotes', 1),
|
|
('[{]', 'Expecting property name enclosed in double quotes', 2),
|
|
('{"spam",', "Expecting ':' delimiter", 7),
|
|
('{"spam"}', "Expecting ':' delimiter", 7),
|
|
('[{"spam"]', "Expecting ':' delimiter", 8),
|
|
('{"spam":}', 'Expecting value', 8),
|
|
('[{"spam":]', 'Expecting value', 9),
|
|
('{"spam":42 "ham"', "Expecting ',' delimiter", 11),
|
|
('[{"spam":42]', "Expecting ',' delimiter", 11),
|
|
('{"spam":42,}', "Illegal trailing comma before end of object", 10),
|
|
('{"spam":42 , }', "Illegal trailing comma before end of object", 11),
|
|
('[123 , ]', "Illegal trailing comma before end of array", 6),
|
|
]
|
|
for data, msg, idx in test_cases:
|
|
with self.assertRaises(self.JSONDecodeError) as cm:
|
|
self.loads(data)
|
|
err = cm.exception
|
|
self.assertEqual(err.msg, msg)
|
|
self.assertEqual(err.pos, idx)
|
|
self.assertEqual(err.lineno, 1)
|
|
self.assertEqual(err.colno, idx + 1)
|
|
self.assertEqual(str(err),
|
|
'%s: line 1 column %d (char %d)' %
|
|
(msg, idx + 1, idx))
|
|
|
|
def test_extra_data(self):
|
|
test_cases = [
|
|
('[]]', 'Extra data', 2),
|
|
('{}}', 'Extra data', 2),
|
|
('[],[]', 'Extra data', 2),
|
|
('{},{}', 'Extra data', 2),
|
|
]
|
|
test_cases += [
|
|
('42,"spam"', 'Extra data', 2),
|
|
('"spam",42', 'Extra data', 6),
|
|
]
|
|
for data, msg, idx in test_cases:
|
|
with self.assertRaises(self.JSONDecodeError) as cm:
|
|
self.loads(data)
|
|
err = cm.exception
|
|
self.assertEqual(err.msg, msg)
|
|
self.assertEqual(err.pos, idx)
|
|
self.assertEqual(err.lineno, 1)
|
|
self.assertEqual(err.colno, idx + 1)
|
|
self.assertEqual(str(err),
|
|
'%s: line 1 column %d (char %d)' %
|
|
(msg, idx + 1, idx))
|
|
|
|
def test_linecol(self):
|
|
test_cases = [
|
|
('!', 1, 1, 0),
|
|
(' !', 1, 2, 1),
|
|
('\n!', 2, 1, 1),
|
|
('\n \n\n !', 4, 6, 10),
|
|
]
|
|
for data, line, col, idx in test_cases:
|
|
with self.assertRaises(self.JSONDecodeError) as cm:
|
|
self.loads(data)
|
|
err = cm.exception
|
|
self.assertEqual(err.msg, 'Expecting value')
|
|
self.assertEqual(err.pos, idx)
|
|
self.assertEqual(err.lineno, line)
|
|
self.assertEqual(err.colno, col)
|
|
self.assertEqual(str(err),
|
|
'Expecting value: line %s column %d (char %d)' %
|
|
(line, col, idx))
|
|
|
|
class TestPyFail(TestFail, PyTest): pass
|
|
class TestCFail(TestFail, CTest): pass
|