From 4eeec2031e2785f22a7004d890168f1d0e3bbc71 Mon Sep 17 00:00:00 2001
From: Claude Paroz <claude@2xlibre.net>
Date: Sat, 26 Sep 2015 10:51:59 +0200
Subject: [PATCH] [1.9.x] Separated XML serialization tests

Backport of d3cfdfb508 from master.
---
 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 = """<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object model="serializers.category">
+        <field type="CharField" name="name">Reference</field>
+    </object>
+    <object model="serializers.category">
+        <field type="CharField" name="name">Non-fiction</field>
+    </object>
+</django-objects>"""
+    mapping_ordering_str = """<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+  <object model="serializers.article" pk="%(article_pk)s">
+    <field name="author" rel="ManyToOneRel" to="serializers.author">%(author_pk)s</field>
+    <field name="headline" type="CharField">Poker has no place on ESPN</field>
+    <field name="pub_date" type="DateTimeField">2006-06-16T11:00:00</field>
+    <field name="categories" rel="ManyToManyRel" to="serializers.category"><object pk="%(first_category_pk)s"></object><object pk="%(second_category_pk)s"></object></field>
+    <field name="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field>
+  </object>
+</django-objects>"""  # 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 = '<?xml version="1.0" standalone="no"?><!DOCTYPE example SYSTEM "http://example.com/example.dtd">'
+        with self.assertRaises(DTDForbidden):
+            next(serializers.deserialize('xml', xml))
+
+
+class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
+    serializer_name = "xml"
+    fwd_ref_str = """<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object pk="1" model="serializers.article">
+        <field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
+        <field type="CharField" name="headline">Forward references pose no problem</field>
+        <field type="DateTimeField" name="pub_date">2006-06-16T15:00:00</field>
+        <field to="serializers.category" name="categories" rel="ManyToManyRel">
+            <object pk="1"></object>
+        </field>
+        <field to="serializers.categorymetadata" name="meta_data" rel="ManyToManyRel"></field>
+    </object>
+    <object pk="1" model="serializers.author">
+        <field type="CharField" name="name">Agnes</field>
+    </object>
+    <object pk="1" model="serializers.category">
+        <field type="CharField" name="name">Reference</field></object>
+</django-objects>"""
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 = """<?xml version="1.0" encoding="utf-8"?>
-<django-objects version="1.0">
-    <object model="serializers.category">
-        <field type="CharField" name="name">Reference</field>
-    </object>
-    <object model="serializers.category">
-        <field type="CharField" name="name">Non-fiction</field>
-    </object>
-</django-objects>"""
-    mapping_ordering_str = """<?xml version="1.0" encoding="utf-8"?>
-<django-objects version="1.0">
-  <object model="serializers.article" pk="%(article_pk)s">
-    <field name="author" rel="ManyToOneRel" to="serializers.author">%(author_pk)s</field>
-    <field name="headline" type="CharField">Poker has no place on ESPN</field>
-    <field name="pub_date" type="DateTimeField">2006-06-16T11:00:00</field>
-    <field name="categories" rel="ManyToManyRel" to="serializers.category"><object pk="%(first_category_pk)s"></object><object pk="%(second_category_pk)s"></object></field>
-    <field name="meta_data" rel="ManyToManyRel" to="serializers.categorymetadata"></field>
-  </object>
-</django-objects>"""  # 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 = """<?xml version="1.0" encoding="utf-8"?>
-<django-objects version="1.0">
-    <object pk="1" model="serializers.article">
-        <field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
-        <field type="CharField" name="headline">Forward references pose no problem</field>
-        <field type="DateTimeField" name="pub_date">2006-06-16T15:00:00</field>
-        <field to="serializers.category" name="categories" rel="ManyToManyRel">
-            <object pk="1"></object>
-        </field>
-        <field to="serializers.categorymetadata" name="meta_data" rel="ManyToManyRel"></field>
-    </object>
-    <object pk="1" model="serializers.author">
-        <field type="CharField" name="name">Agnes</field>
-    </object>
-    <object pk="1" model="serializers.category">
-        <field type="CharField" name="name">Reference</field></object>
-</django-objects>"""
-
-
 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 = '<?xml version="1.0" standalone="no"?><!DOCTYPE example SYSTEM "http://example.com/example.dtd">'
-        with self.assertRaises(DTDForbidden):
-            next(serializers.deserialize('xml', xml))