From d3cfdfb508c191278761711f0ce91b789d65b37c Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 26 Sep 2015 10:51:59 +0200 Subject: [PATCH] Separated XML serialization tests --- tests/serializers/test_xml.py | 118 +++++++++++++++++++++++++++++ tests/serializers/tests.py | 98 ------------------------ tests/serializers_regress/tests.py | 17 +---- 3 files changed, 119 insertions(+), 114 deletions(-) create mode 100644 tests/serializers/test_xml.py diff --git a/tests/serializers/test_xml.py b/tests/serializers/test_xml.py new file mode 100644 index 0000000000..e516444c95 --- /dev/null +++ b/tests/serializers/test_xml.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from xml.dom import minidom + +from django.core import serializers +from django.core.serializers.xml_serializer import DTDForbidden +from django.test import TestCase, TransactionTestCase +from django.utils import six + +from .tests import SerializersTestBase, SerializersTransactionTestBase + + +class XmlSerializerTestCase(SerializersTestBase, TestCase): + serializer_name = "xml" + pkless_str = """ + + + Reference + + + Non-fiction + +""" + mapping_ordering_str = """ + + + %(author_pk)s + Poker has no place on ESPN + 2006-06-16T11:00:00 + + + +""" # NOQA + + @staticmethod + def _comparison_value(value): + # The XML serializer handles everything as strings, so comparisons + # need to be performed on the stringified value + return six.text_type(value) + + @staticmethod + def _validate_output(serial_str): + try: + minidom.parseString(serial_str) + except Exception: + return False + else: + return True + + @staticmethod + def _get_pk_values(serial_str): + ret_list = [] + dom = minidom.parseString(serial_str) + fields = dom.getElementsByTagName("object") + for field in fields: + ret_list.append(field.getAttribute("pk")) + return ret_list + + @staticmethod + def _get_field_values(serial_str, field_name): + ret_list = [] + dom = minidom.parseString(serial_str) + fields = dom.getElementsByTagName("field") + for field in fields: + if field.getAttribute("name") == field_name: + temp = [] + for child in field.childNodes: + temp.append(child.nodeValue) + ret_list.append("".join(temp)) + return ret_list + + def test_control_char_failure(self): + """ + Serializing control characters with XML should fail as those characters + are not supported in the XML 1.0 standard (except HT, LF, CR). + """ + self.a1.headline = "This contains \u0001 control \u0011 chars" + msg = "Article.headline (pk:%s) contains unserializable characters" % self.a1.pk + with self.assertRaisesMessage(ValueError, msg): + serializers.serialize(self.serializer_name, [self.a1]) + self.a1.headline = "HT \u0009, LF \u000A, and CR \u000D are allowed" + self.assertIn( + "HT \t, LF \n, and CR \r are allowed", + serializers.serialize(self.serializer_name, [self.a1]) + ) + + def test_no_dtd(self): + """ + The XML deserializer shouldn't allow a DTD. + + This is the most straightforward way to prevent all entity definitions + and avoid both external entities and entity-expansion attacks. + """ + xml = '' + with self.assertRaises(DTDForbidden): + next(serializers.deserialize('xml', xml)) + + +class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase): + serializer_name = "xml" + fwd_ref_str = """ + + + 1 + Forward references pose no problem + 2006-06-16T15:00:00 + + + + + + + Agnes + + + Reference +""" diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py index f92f0775d6..c288bf7ab8 100644 --- a/tests/serializers/tests.py +++ b/tests/serializers/tests.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import json import re from datetime import datetime -from xml.dom import minidom from django.core import serializers from django.core.serializers.base import ProgressBar @@ -14,7 +13,6 @@ from django.test import ( skipUnlessDBFeature, ) from django.test.utils import Approximate -from django.utils import six from django.utils.six import StringIO from .models import ( @@ -324,102 +322,6 @@ class SerializersTransactionTestBase(object): self.assertEqual(art_obj.author.name, "Agnes") -class XmlSerializerTestCase(SerializersTestBase, TestCase): - serializer_name = "xml" - pkless_str = """ - - - Reference - - - Non-fiction - -""" - mapping_ordering_str = """ - - - %(author_pk)s - Poker has no place on ESPN - 2006-06-16T11:00:00 - - - -""" # NOQA - - @staticmethod - def _comparison_value(value): - # The XML serializer handles everything as strings, so comparisons - # need to be performed on the stringified value - return six.text_type(value) - - @staticmethod - def _validate_output(serial_str): - try: - minidom.parseString(serial_str) - except Exception: - return False - else: - return True - - @staticmethod - def _get_pk_values(serial_str): - ret_list = [] - dom = minidom.parseString(serial_str) - fields = dom.getElementsByTagName("object") - for field in fields: - ret_list.append(field.getAttribute("pk")) - return ret_list - - @staticmethod - def _get_field_values(serial_str, field_name): - ret_list = [] - dom = minidom.parseString(serial_str) - fields = dom.getElementsByTagName("field") - for field in fields: - if field.getAttribute("name") == field_name: - temp = [] - for child in field.childNodes: - temp.append(child.nodeValue) - ret_list.append("".join(temp)) - return ret_list - - def test_control_char_failure(self): - """ - Serializing control characters with XML should fail as those characters - are not supported in the XML 1.0 standard (except HT, LF, CR). - """ - self.a1.headline = "This contains \u0001 control \u0011 chars" - msg = "Article.headline (pk:%s) contains unserializable characters" % self.a1.pk - with self.assertRaisesMessage(ValueError, msg): - serializers.serialize(self.serializer_name, [self.a1]) - self.a1.headline = "HT \u0009, LF \u000A, and CR \u000D are allowed" - self.assertIn( - "HT \t, LF \n, and CR \r are allowed", - serializers.serialize(self.serializer_name, [self.a1]) - ) - - -class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase): - serializer_name = "xml" - fwd_ref_str = """ - - - 1 - Forward references pose no problem - 2006-06-16T15:00:00 - - - - - - - Agnes - - - Reference -""" - - class JsonSerializerTestCase(SerializersTestBase, TestCase): serializer_name = "json" pkless_str = """[ diff --git a/tests/serializers_regress/tests.py b/tests/serializers_regress/tests.py index 3da6ddafb4..fd05eedc43 100644 --- a/tests/serializers_regress/tests.py +++ b/tests/serializers_regress/tests.py @@ -15,10 +15,9 @@ import uuid from django.core import serializers from django.core.serializers import SerializerDoesNotExist from django.core.serializers.base import DeserializationError -from django.core.serializers.xml_serializer import DTDForbidden from django.db import connection, models from django.http import HttpResponse -from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature +from django.test import TestCase, skipUnlessDBFeature from django.utils import six from django.utils.functional import curry @@ -570,17 +569,3 @@ for format in [f for f in serializers.get_serializer_formats() setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format)) if format != 'python': setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format)) - - -class XmlDeserializerSecurityTests(SimpleTestCase): - - def test_no_dtd(self): - """ - The XML deserializer shouldn't allow a DTD. - - This is the most straightforward way to prevent all entity definitions - and avoid both external entities and entity-expansion attacks. - """ - xml = '' - with self.assertRaises(DTDForbidden): - next(serializers.deserialize('xml', xml))