Skip to content

Commit 9d136d6

Browse files
committed
Add test.test_json from CPython 3.8.2
1 parent d5b0965 commit 9d136d6

19 files changed

+1470
-0
lines changed

Lib/test/test_json/__init__.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import os
2+
import json
3+
import doctest
4+
import unittest
5+
6+
from test import support
7+
8+
# import json with and without accelerations
9+
cjson = support.import_fresh_module('json', fresh=['_json'])
10+
pyjson = support.import_fresh_module('json', blocked=['_json'])
11+
# JSONDecodeError is cached inside the _json module
12+
cjson.JSONDecodeError = cjson.decoder.JSONDecodeError = json.JSONDecodeError
13+
14+
# create two base classes that will be used by the other tests
15+
class PyTest(unittest.TestCase):
16+
json = pyjson
17+
loads = staticmethod(pyjson.loads)
18+
dumps = staticmethod(pyjson.dumps)
19+
JSONDecodeError = staticmethod(pyjson.JSONDecodeError)
20+
21+
@unittest.skipUnless(cjson, 'requires _json')
22+
class CTest(unittest.TestCase):
23+
if cjson is not None:
24+
json = cjson
25+
loads = staticmethod(cjson.loads)
26+
dumps = staticmethod(cjson.dumps)
27+
JSONDecodeError = staticmethod(cjson.JSONDecodeError)
28+
29+
# test PyTest and CTest checking if the functions come from the right module
30+
class TestPyTest(PyTest):
31+
def test_pyjson(self):
32+
self.assertEqual(self.json.scanner.make_scanner.__module__,
33+
'json.scanner')
34+
self.assertEqual(self.json.decoder.scanstring.__module__,
35+
'json.decoder')
36+
self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__,
37+
'json.encoder')
38+
39+
class TestCTest(CTest):
40+
def test_cjson(self):
41+
self.assertEqual(self.json.scanner.make_scanner.__module__, '_json')
42+
self.assertEqual(self.json.decoder.scanstring.__module__, '_json')
43+
self.assertEqual(self.json.encoder.c_make_encoder.__module__, '_json')
44+
self.assertEqual(self.json.encoder.encode_basestring_ascii.__module__,
45+
'_json')
46+
47+
48+
def load_tests(loader, _, pattern):
49+
suite = unittest.TestSuite()
50+
for mod in (json, json.encoder, json.decoder):
51+
suite.addTest(doctest.DocTestSuite(mod))
52+
suite.addTest(TestPyTest('test_pyjson'))
53+
suite.addTest(TestCTest('test_cjson'))
54+
55+
pkg_dir = os.path.dirname(__file__)
56+
return support.load_package_tests(pkg_dir, loader, suite, pattern)

Lib/test/test_json/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import unittest
2+
from test.test_json import load_tests
3+
4+
unittest.main()

Lib/test/test_json/test_decode.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import decimal
2+
from io import StringIO
3+
from collections import OrderedDict
4+
from test.test_json import PyTest, CTest
5+
6+
7+
class TestDecode:
8+
def test_decimal(self):
9+
rval = self.loads('1.1', parse_float=decimal.Decimal)
10+
self.assertTrue(isinstance(rval, decimal.Decimal))
11+
self.assertEqual(rval, decimal.Decimal('1.1'))
12+
13+
def test_float(self):
14+
rval = self.loads('1', parse_int=float)
15+
self.assertTrue(isinstance(rval, float))
16+
self.assertEqual(rval, 1.0)
17+
18+
def test_empty_objects(self):
19+
self.assertEqual(self.loads('{}'), {})
20+
self.assertEqual(self.loads('[]'), [])
21+
self.assertEqual(self.loads('""'), "")
22+
23+
def test_object_pairs_hook(self):
24+
s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}'
25+
p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4),
26+
("qrt", 5), ("pad", 6), ("hoy", 7)]
27+
self.assertEqual(self.loads(s), eval(s))
28+
self.assertEqual(self.loads(s, object_pairs_hook=lambda x: x), p)
29+
self.assertEqual(self.json.load(StringIO(s),
30+
object_pairs_hook=lambda x: x), p)
31+
od = self.loads(s, object_pairs_hook=OrderedDict)
32+
self.assertEqual(od, OrderedDict(p))
33+
self.assertEqual(type(od), OrderedDict)
34+
# the object_pairs_hook takes priority over the object_hook
35+
self.assertEqual(self.loads(s, object_pairs_hook=OrderedDict,
36+
object_hook=lambda x: None),
37+
OrderedDict(p))
38+
# check that empty object literals work (see #17368)
39+
self.assertEqual(self.loads('{}', object_pairs_hook=OrderedDict),
40+
OrderedDict())
41+
self.assertEqual(self.loads('{"empty": {}}',
42+
object_pairs_hook=OrderedDict),
43+
OrderedDict([('empty', OrderedDict())]))
44+
45+
def test_decoder_optimizations(self):
46+
# Several optimizations were made that skip over calls to
47+
# the whitespace regex, so this test is designed to try and
48+
# exercise the uncommon cases. The array cases are already covered.
49+
rval = self.loads('{ "key" : "value" , "k":"v" }')
50+
self.assertEqual(rval, {"key":"value", "k":"v"})
51+
52+
def check_keys_reuse(self, source, loads):
53+
rval = loads(source)
54+
(a, b), (c, d) = sorted(rval[0]), sorted(rval[1])
55+
self.assertIs(a, c)
56+
self.assertIs(b, d)
57+
58+
def test_keys_reuse(self):
59+
s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]'
60+
self.check_keys_reuse(s, self.loads)
61+
decoder = self.json.decoder.JSONDecoder()
62+
self.check_keys_reuse(s, decoder.decode)
63+
self.assertFalse(decoder.memo)
64+
65+
def test_extra_data(self):
66+
s = '[1, 2, 3]5'
67+
msg = 'Extra data'
68+
self.assertRaisesRegex(self.JSONDecodeError, msg, self.loads, s)
69+
70+
def test_invalid_escape(self):
71+
s = '["abc\\y"]'
72+
msg = 'escape'
73+
self.assertRaisesRegex(self.JSONDecodeError, msg, self.loads, s)
74+
75+
def test_invalid_input_type(self):
76+
msg = 'the JSON object must be str'
77+
for value in [1, 3.14, [], {}, None]:
78+
self.assertRaisesRegex(TypeError, msg, self.loads, value)
79+
80+
def test_string_with_utf8_bom(self):
81+
# see #18958
82+
bom_json = "[1,2,3]".encode('utf-8-sig').decode('utf-8')
83+
with self.assertRaises(self.JSONDecodeError) as cm:
84+
self.loads(bom_json)
85+
self.assertIn('BOM', str(cm.exception))
86+
with self.assertRaises(self.JSONDecodeError) as cm:
87+
self.json.load(StringIO(bom_json))
88+
self.assertIn('BOM', str(cm.exception))
89+
# make sure that the BOM is not detected in the middle of a string
90+
bom_in_str = '"{}"'.format(''.encode('utf-8-sig').decode('utf-8'))
91+
self.assertEqual(self.loads(bom_in_str), '\ufeff')
92+
self.assertEqual(self.json.load(StringIO(bom_in_str)), '\ufeff')
93+
94+
def test_negative_index(self):
95+
d = self.json.JSONDecoder()
96+
self.assertRaises(ValueError, d.raw_decode, 'a'*42, -50000)
97+
98+
def test_deprecated_encode(self):
99+
with self.assertWarns(DeprecationWarning):
100+
self.loads('{}', encoding='fake')
101+
102+
class TestPyDecode(TestDecode, PyTest): pass
103+
class TestCDecode(TestDecode, CTest): pass

Lib/test/test_json/test_default.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from test.test_json import PyTest, CTest
2+
3+
4+
class TestDefault:
5+
def test_default(self):
6+
self.assertEqual(
7+
self.dumps(type, default=repr),
8+
self.dumps(repr(type)))
9+
10+
11+
class TestPyDefault(TestDefault, PyTest): pass
12+
class TestCDefault(TestDefault, CTest): pass

Lib/test/test_json/test_dump.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from io import StringIO
2+
from test.test_json import PyTest, CTest
3+
4+
from test.support import bigmemtest, _1G
5+
6+
class TestDump:
7+
def test_dump(self):
8+
sio = StringIO()
9+
self.json.dump({}, sio)
10+
self.assertEqual(sio.getvalue(), '{}')
11+
12+
def test_dumps(self):
13+
self.assertEqual(self.dumps({}), '{}')
14+
15+
def test_dump_skipkeys(self):
16+
v = {b'invalid_key': False, 'valid_key': True}
17+
with self.assertRaises(TypeError):
18+
self.json.dumps(v)
19+
20+
s = self.json.dumps(v, skipkeys=True)
21+
o = self.json.loads(s)
22+
self.assertIn('valid_key', o)
23+
self.assertNotIn(b'invalid_key', o)
24+
25+
def test_encode_truefalse(self):
26+
self.assertEqual(self.dumps(
27+
{True: False, False: True}, sort_keys=True),
28+
'{"false": true, "true": false}')
29+
self.assertEqual(self.dumps(
30+
{2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True),
31+
'{"false": 1, "2": 3.0, "4.0": 5, "6": true}')
32+
33+
# Issue 16228: Crash on encoding resized list
34+
def test_encode_mutated(self):
35+
a = [object()] * 10
36+
def crasher(obj):
37+
del a[-1]
38+
self.assertEqual(self.dumps(a, default=crasher),
39+
'[null, null, null, null, null]')
40+
41+
# Issue 24094
42+
def test_encode_evil_dict(self):
43+
class D(dict):
44+
def keys(self):
45+
return L
46+
47+
class X:
48+
def __hash__(self):
49+
del L[0]
50+
return 1337
51+
52+
def __lt__(self, o):
53+
return 0
54+
55+
L = [X() for i in range(1122)]
56+
d = D()
57+
d[1337] = "true.dat"
58+
self.assertEqual(self.dumps(d, sort_keys=True), '{"1337": "true.dat"}')
59+
60+
61+
class TestPyDump(TestDump, PyTest): pass
62+
63+
class TestCDump(TestDump, CTest):
64+
65+
# The size requirement here is hopefully over-estimated (actual
66+
# memory consumption depending on implementation details, and also
67+
# system memory management, since this may allocate a lot of
68+
# small objects).
69+
70+
@bigmemtest(size=_1G, memuse=1)
71+
def test_large_list(self, size):
72+
N = int(30 * 1024 * 1024 * (size / _1G))
73+
l = [1] * N
74+
encoded = self.dumps(l)
75+
self.assertEqual(len(encoded), N * 3)
76+
self.assertEqual(encoded[:1], "[")
77+
self.assertEqual(encoded[-2:], "1]")
78+
self.assertEqual(encoded[1:-2], "1, " * (N - 1))
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from collections import OrderedDict
2+
from test.test_json import PyTest, CTest
3+
from test.support import bigaddrspacetest
4+
5+
6+
CASES = [
7+
('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'),
8+
('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'),
9+
('controls', '"controls"'),
10+
('\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'),
11+
('{"object with 1 member":["array with 1 element"]}', '"{\\"object with 1 member\\":[\\"array with 1 element\\"]}"'),
12+
(' s p a c e d ', '" s p a c e d "'),
13+
('\U0001d120', '"\\ud834\\udd20"'),
14+
('\u03b1\u03a9', '"\\u03b1\\u03a9"'),
15+
("`1~!@#$%^&*()_+-={':[,]}|;.</>?", '"`1~!@#$%^&*()_+-={\':[,]}|;.</>?"'),
16+
('\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'),
17+
('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'),
18+
]
19+
20+
class TestEncodeBasestringAscii:
21+
def test_encode_basestring_ascii(self):
22+
fname = self.json.encoder.encode_basestring_ascii.__name__
23+
for input_string, expect in CASES:
24+
result = self.json.encoder.encode_basestring_ascii(input_string)
25+
self.assertEqual(result, expect,
26+
'{0!r} != {1!r} for {2}({3!r})'.format(
27+
result, expect, fname, input_string))
28+
29+
def test_ordered_dict(self):
30+
# See issue 6105
31+
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
32+
s = self.dumps(OrderedDict(items))
33+
self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')
34+
35+
def test_sorted_dict(self):
36+
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
37+
s = self.dumps(dict(items), sort_keys=True)
38+
self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}')
39+
40+
41+
class TestPyEncodeBasestringAscii(TestEncodeBasestringAscii, PyTest): pass
42+
class TestCEncodeBasestringAscii(TestEncodeBasestringAscii, CTest):
43+
@bigaddrspacetest
44+
def test_overflow(self):
45+
size = (2**32)//6 + 1
46+
s = "\x00"*size
47+
with self.assertRaises(OverflowError):
48+
self.json.encoder.encode_basestring_ascii(s)

0 commit comments

Comments
 (0)