1from test.test_json import PyTest, CTest
2
3# 2007-10-05
4JSONDOCS = [
5    # http://json.org/JSON_checker/test/fail1.json
6    '"A JSON payload should be an object or array, not a string."',
7    # http://json.org/JSON_checker/test/fail2.json
8    '["Unclosed array"',
9    # http://json.org/JSON_checker/test/fail3.json
10    '{unquoted_key: "keys must be quoted"}',
11    # http://json.org/JSON_checker/test/fail4.json
12    '["extra comma",]',
13    # http://json.org/JSON_checker/test/fail5.json
14    '["double extra comma",,]',
15    # http://json.org/JSON_checker/test/fail6.json
16    '[   , "<-- missing value"]',
17    # http://json.org/JSON_checker/test/fail7.json
18    '["Comma after the close"],',
19    # http://json.org/JSON_checker/test/fail8.json
20    '["Extra close"]]',
21    # http://json.org/JSON_checker/test/fail9.json
22    '{"Extra comma": true,}',
23    # http://json.org/JSON_checker/test/fail10.json
24    '{"Extra value after close": true} "misplaced quoted value"',
25    # http://json.org/JSON_checker/test/fail11.json
26    '{"Illegal expression": 1 + 2}',
27    # http://json.org/JSON_checker/test/fail12.json
28    '{"Illegal invocation": alert()}',
29    # http://json.org/JSON_checker/test/fail13.json
30    '{"Numbers cannot have leading zeroes": 013}',
31    # http://json.org/JSON_checker/test/fail14.json
32    '{"Numbers cannot be hex": 0x14}',
33    # http://json.org/JSON_checker/test/fail15.json
34    '["Illegal backslash escape: \\x15"]',
35    # http://json.org/JSON_checker/test/fail16.json
36    '[\\naked]',
37    # http://json.org/JSON_checker/test/fail17.json
38    '["Illegal backslash escape: \\017"]',
39    # http://json.org/JSON_checker/test/fail18.json
40    '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]',
41    # http://json.org/JSON_checker/test/fail19.json
42    '{"Missing colon" null}',
43    # http://json.org/JSON_checker/test/fail20.json
44    '{"Double colon":: null}',
45    # http://json.org/JSON_checker/test/fail21.json
46    '{"Comma instead of colon", null}',
47    # http://json.org/JSON_checker/test/fail22.json
48    '["Colon instead of comma": false]',
49    # http://json.org/JSON_checker/test/fail23.json
50    '["Bad value", truth]',
51    # http://json.org/JSON_checker/test/fail24.json
52    "['single quote']",
53    # http://json.org/JSON_checker/test/fail25.json
54    '["\ttab\tcharacter\tin\tstring\t"]',
55    # http://json.org/JSON_checker/test/fail26.json
56    '["tab\\   character\\   in\\  string\\  "]',
57    # http://json.org/JSON_checker/test/fail27.json
58    '["line\nbreak"]',
59    # http://json.org/JSON_checker/test/fail28.json
60    '["line\\\nbreak"]',
61    # http://json.org/JSON_checker/test/fail29.json
62    '[0e]',
63    # http://json.org/JSON_checker/test/fail30.json
64    '[0e+]',
65    # http://json.org/JSON_checker/test/fail31.json
66    '[0e+-1]',
67    # http://json.org/JSON_checker/test/fail32.json
68    '{"Comma instead if closing brace": true,',
69    # http://json.org/JSON_checker/test/fail33.json
70    '["mismatch"}',
71    # http://code.google.com/p/simplejson/issues/detail?id=3
72    '["A\u001FZ control characters in string"]',
73]
74
75SKIPS = {
76    1: "why not have a string payload?",
77    18: "spec doesn't specify any nesting limitations",
78}
79
80class TestFail:
81    def test_failures(self):
82        for idx, doc in enumerate(JSONDOCS):
83            idx = idx + 1
84            if idx in SKIPS:
85                self.loads(doc)
86                continue
87            try:
88                self.loads(doc)
89            except self.JSONDecodeError:
90                pass
91            else:
92                self.fail("Expected failure for fail{0}.json: {1!r}".format(idx, doc))
93
94    def test_non_string_keys_dict(self):
95        data = {'a' : 1, (1, 2) : 2}
96        with self.assertRaisesRegex(TypeError,
97                'keys must be str, int, float, bool or None, not tuple'):
98            self.dumps(data)
99
100    def test_not_serializable(self):
101        import sys
102        with self.assertRaisesRegex(TypeError,
103                'Object of type module is not JSON serializable'):
104            self.dumps(sys)
105
106    def test_truncated_input(self):
107        test_cases = [
108            ('', 'Expecting value', 0),
109            ('[', 'Expecting value', 1),
110            ('[42', "Expecting ',' delimiter", 3),
111            ('[42,', 'Expecting value', 4),
112            ('["', 'Unterminated string starting at', 1),
113            ('["spam', 'Unterminated string starting at', 1),
114            ('["spam"', "Expecting ',' delimiter", 7),
115            ('["spam",', 'Expecting value', 8),
116            ('{', 'Expecting property name enclosed in double quotes', 1),
117            ('{"', 'Unterminated string starting at', 1),
118            ('{"spam', 'Unterminated string starting at', 1),
119            ('{"spam"', "Expecting ':' delimiter", 7),
120            ('{"spam":', 'Expecting value', 8),
121            ('{"spam":42', "Expecting ',' delimiter", 10),
122            ('{"spam":42,', 'Expecting property name enclosed in double quotes', 11),
123        ]
124        test_cases += [
125            ('"', 'Unterminated string starting at', 0),
126            ('"spam', 'Unterminated string starting at', 0),
127        ]
128        for data, msg, idx in test_cases:
129            with self.assertRaises(self.JSONDecodeError) as cm:
130                self.loads(data)
131            err = cm.exception
132            self.assertEqual(err.msg, msg)
133            self.assertEqual(err.pos, idx)
134            self.assertEqual(err.lineno, 1)
135            self.assertEqual(err.colno, idx + 1)
136            self.assertEqual(str(err),
137                             '%s: line 1 column %d (char %d)' %
138                             (msg, idx + 1, idx))
139
140    def test_unexpected_data(self):
141        test_cases = [
142            ('[,', 'Expecting value', 1),
143            ('{"spam":[}', 'Expecting value', 9),
144            ('[42:', "Expecting ',' delimiter", 3),
145            ('[42 "spam"', "Expecting ',' delimiter", 4),
146            ('[42,]', 'Expecting value', 4),
147            ('{"spam":[42}', "Expecting ',' delimiter", 11),
148            ('["]', 'Unterminated string starting at', 1),
149            ('["spam":', "Expecting ',' delimiter", 7),
150            ('["spam",]', 'Expecting value', 8),
151            ('{:', 'Expecting property name enclosed in double quotes', 1),
152            ('{,', 'Expecting property name enclosed in double quotes', 1),
153            ('{42', 'Expecting property name enclosed in double quotes', 1),
154            ('[{]', 'Expecting property name enclosed in double quotes', 2),
155            ('{"spam",', "Expecting ':' delimiter", 7),
156            ('{"spam"}', "Expecting ':' delimiter", 7),
157            ('[{"spam"]', "Expecting ':' delimiter", 8),
158            ('{"spam":}', 'Expecting value', 8),
159            ('[{"spam":]', 'Expecting value', 9),
160            ('{"spam":42 "ham"', "Expecting ',' delimiter", 11),
161            ('[{"spam":42]', "Expecting ',' delimiter", 11),
162            ('{"spam":42,}', 'Expecting property name enclosed in double quotes', 11),
163        ]
164        for data, msg, idx in test_cases:
165            with self.assertRaises(self.JSONDecodeError) as cm:
166                self.loads(data)
167            err = cm.exception
168            self.assertEqual(err.msg, msg)
169            self.assertEqual(err.pos, idx)
170            self.assertEqual(err.lineno, 1)
171            self.assertEqual(err.colno, idx + 1)
172            self.assertEqual(str(err),
173                             '%s: line 1 column %d (char %d)' %
174                             (msg, idx + 1, idx))
175
176    def test_extra_data(self):
177        test_cases = [
178            ('[]]', 'Extra data', 2),
179            ('{}}', 'Extra data', 2),
180            ('[],[]', 'Extra data', 2),
181            ('{},{}', 'Extra data', 2),
182        ]
183        test_cases += [
184            ('42,"spam"', 'Extra data', 2),
185            ('"spam",42', 'Extra data', 6),
186        ]
187        for data, msg, idx in test_cases:
188            with self.assertRaises(self.JSONDecodeError) as cm:
189                self.loads(data)
190            err = cm.exception
191            self.assertEqual(err.msg, msg)
192            self.assertEqual(err.pos, idx)
193            self.assertEqual(err.lineno, 1)
194            self.assertEqual(err.colno, idx + 1)
195            self.assertEqual(str(err),
196                             '%s: line 1 column %d (char %d)' %
197                             (msg, idx + 1, idx))
198
199    def test_linecol(self):
200        test_cases = [
201            ('!', 1, 1, 0),
202            (' !', 1, 2, 1),
203            ('\n!', 2, 1, 1),
204            ('\n  \n\n     !', 4, 6, 10),
205        ]
206        for data, line, col, idx in test_cases:
207            with self.assertRaises(self.JSONDecodeError) as cm:
208                self.loads(data)
209            err = cm.exception
210            self.assertEqual(err.msg, 'Expecting value')
211            self.assertEqual(err.pos, idx)
212            self.assertEqual(err.lineno, line)
213            self.assertEqual(err.colno, col)
214            self.assertEqual(str(err),
215                             'Expecting value: line %s column %d (char %d)' %
216                             (line, col, idx))
217
218class TestPyFail(TestFail, PyTest): pass
219class TestCFail(TestFail, CTest): pass
220