tests.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. """
  2. A test spanning all the capabilities of all the serializers.
  3. This class defines sample data and a dynamically generated
  4. test case that is capable of testing the capabilities of
  5. the serializers. This includes all valid data values, plus
  6. forward, backwards and self references.
  7. """
  8. from __future__ import unicode_literals
  9. import datetime
  10. import decimal
  11. import uuid
  12. from unittest import skipUnless
  13. from django.core import serializers
  14. from django.core.serializers import SerializerDoesNotExist
  15. from django.core.serializers.base import DeserializationError
  16. from django.core.serializers.xml_serializer import DTDForbidden
  17. from django.db import connection, models
  18. from django.http import HttpResponse
  19. from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
  20. from django.utils import six
  21. from django.utils.functional import curry
  22. from .models import (
  23. Anchor, AutoNowDateTimeData, BaseModel, BigIntegerData, BinaryData,
  24. BooleanData, BooleanPKData, CharData, CharPKData, ComplexModel, DateData,
  25. DateTimeData, DecimalData, DecimalPKData, EmailData, EmailPKData,
  26. ExplicitInheritBaseModel, FileData, FilePathData, FilePathPKData, FKData,
  27. FKDataNaturalKey, FKDataToField, FKDataToO2O, FKSelfData, FKToUUID,
  28. FloatData, FloatPKData, GenericData, GenericIPAddressData,
  29. GenericIPAddressPKData, InheritAbstractModel, InheritBaseModel,
  30. IntegerData, IntegerPKData, Intermediate, LengthModel, M2MData,
  31. M2MIntermediateData, M2MSelfData, ModifyingSaveData, NaturalKeyAnchor,
  32. NullBooleanData, O2OData, PositiveIntegerData, PositiveIntegerPKData,
  33. PositiveSmallIntegerData, PositiveSmallIntegerPKData, ProxyBaseModel,
  34. ProxyProxyBaseModel, SlugData, SlugPKData, SmallData, SmallPKData, Tag,
  35. TextData, TimeData, UniqueAnchor, UUIDData,
  36. )
  37. try:
  38. import yaml
  39. except ImportError:
  40. yaml = None
  41. # A set of functions that can be used to recreate
  42. # test data objects of various kinds.
  43. # The save method is a raw base model save, to make
  44. # sure that the data in the database matches the
  45. # exact test case.
  46. def data_create(pk, klass, data):
  47. instance = klass(id=pk)
  48. instance.data = data
  49. models.Model.save_base(instance, raw=True)
  50. return [instance]
  51. def generic_create(pk, klass, data):
  52. instance = klass(id=pk)
  53. instance.data = data[0]
  54. models.Model.save_base(instance, raw=True)
  55. for tag in data[1:]:
  56. instance.tags.create(data=tag)
  57. return [instance]
  58. def fk_create(pk, klass, data):
  59. instance = klass(id=pk)
  60. setattr(instance, 'data_id', data)
  61. models.Model.save_base(instance, raw=True)
  62. return [instance]
  63. def m2m_create(pk, klass, data):
  64. instance = klass(id=pk)
  65. models.Model.save_base(instance, raw=True)
  66. instance.data = data
  67. return [instance]
  68. def im2m_create(pk, klass, data):
  69. instance = klass(id=pk)
  70. models.Model.save_base(instance, raw=True)
  71. return [instance]
  72. def im_create(pk, klass, data):
  73. instance = klass(id=pk)
  74. instance.right_id = data['right']
  75. instance.left_id = data['left']
  76. if 'extra' in data:
  77. instance.extra = data['extra']
  78. models.Model.save_base(instance, raw=True)
  79. return [instance]
  80. def o2o_create(pk, klass, data):
  81. instance = klass()
  82. instance.data_id = data
  83. models.Model.save_base(instance, raw=True)
  84. return [instance]
  85. def pk_create(pk, klass, data):
  86. instance = klass()
  87. instance.data = data
  88. models.Model.save_base(instance, raw=True)
  89. return [instance]
  90. def inherited_create(pk, klass, data):
  91. instance = klass(id=pk, **data)
  92. # This isn't a raw save because:
  93. # 1) we're testing inheritance, not field behavior, so none
  94. # of the field values need to be protected.
  95. # 2) saving the child class and having the parent created
  96. # automatically is easier than manually creating both.
  97. models.Model.save(instance)
  98. created = [instance]
  99. for klass, field in instance._meta.parents.items():
  100. created.append(klass.objects.get(id=pk))
  101. return created
  102. # A set of functions that can be used to compare
  103. # test data objects of various kinds
  104. def data_compare(testcase, pk, klass, data):
  105. instance = klass.objects.get(id=pk)
  106. if klass == BinaryData and data is not None:
  107. testcase.assertEqual(bytes(data), bytes(instance.data),
  108. "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (
  109. pk, repr(bytes(data)), type(data), repr(bytes(instance.data)),
  110. type(instance.data))
  111. )
  112. else:
  113. testcase.assertEqual(data, instance.data,
  114. "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (
  115. pk, data, type(data), instance, type(instance.data))
  116. )
  117. def generic_compare(testcase, pk, klass, data):
  118. instance = klass.objects.get(id=pk)
  119. testcase.assertEqual(data[0], instance.data)
  120. testcase.assertEqual(data[1:], [t.data for t in instance.tags.order_by('id')])
  121. def fk_compare(testcase, pk, klass, data):
  122. instance = klass.objects.get(id=pk)
  123. testcase.assertEqual(data, instance.data_id)
  124. def m2m_compare(testcase, pk, klass, data):
  125. instance = klass.objects.get(id=pk)
  126. testcase.assertEqual(data, [obj.id for obj in instance.data.order_by('id')])
  127. def im2m_compare(testcase, pk, klass, data):
  128. klass.objects.get(id=pk)
  129. # actually nothing else to check, the instance just should exist
  130. def im_compare(testcase, pk, klass, data):
  131. instance = klass.objects.get(id=pk)
  132. testcase.assertEqual(data['left'], instance.left_id)
  133. testcase.assertEqual(data['right'], instance.right_id)
  134. if 'extra' in data:
  135. testcase.assertEqual(data['extra'], instance.extra)
  136. else:
  137. testcase.assertEqual("doesn't matter", instance.extra)
  138. def o2o_compare(testcase, pk, klass, data):
  139. instance = klass.objects.get(data=data)
  140. testcase.assertEqual(data, instance.data_id)
  141. def pk_compare(testcase, pk, klass, data):
  142. instance = klass.objects.get(data=data)
  143. testcase.assertEqual(data, instance.data)
  144. def inherited_compare(testcase, pk, klass, data):
  145. instance = klass.objects.get(id=pk)
  146. for key, value in data.items():
  147. testcase.assertEqual(value, getattr(instance, key))
  148. # Define some data types. Each data type is
  149. # actually a pair of functions; one to create
  150. # and one to compare objects of that type
  151. data_obj = (data_create, data_compare)
  152. generic_obj = (generic_create, generic_compare)
  153. fk_obj = (fk_create, fk_compare)
  154. m2m_obj = (m2m_create, m2m_compare)
  155. im2m_obj = (im2m_create, im2m_compare)
  156. im_obj = (im_create, im_compare)
  157. o2o_obj = (o2o_create, o2o_compare)
  158. pk_obj = (pk_create, pk_compare)
  159. inherited_obj = (inherited_create, inherited_compare)
  160. uuid_obj = uuid.uuid4()
  161. test_data = [
  162. # Format: (data type, PK value, Model Class, data)
  163. (data_obj, 1, BinaryData, six.memoryview(b"\x05\xFD\x00")),
  164. (data_obj, 2, BinaryData, None),
  165. (data_obj, 5, BooleanData, True),
  166. (data_obj, 6, BooleanData, False),
  167. (data_obj, 10, CharData, "Test Char Data"),
  168. (data_obj, 11, CharData, ""),
  169. (data_obj, 12, CharData, "None"),
  170. (data_obj, 13, CharData, "null"),
  171. (data_obj, 14, CharData, "NULL"),
  172. (data_obj, 15, CharData, None),
  173. # (We use something that will fit into a latin1 database encoding here,
  174. # because that is still the default used on many system setups.)
  175. (data_obj, 16, CharData, '\xa5'),
  176. (data_obj, 20, DateData, datetime.date(2006, 6, 16)),
  177. (data_obj, 21, DateData, None),
  178. (data_obj, 30, DateTimeData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  179. (data_obj, 31, DateTimeData, None),
  180. (data_obj, 40, EmailData, "hovercraft@example.com"),
  181. (data_obj, 41, EmailData, None),
  182. (data_obj, 42, EmailData, ""),
  183. (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
  184. # (data_obj, 51, FileData, None),
  185. (data_obj, 52, FileData, ""),
  186. (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
  187. (data_obj, 61, FilePathData, None),
  188. (data_obj, 62, FilePathData, ""),
  189. (data_obj, 70, DecimalData, decimal.Decimal('12.345')),
  190. (data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
  191. (data_obj, 72, DecimalData, decimal.Decimal('0.0')),
  192. (data_obj, 73, DecimalData, None),
  193. (data_obj, 74, FloatData, 12.345),
  194. (data_obj, 75, FloatData, -12.345),
  195. (data_obj, 76, FloatData, 0.0),
  196. (data_obj, 77, FloatData, None),
  197. (data_obj, 80, IntegerData, 123456789),
  198. (data_obj, 81, IntegerData, -123456789),
  199. (data_obj, 82, IntegerData, 0),
  200. (data_obj, 83, IntegerData, None),
  201. # (XX, ImageData
  202. (data_obj, 95, GenericIPAddressData, "fe80:1424:2223:6cff:fe8a:2e8a:2151:abcd"),
  203. (data_obj, 96, GenericIPAddressData, None),
  204. (data_obj, 100, NullBooleanData, True),
  205. (data_obj, 101, NullBooleanData, False),
  206. (data_obj, 102, NullBooleanData, None),
  207. (data_obj, 120, PositiveIntegerData, 123456789),
  208. (data_obj, 121, PositiveIntegerData, None),
  209. (data_obj, 130, PositiveSmallIntegerData, 12),
  210. (data_obj, 131, PositiveSmallIntegerData, None),
  211. (data_obj, 140, SlugData, "this-is-a-slug"),
  212. (data_obj, 141, SlugData, None),
  213. (data_obj, 142, SlugData, ""),
  214. (data_obj, 150, SmallData, 12),
  215. (data_obj, 151, SmallData, -12),
  216. (data_obj, 152, SmallData, 0),
  217. (data_obj, 153, SmallData, None),
  218. (data_obj, 160, TextData, """This is a long piece of text.
  219. It contains line breaks.
  220. Several of them.
  221. The end."""),
  222. (data_obj, 161, TextData, ""),
  223. (data_obj, 162, TextData, None),
  224. (data_obj, 170, TimeData, datetime.time(10, 42, 37)),
  225. (data_obj, 171, TimeData, None),
  226. (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
  227. (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
  228. (data_obj, 300, Anchor, "Anchor 1"),
  229. (data_obj, 301, Anchor, "Anchor 2"),
  230. (data_obj, 302, UniqueAnchor, "UAnchor 1"),
  231. (fk_obj, 400, FKData, 300), # Post reference
  232. (fk_obj, 401, FKData, 500), # Pre reference
  233. (fk_obj, 402, FKData, None), # Empty reference
  234. (m2m_obj, 410, M2MData, []), # Empty set
  235. (m2m_obj, 411, M2MData, [300, 301]), # Post reference
  236. (m2m_obj, 412, M2MData, [500, 501]), # Pre reference
  237. (m2m_obj, 413, M2MData, [300, 301, 500, 501]), # Pre and Post reference
  238. (o2o_obj, None, O2OData, 300), # Post reference
  239. (o2o_obj, None, O2OData, 500), # Pre reference
  240. (fk_obj, 430, FKSelfData, 431), # Pre reference
  241. (fk_obj, 431, FKSelfData, 430), # Post reference
  242. (fk_obj, 432, FKSelfData, None), # Empty reference
  243. (m2m_obj, 440, M2MSelfData, []),
  244. (m2m_obj, 441, M2MSelfData, []),
  245. (m2m_obj, 442, M2MSelfData, [440, 441]),
  246. (m2m_obj, 443, M2MSelfData, [445, 446]),
  247. (m2m_obj, 444, M2MSelfData, [440, 441, 445, 446]),
  248. (m2m_obj, 445, M2MSelfData, []),
  249. (m2m_obj, 446, M2MSelfData, []),
  250. (fk_obj, 450, FKDataToField, "UAnchor 1"),
  251. (fk_obj, 451, FKDataToField, "UAnchor 2"),
  252. (fk_obj, 452, FKDataToField, None),
  253. (fk_obj, 460, FKDataToO2O, 300),
  254. (im2m_obj, 470, M2MIntermediateData, None),
  255. # testing post- and prereferences and extra fields
  256. (im_obj, 480, Intermediate, {'right': 300, 'left': 470}),
  257. (im_obj, 481, Intermediate, {'right': 300, 'left': 490}),
  258. (im_obj, 482, Intermediate, {'right': 500, 'left': 470}),
  259. (im_obj, 483, Intermediate, {'right': 500, 'left': 490}),
  260. (im_obj, 484, Intermediate, {'right': 300, 'left': 470, 'extra': "extra"}),
  261. (im_obj, 485, Intermediate, {'right': 300, 'left': 490, 'extra': "extra"}),
  262. (im_obj, 486, Intermediate, {'right': 500, 'left': 470, 'extra': "extra"}),
  263. (im_obj, 487, Intermediate, {'right': 500, 'left': 490, 'extra': "extra"}),
  264. (im2m_obj, 490, M2MIntermediateData, []),
  265. (data_obj, 500, Anchor, "Anchor 3"),
  266. (data_obj, 501, Anchor, "Anchor 4"),
  267. (data_obj, 502, UniqueAnchor, "UAnchor 2"),
  268. (pk_obj, 601, BooleanPKData, True),
  269. (pk_obj, 602, BooleanPKData, False),
  270. (pk_obj, 610, CharPKData, "Test Char PKData"),
  271. # (pk_obj, 620, DatePKData, datetime.date(2006, 6, 16)),
  272. # (pk_obj, 630, DateTimePKData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  273. (pk_obj, 640, EmailPKData, "hovercraft@example.com"),
  274. # (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
  275. (pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
  276. (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
  277. (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
  278. (pk_obj, 672, DecimalPKData, decimal.Decimal('0.0')),
  279. (pk_obj, 673, FloatPKData, 12.345),
  280. (pk_obj, 674, FloatPKData, -12.345),
  281. (pk_obj, 675, FloatPKData, 0.0),
  282. (pk_obj, 680, IntegerPKData, 123456789),
  283. (pk_obj, 681, IntegerPKData, -123456789),
  284. (pk_obj, 682, IntegerPKData, 0),
  285. # (XX, ImagePKData
  286. (pk_obj, 695, GenericIPAddressPKData, "fe80:1424:2223:6cff:fe8a:2e8a:2151:abcd"),
  287. # (pk_obj, 700, NullBooleanPKData, True),
  288. # (pk_obj, 701, NullBooleanPKData, False),
  289. (pk_obj, 720, PositiveIntegerPKData, 123456789),
  290. (pk_obj, 730, PositiveSmallIntegerPKData, 12),
  291. (pk_obj, 740, SlugPKData, "this-is-a-slug"),
  292. (pk_obj, 750, SmallPKData, 12),
  293. (pk_obj, 751, SmallPKData, -12),
  294. (pk_obj, 752, SmallPKData, 0),
  295. # (pk_obj, 760, TextPKData, """This is a long piece of text.
  296. # It contains line breaks.
  297. # Several of them.
  298. # The end."""),
  299. # (pk_obj, 770, TimePKData, datetime.time(10, 42, 37)),
  300. # (pk_obj, 790, XMLPKData, "<foo></foo>"),
  301. (pk_obj, 791, UUIDData, uuid_obj),
  302. (fk_obj, 792, FKToUUID, uuid_obj),
  303. (data_obj, 800, AutoNowDateTimeData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  304. (data_obj, 810, ModifyingSaveData, 42),
  305. (inherited_obj, 900, InheritAbstractModel, {'child_data': 37, 'parent_data': 42}),
  306. (inherited_obj, 910, ExplicitInheritBaseModel, {'child_data': 37, 'parent_data': 42}),
  307. (inherited_obj, 920, InheritBaseModel, {'child_data': 37, 'parent_data': 42}),
  308. (data_obj, 1000, BigIntegerData, 9223372036854775807),
  309. (data_obj, 1001, BigIntegerData, -9223372036854775808),
  310. (data_obj, 1002, BigIntegerData, 0),
  311. (data_obj, 1003, BigIntegerData, None),
  312. (data_obj, 1004, LengthModel, 0),
  313. (data_obj, 1005, LengthModel, 1),
  314. ]
  315. natural_key_test_data = [
  316. (data_obj, 1100, NaturalKeyAnchor, "Natural Key Anghor"),
  317. (fk_obj, 1101, FKDataNaturalKey, 1100),
  318. (fk_obj, 1102, FKDataNaturalKey, None),
  319. ]
  320. # Because Oracle treats the empty string as NULL, Oracle is expected to fail
  321. # when field.empty_strings_allowed is True and the value is None; skip these
  322. # tests.
  323. if connection.features.interprets_empty_strings_as_nulls:
  324. test_data = [data for data in test_data
  325. if not (data[0] == data_obj and
  326. data[2]._meta.get_field('data').empty_strings_allowed and
  327. data[3] is None)]
  328. # Regression test for #8651 -- a FK to an object with PK of 0
  329. # This won't work on MySQL since it won't let you create an object
  330. # with an autoincrement primary key of 0,
  331. if connection.features.allows_auto_pk_0:
  332. test_data.extend([
  333. (data_obj, 0, Anchor, "Anchor 0"),
  334. (fk_obj, 465, FKData, 0),
  335. ])
  336. # Dynamically create serializer tests to ensure that all
  337. # registered serializers are automatically tested.
  338. @skipUnlessDBFeature('can_defer_constraint_checks')
  339. class SerializerTests(TestCase):
  340. def test_get_unknown_serializer(self):
  341. """
  342. #15889: get_serializer('nonsense') raises a SerializerDoesNotExist
  343. """
  344. with self.assertRaises(SerializerDoesNotExist):
  345. serializers.get_serializer("nonsense")
  346. with self.assertRaises(KeyError):
  347. serializers.get_serializer("nonsense")
  348. # SerializerDoesNotExist is instantiated with the nonexistent format
  349. with self.assertRaises(SerializerDoesNotExist) as cm:
  350. serializers.get_serializer("nonsense")
  351. self.assertEqual(cm.exception.args, ("nonsense",))
  352. def test_unregister_unknown_serializer(self):
  353. with self.assertRaises(SerializerDoesNotExist):
  354. serializers.unregister_serializer("nonsense")
  355. def test_get_unknown_deserializer(self):
  356. with self.assertRaises(SerializerDoesNotExist):
  357. serializers.get_deserializer("nonsense")
  358. def test_json_deserializer_exception(self):
  359. with self.assertRaises(DeserializationError):
  360. for obj in serializers.deserialize("json", """[{"pk":1}"""):
  361. pass
  362. @skipUnless(yaml, "PyYAML not installed")
  363. def test_yaml_deserializer_exception(self):
  364. with self.assertRaises(DeserializationError):
  365. for obj in serializers.deserialize("yaml", "{"):
  366. pass
  367. def test_serialize_proxy_model(self):
  368. BaseModel.objects.create(parent_data=1)
  369. base_objects = BaseModel.objects.all()
  370. proxy_objects = ProxyBaseModel.objects.all()
  371. proxy_proxy_objects = ProxyProxyBaseModel.objects.all()
  372. base_data = serializers.serialize("json", base_objects)
  373. proxy_data = serializers.serialize("json", proxy_objects)
  374. proxy_proxy_data = serializers.serialize("json", proxy_proxy_objects)
  375. self.assertEqual(base_data, proxy_data.replace('proxy', ''))
  376. self.assertEqual(base_data, proxy_proxy_data.replace('proxy', ''))
  377. def serializerTest(format, self):
  378. # Create all the objects defined in the test data
  379. objects = []
  380. instance_count = {}
  381. for (func, pk, klass, datum) in test_data:
  382. with connection.constraint_checks_disabled():
  383. objects.extend(func[0](pk, klass, datum))
  384. # Get a count of the number of objects created for each class
  385. for klass in instance_count:
  386. instance_count[klass] = klass.objects.count()
  387. # Add the generic tagged objects to the object list
  388. objects.extend(Tag.objects.all())
  389. # Serialize the test database
  390. serialized_data = serializers.serialize(format, objects, indent=2)
  391. for obj in serializers.deserialize(format, serialized_data):
  392. obj.save()
  393. # Assert that the deserialized data is the same
  394. # as the original source
  395. for (func, pk, klass, datum) in test_data:
  396. func[1](self, pk, klass, datum)
  397. # Assert that the number of objects deserialized is the
  398. # same as the number that was serialized.
  399. for klass, count in instance_count.items():
  400. self.assertEqual(count, klass.objects.count())
  401. def naturalKeySerializerTest(format, self):
  402. # Create all the objects defined in the test data
  403. objects = []
  404. instance_count = {}
  405. for (func, pk, klass, datum) in natural_key_test_data:
  406. with connection.constraint_checks_disabled():
  407. objects.extend(func[0](pk, klass, datum))
  408. # Get a count of the number of objects created for each class
  409. for klass in instance_count:
  410. instance_count[klass] = klass.objects.count()
  411. # Serialize the test database
  412. serialized_data = serializers.serialize(format, objects, indent=2,
  413. use_natural_foreign_keys=True)
  414. for obj in serializers.deserialize(format, serialized_data):
  415. obj.save()
  416. # Assert that the deserialized data is the same
  417. # as the original source
  418. for (func, pk, klass, datum) in natural_key_test_data:
  419. func[1](self, pk, klass, datum)
  420. # Assert that the number of objects deserialized is the
  421. # same as the number that was serialized.
  422. for klass, count in instance_count.items():
  423. self.assertEqual(count, klass.objects.count())
  424. def fieldsTest(format, self):
  425. obj = ComplexModel(field1='first', field2='second', field3='third')
  426. obj.save_base(raw=True)
  427. # Serialize then deserialize the test database
  428. serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1', 'field3'))
  429. result = next(serializers.deserialize(format, serialized_data))
  430. # Check that the deserialized object contains data in only the serialized fields.
  431. self.assertEqual(result.object.field1, 'first')
  432. self.assertEqual(result.object.field2, '')
  433. self.assertEqual(result.object.field3, 'third')
  434. def streamTest(format, self):
  435. obj = ComplexModel(field1='first', field2='second', field3='third')
  436. obj.save_base(raw=True)
  437. # Serialize the test database to a stream
  438. for stream in (six.StringIO(), HttpResponse()):
  439. serializers.serialize(format, [obj], indent=2, stream=stream)
  440. # Serialize normally for a comparison
  441. string_data = serializers.serialize(format, [obj], indent=2)
  442. # Check that the two are the same
  443. if isinstance(stream, six.StringIO):
  444. self.assertEqual(string_data, stream.getvalue())
  445. else:
  446. self.assertEqual(string_data, stream.content.decode('utf-8'))
  447. def naturalKeyTest(format, self):
  448. book1 = {'data': '978-1590597255', 'title': 'The Definitive Guide to '
  449. 'Django: Web Development Done Right'}
  450. book2 = {'data': '978-1590599969', 'title': 'Practical Django Projects'}
  451. # Create the books.
  452. adrian = NaturalKeyAnchor.objects.create(**book1)
  453. james = NaturalKeyAnchor.objects.create(**book2)
  454. # Serialize the books.
  455. string_data = serializers.serialize(format, NaturalKeyAnchor.objects.all(),
  456. indent=2, use_natural_foreign_keys=True,
  457. use_natural_primary_keys=True)
  458. # Delete one book (to prove that the natural key generation will only
  459. # restore the primary keys of books found in the database via the
  460. # get_natural_key manager method).
  461. james.delete()
  462. # Deserialize and test.
  463. books = list(serializers.deserialize(format, string_data))
  464. self.assertEqual(len(books), 2)
  465. self.assertEqual(books[0].object.title, book1['title'])
  466. self.assertEqual(books[0].object.pk, adrian.pk)
  467. self.assertEqual(books[1].object.title, book2['title'])
  468. self.assertEqual(books[1].object.pk, None)
  469. for format in [f for f in serializers.get_serializer_formats()
  470. if not isinstance(serializers.get_serializer(f), serializers.BadSerializer) and not f == 'geojson']:
  471. setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
  472. setattr(SerializerTests, 'test_' + format + '_natural_key_serializer', curry(naturalKeySerializerTest, format))
  473. setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
  474. setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format))
  475. if format != 'python':
  476. setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))
  477. class XmlDeserializerSecurityTests(SimpleTestCase):
  478. def test_no_dtd(self):
  479. """
  480. The XML deserializer shouldn't allow a DTD.
  481. This is the most straightforward way to prevent all entity definitions
  482. and avoid both external entities and entity-expansion attacks.
  483. """
  484. xml = '<?xml version="1.0" standalone="no"?><!DOCTYPE example SYSTEM "http://example.com/example.dtd">'
  485. with self.assertRaises(DTDForbidden):
  486. next(serializers.deserialize('xml', xml))