summaryrefslogtreecommitdiff
path: root/Lib/json/tests/test_recursion.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/json/tests/test_recursion.py')
-rw-r--r--Lib/json/tests/test_recursion.py79
1 files changed, 60 insertions, 19 deletions
diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py
index 1e9b8ab757..b5221e5d16 100644
--- a/Lib/json/tests/test_recursion.py
+++ b/Lib/json/tests/test_recursion.py
@@ -1,28 +1,16 @@
-from unittest import TestCase
+from json.tests import PyTest, CTest
-import json
class JSONTestObject:
pass
-class RecursiveJSONEncoder(json.JSONEncoder):
- recurse = False
- def default(self, o):
- if o is JSONTestObject:
- if self.recurse:
- return [JSONTestObject]
- else:
- return 'JSONTestObject'
- return json.JSONEncoder.default(o)
-
-
-class TestRecursion(TestCase):
+class TestRecursion(object):
def test_listrecursion(self):
x = []
x.append(x)
try:
- json.dumps(x)
+ self.dumps(x)
except ValueError:
pass
else:
@@ -31,7 +19,7 @@ class TestRecursion(TestCase):
y = [x]
x.append(y)
try:
- json.dumps(x)
+ self.dumps(x)
except ValueError:
pass
else:
@@ -39,13 +27,13 @@ class TestRecursion(TestCase):
y = []
x = [y, y]
# ensure that the marker is cleared
- json.dumps(x)
+ self.dumps(x)
def test_dictrecursion(self):
x = {}
x["test"] = x
try:
- json.dumps(x)
+ self.dumps(x)
except ValueError:
pass
else:
@@ -53,9 +41,19 @@ class TestRecursion(TestCase):
x = {}
y = {"a": x, "b": x}
# ensure that the marker is cleared
- json.dumps(x)
+ 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 pyjson.JSONEncoder.default(o)
+
enc = RecursiveJSONEncoder()
self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"')
enc.recurse = True
@@ -65,3 +63,46 @@ class TestRecursion(TestCase):
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
+ # str
+ with self.assertRaises(RuntimeError):
+ self.loads('{"a":' * 100000 + '1' + '}' * 100000)
+ with self.assertRaises(RuntimeError):
+ self.loads('{"a":' * 100000 + '[1]' + '}' * 100000)
+ with self.assertRaises(RuntimeError):
+ self.loads('[' * 100000 + '1' + ']' * 100000)
+ # unicode
+ with self.assertRaises(RuntimeError):
+ self.loads(u'{"a":' * 100000 + u'1' + u'}' * 100000)
+ with self.assertRaises(RuntimeError):
+ self.loads(u'{"a":' * 100000 + u'[1]' + u'}' * 100000)
+ with self.assertRaises(RuntimeError):
+ self.loads(u'[' * 100000 + u'1' + u']' * 100000)
+
+ def test_highly_nested_objects_encoding(self):
+ # See #12051
+ l, d = [], {}
+ for x in xrange(100000):
+ l, d = [l], {'k':d}
+ with self.assertRaises(RuntimeError):
+ self.dumps(l)
+ with self.assertRaises(RuntimeError):
+ 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(RuntimeError):
+ EndlessJSONEncoder(check_circular=False).encode(5j)
+
+
+class TestPyRecursion(TestRecursion, PyTest): pass
+class TestCRecursion(TestRecursion, CTest): pass