101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
|
from test.test_json import PyTest, CTest
|
||
|
|
||
|
|
||
|
class JSONTestObject:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class TestRecursion:
|
||
|
def test_listrecursion(self):
|
||
|
x = []
|
||
|
x.append(x)
|
||
|
try:
|
||
|
self.dumps(x)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
else:
|
||
|
self.fail("didn't raise ValueError on list recursion")
|
||
|
x = []
|
||
|
y = [x]
|
||
|
x.append(y)
|
||
|
try:
|
||
|
self.dumps(x)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
else:
|
||
|
self.fail("didn't raise ValueError on alternating list recursion")
|
||
|
y = []
|
||
|
x = [y, y]
|
||
|
# ensure that the marker is cleared
|
||
|
self.dumps(x)
|
||
|
|
||
|
def test_dictrecursion(self):
|
||
|
x = {}
|
||
|
x["test"] = x
|
||
|
try:
|
||
|
self.dumps(x)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
else:
|
||
|
self.fail("didn't raise ValueError on dict recursion")
|
||
|
x = {}
|
||
|
y = {"a": x, "b": x}
|
||
|
# ensure that the marker is cleared
|
||
|
self.dumps(x)
|
||
|
|
||
|
def test_defaultrecursion(self):
|
||
|
class RecursiveJSONEncoder(self.json.JSONEncoder):
|
||
|
recurse = False
|
||
|
def default(self, o):
|
||
|
if o is JSONTestObject:
|
||
|
if self.recurse:
|
||
|
return [JSONTestObject]
|
||
|
else:
|
||
|
return 'JSONTestObject'
|
||
|
return self.json.JSONEncoder.default(o)
|
||
|
|
||
|
enc = RecursiveJSONEncoder()
|
||
|
self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"')
|
||
|
enc.recurse = True
|
||
|
try:
|
||
|
enc.encode(JSONTestObject)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
else:
|
||
|
self.fail("didn't raise ValueError on default recursion")
|
||
|
|
||
|
|
||
|
def test_highly_nested_objects_decoding(self):
|
||
|
# test that loading highly-nested objects doesn't segfault when C
|
||
|
# accelerations are used. See #12017
|
||
|
with self.assertRaises(RecursionError):
|
||
|
self.loads('{"a":' * 100000 + '1' + '}' * 100000)
|
||
|
with self.assertRaises(RecursionError):
|
||
|
self.loads('{"a":' * 100000 + '[1]' + '}' * 100000)
|
||
|
with self.assertRaises(RecursionError):
|
||
|
self.loads('[' * 100000 + '1' + ']' * 100000)
|
||
|
|
||
|
def test_highly_nested_objects_encoding(self):
|
||
|
# See #12051
|
||
|
l, d = [], {}
|
||
|
for x in range(100000):
|
||
|
l, d = [l], {'k':d}
|
||
|
with self.assertRaises(RecursionError):
|
||
|
self.dumps(l)
|
||
|
with self.assertRaises(RecursionError):
|
||
|
self.dumps(d)
|
||
|
|
||
|
def test_endless_recursion(self):
|
||
|
# See #12051
|
||
|
class EndlessJSONEncoder(self.json.JSONEncoder):
|
||
|
def default(self, o):
|
||
|
"""If check_circular is False, this will keep adding another list."""
|
||
|
return [o]
|
||
|
|
||
|
with self.assertRaises(RecursionError):
|
||
|
EndlessJSONEncoder(check_circular=False).encode(5j)
|
||
|
|
||
|
|
||
|
class TestPyRecursion(TestRecursion, PyTest): pass
|
||
|
class TestCRecursion(TestRecursion, CTest): pass
|