|
1 | 1 | import json |
2 | | -import time |
| 2 | +import textwrap |
3 | 3 | import unittest |
4 | 4 |
|
| 5 | +from django.core.exceptions import SuspiciousOperation |
5 | 6 | from django.core.serializers.base import DeserializationError, DeserializedObject |
6 | 7 | from django.core.serializers.json import Deserializer as JsonDeserializer |
7 | 8 | from django.core.serializers.jsonl import Deserializer as JsonlDeserializer |
8 | 9 | from django.core.serializers.python import Deserializer |
9 | 10 | from django.core.serializers.xml_serializer import Deserializer as XMLDeserializer |
10 | | -from django.db import models |
11 | 11 | from django.test import SimpleTestCase |
12 | | -from django.test.utils import garbage_collect |
13 | 12 |
|
14 | 13 | from .models import Author |
15 | 14 |
|
@@ -138,52 +137,23 @@ def test_yaml_bytes_input(self): |
138 | 137 | self.assertEqual(first_item.object, self.jane) |
139 | 138 | self.assertEqual(second_item.object, self.joe) |
140 | 139 |
|
141 | | - def test_crafted_xml_performance(self): |
142 | | - """The time to process invalid inputs is not quadratic.""" |
143 | | - |
144 | | - def build_crafted_xml(depth, leaf_text_len): |
145 | | - nested_open = "<nested>" * depth |
146 | | - nested_close = "</nested>" * depth |
147 | | - leaf = "x" * leaf_text_len |
148 | | - field_content = f"{nested_open}{leaf}{nested_close}" |
149 | | - return f""" |
150 | | - <django-objects version="1.0"> |
151 | | - <object model="contenttypes.contenttype" pk="1"> |
152 | | - <field name="app_label">{field_content}</field> |
153 | | - <field name="model">m</field> |
154 | | - </object> |
155 | | - </django-objects> |
156 | | - """ |
157 | | - |
158 | | - def deserialize(crafted_xml): |
159 | | - iterator = XMLDeserializer(crafted_xml) |
160 | | - garbage_collect() |
161 | | - |
162 | | - start_time = time.perf_counter() |
163 | | - result = list(iterator) |
164 | | - end_time = time.perf_counter() |
165 | | - |
166 | | - self.assertEqual(len(result), 1) |
167 | | - self.assertIsInstance(result[0].object, models.Model) |
168 | | - return end_time - start_time |
169 | | - |
170 | | - def assertFactor(label, params, factor=2): |
171 | | - factors = [] |
172 | | - prev_time = None |
173 | | - for depth, length in params: |
174 | | - crafted_xml = build_crafted_xml(depth, length) |
175 | | - elapsed = deserialize(crafted_xml) |
176 | | - if prev_time is not None: |
177 | | - factors.append(elapsed / prev_time) |
178 | | - prev_time = elapsed |
179 | | - |
180 | | - with self.subTest(label): |
181 | | - # Assert based on the average factor to reduce test flakiness. |
182 | | - self.assertLessEqual(sum(factors) / len(factors), factor) |
183 | | - |
184 | | - assertFactor( |
185 | | - "varying depth, varying length", |
186 | | - [(50, 2000), (100, 4000), (200, 8000), (400, 16000), (800, 32000)], |
187 | | - 2, |
| 140 | + def test_crafted_xml_rejected(self): |
| 141 | + depth = 100 |
| 142 | + leaf_text_len = 1000 |
| 143 | + nested_open = "<nested>" * depth |
| 144 | + nested_close = "</nested>" * depth |
| 145 | + leaf = "x" * leaf_text_len |
| 146 | + field_content = f"{nested_open}{leaf}{nested_close}" |
| 147 | + crafted_xml = textwrap.dedent( |
| 148 | + f""" |
| 149 | + <django-objects version="1.0"> |
| 150 | + <object model="contenttypes.contenttype" pk="1"> |
| 151 | + <field name="app_label">{field_content}</field> |
| 152 | + <field name="model">m</field> |
| 153 | + </object> |
| 154 | + </django-objects>""" |
188 | 155 | ) |
189 | | - assertFactor("constant depth, varying length", [(100, 1), (100, 1000)], 2) |
| 156 | + |
| 157 | + msg = "Unexpected element: 'nested'" |
| 158 | + with self.assertRaisesMessage(SuspiciousOperation, msg): |
| 159 | + list(XMLDeserializer(crafted_xml)) |
0 commit comments