test_data.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. import datetime
  9. import decimal
  10. import uuid
  11. from django.core import serializers
  12. from django.db import connection, models
  13. from django.test import TestCase
  14. from .models import (
  15. Anchor, AutoNowDateTimeData, BigIntegerData, BinaryData, BooleanData,
  16. BooleanPKData, CharData, CharPKData, DateData, DatePKData, DateTimeData,
  17. DateTimePKData, DecimalData, DecimalPKData, EmailData, EmailPKData,
  18. ExplicitInheritBaseModel, FileData, FilePathData, FilePathPKData, FKData,
  19. FKDataToField, FKDataToO2O, FKSelfData, FKToUUID, FloatData, FloatPKData,
  20. GenericData, GenericIPAddressData, GenericIPAddressPKData,
  21. InheritAbstractModel, InheritBaseModel, IntegerData, IntegerPKData,
  22. Intermediate, LengthModel, M2MData, M2MIntermediateData, M2MSelfData,
  23. ModifyingSaveData, NullBooleanData, O2OData, PositiveBigIntegerData,
  24. PositiveIntegerData, PositiveIntegerPKData, PositiveSmallIntegerData,
  25. PositiveSmallIntegerPKData, SlugData, SlugPKData, SmallData, SmallPKData,
  26. Tag, TextData, TimeData, UniqueAnchor, UUIDData,
  27. )
  28. from .tests import register_tests
  29. # A set of functions that can be used to recreate
  30. # test data objects of various kinds.
  31. # The save method is a raw base model save, to make
  32. # sure that the data in the database matches the
  33. # exact test case.
  34. def data_create(pk, klass, data):
  35. instance = klass(id=pk)
  36. instance.data = data
  37. models.Model.save_base(instance, raw=True)
  38. return [instance]
  39. def generic_create(pk, klass, data):
  40. instance = klass(id=pk)
  41. instance.data = data[0]
  42. models.Model.save_base(instance, raw=True)
  43. for tag in data[1:]:
  44. instance.tags.create(data=tag)
  45. return [instance]
  46. def fk_create(pk, klass, data):
  47. instance = klass(id=pk)
  48. setattr(instance, 'data_id', data)
  49. models.Model.save_base(instance, raw=True)
  50. return [instance]
  51. def m2m_create(pk, klass, data):
  52. instance = klass(id=pk)
  53. models.Model.save_base(instance, raw=True)
  54. instance.data.set(data)
  55. return [instance]
  56. def im2m_create(pk, klass, data):
  57. instance = klass(id=pk)
  58. models.Model.save_base(instance, raw=True)
  59. return [instance]
  60. def im_create(pk, klass, data):
  61. instance = klass(id=pk)
  62. instance.right_id = data['right']
  63. instance.left_id = data['left']
  64. if 'extra' in data:
  65. instance.extra = data['extra']
  66. models.Model.save_base(instance, raw=True)
  67. return [instance]
  68. def o2o_create(pk, klass, data):
  69. instance = klass()
  70. instance.data_id = data
  71. models.Model.save_base(instance, raw=True)
  72. return [instance]
  73. def pk_create(pk, klass, data):
  74. instance = klass()
  75. instance.data = data
  76. models.Model.save_base(instance, raw=True)
  77. return [instance]
  78. def inherited_create(pk, klass, data):
  79. instance = klass(id=pk, **data)
  80. # This isn't a raw save because:
  81. # 1) we're testing inheritance, not field behavior, so none
  82. # of the field values need to be protected.
  83. # 2) saving the child class and having the parent created
  84. # automatically is easier than manually creating both.
  85. models.Model.save(instance)
  86. created = [instance]
  87. for klass in instance._meta.parents:
  88. created.append(klass.objects.get(id=pk))
  89. return created
  90. # A set of functions that can be used to compare
  91. # test data objects of various kinds
  92. def data_compare(testcase, pk, klass, data):
  93. instance = klass.objects.get(id=pk)
  94. if klass == BinaryData and data is not None:
  95. testcase.assertEqual(
  96. bytes(data), bytes(instance.data),
  97. "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (
  98. pk, repr(bytes(data)), type(data), repr(bytes(instance.data)),
  99. type(instance.data),
  100. )
  101. )
  102. else:
  103. testcase.assertEqual(
  104. data, instance.data,
  105. "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % (
  106. pk, data, type(data), instance, type(instance.data),
  107. )
  108. )
  109. def generic_compare(testcase, pk, klass, data):
  110. instance = klass.objects.get(id=pk)
  111. testcase.assertEqual(data[0], instance.data)
  112. testcase.assertEqual(data[1:], [t.data for t in instance.tags.order_by('id')])
  113. def fk_compare(testcase, pk, klass, data):
  114. instance = klass.objects.get(id=pk)
  115. testcase.assertEqual(data, instance.data_id)
  116. def m2m_compare(testcase, pk, klass, data):
  117. instance = klass.objects.get(id=pk)
  118. testcase.assertEqual(data, [obj.id for obj in instance.data.order_by('id')])
  119. def im2m_compare(testcase, pk, klass, data):
  120. klass.objects.get(id=pk)
  121. # actually nothing else to check, the instance just should exist
  122. def im_compare(testcase, pk, klass, data):
  123. instance = klass.objects.get(id=pk)
  124. testcase.assertEqual(data['left'], instance.left_id)
  125. testcase.assertEqual(data['right'], instance.right_id)
  126. if 'extra' in data:
  127. testcase.assertEqual(data['extra'], instance.extra)
  128. else:
  129. testcase.assertEqual("doesn't matter", instance.extra)
  130. def o2o_compare(testcase, pk, klass, data):
  131. instance = klass.objects.get(data=data)
  132. testcase.assertEqual(data, instance.data_id)
  133. def pk_compare(testcase, pk, klass, data):
  134. instance = klass.objects.get(data=data)
  135. testcase.assertEqual(data, instance.data)
  136. def inherited_compare(testcase, pk, klass, data):
  137. instance = klass.objects.get(id=pk)
  138. for key, value in data.items():
  139. testcase.assertEqual(value, getattr(instance, key))
  140. # Define some data types. Each data type is
  141. # actually a pair of functions; one to create
  142. # and one to compare objects of that type
  143. data_obj = (data_create, data_compare)
  144. generic_obj = (generic_create, generic_compare)
  145. fk_obj = (fk_create, fk_compare)
  146. m2m_obj = (m2m_create, m2m_compare)
  147. im2m_obj = (im2m_create, im2m_compare)
  148. im_obj = (im_create, im_compare)
  149. o2o_obj = (o2o_create, o2o_compare)
  150. pk_obj = (pk_create, pk_compare)
  151. inherited_obj = (inherited_create, inherited_compare)
  152. uuid_obj = uuid.uuid4()
  153. test_data = [
  154. # Format: (data type, PK value, Model Class, data)
  155. (data_obj, 1, BinaryData, memoryview(b"\x05\xFD\x00")),
  156. (data_obj, 2, BinaryData, None),
  157. (data_obj, 5, BooleanData, True),
  158. (data_obj, 6, BooleanData, False),
  159. (data_obj, 7, BooleanData, None),
  160. (data_obj, 10, CharData, "Test Char Data"),
  161. (data_obj, 11, CharData, ""),
  162. (data_obj, 12, CharData, "None"),
  163. (data_obj, 13, CharData, "null"),
  164. (data_obj, 14, CharData, "NULL"),
  165. (data_obj, 15, CharData, None),
  166. # (We use something that will fit into a latin1 database encoding here,
  167. # because that is still the default used on many system setups.)
  168. (data_obj, 16, CharData, '\xa5'),
  169. (data_obj, 20, DateData, datetime.date(2006, 6, 16)),
  170. (data_obj, 21, DateData, None),
  171. (data_obj, 30, DateTimeData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  172. (data_obj, 31, DateTimeData, None),
  173. (data_obj, 40, EmailData, "hovercraft@example.com"),
  174. (data_obj, 41, EmailData, None),
  175. (data_obj, 42, EmailData, ""),
  176. (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
  177. # (data_obj, 51, FileData, None),
  178. (data_obj, 52, FileData, ""),
  179. (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
  180. (data_obj, 61, FilePathData, None),
  181. (data_obj, 62, FilePathData, ""),
  182. (data_obj, 70, DecimalData, decimal.Decimal('12.345')),
  183. (data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
  184. (data_obj, 72, DecimalData, decimal.Decimal('0.0')),
  185. (data_obj, 73, DecimalData, None),
  186. (data_obj, 74, FloatData, 12.345),
  187. (data_obj, 75, FloatData, -12.345),
  188. (data_obj, 76, FloatData, 0.0),
  189. (data_obj, 77, FloatData, None),
  190. (data_obj, 80, IntegerData, 123456789),
  191. (data_obj, 81, IntegerData, -123456789),
  192. (data_obj, 82, IntegerData, 0),
  193. (data_obj, 83, IntegerData, None),
  194. # (XX, ImageData
  195. (data_obj, 95, GenericIPAddressData, "fe80:1424:2223:6cff:fe8a:2e8a:2151:abcd"),
  196. (data_obj, 96, GenericIPAddressData, None),
  197. (data_obj, 100, NullBooleanData, True),
  198. (data_obj, 101, NullBooleanData, False),
  199. (data_obj, 102, NullBooleanData, None),
  200. (data_obj, 110, PositiveBigIntegerData, 9223372036854775807),
  201. (data_obj, 111, PositiveBigIntegerData, None),
  202. (data_obj, 120, PositiveIntegerData, 123456789),
  203. (data_obj, 121, PositiveIntegerData, None),
  204. (data_obj, 130, PositiveSmallIntegerData, 12),
  205. (data_obj, 131, PositiveSmallIntegerData, None),
  206. (data_obj, 140, SlugData, "this-is-a-slug"),
  207. (data_obj, 141, SlugData, None),
  208. (data_obj, 142, SlugData, ""),
  209. (data_obj, 150, SmallData, 12),
  210. (data_obj, 151, SmallData, -12),
  211. (data_obj, 152, SmallData, 0),
  212. (data_obj, 153, SmallData, None),
  213. (data_obj, 160, TextData, """This is a long piece of text.
  214. It contains line breaks.
  215. Several of them.
  216. The end."""),
  217. (data_obj, 161, TextData, ""),
  218. (data_obj, 162, TextData, None),
  219. (data_obj, 170, TimeData, datetime.time(10, 42, 37)),
  220. (data_obj, 171, TimeData, None),
  221. (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
  222. (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
  223. (data_obj, 300, Anchor, "Anchor 1"),
  224. (data_obj, 301, Anchor, "Anchor 2"),
  225. (data_obj, 302, UniqueAnchor, "UAnchor 1"),
  226. (fk_obj, 400, FKData, 300), # Post reference
  227. (fk_obj, 401, FKData, 500), # Pre reference
  228. (fk_obj, 402, FKData, None), # Empty reference
  229. (m2m_obj, 410, M2MData, []), # Empty set
  230. (m2m_obj, 411, M2MData, [300, 301]), # Post reference
  231. (m2m_obj, 412, M2MData, [500, 501]), # Pre reference
  232. (m2m_obj, 413, M2MData, [300, 301, 500, 501]), # Pre and Post reference
  233. (o2o_obj, None, O2OData, 300), # Post reference
  234. (o2o_obj, None, O2OData, 500), # Pre reference
  235. (fk_obj, 430, FKSelfData, 431), # Pre reference
  236. (fk_obj, 431, FKSelfData, 430), # Post reference
  237. (fk_obj, 432, FKSelfData, None), # Empty reference
  238. (m2m_obj, 440, M2MSelfData, []),
  239. (m2m_obj, 441, M2MSelfData, []),
  240. (m2m_obj, 442, M2MSelfData, [440, 441]),
  241. (m2m_obj, 443, M2MSelfData, [445, 446]),
  242. (m2m_obj, 444, M2MSelfData, [440, 441, 445, 446]),
  243. (m2m_obj, 445, M2MSelfData, []),
  244. (m2m_obj, 446, M2MSelfData, []),
  245. (fk_obj, 450, FKDataToField, "UAnchor 1"),
  246. (fk_obj, 451, FKDataToField, "UAnchor 2"),
  247. (fk_obj, 452, FKDataToField, None),
  248. (fk_obj, 460, FKDataToO2O, 300),
  249. (im2m_obj, 470, M2MIntermediateData, None),
  250. # testing post- and pre-references and extra fields
  251. (im_obj, 480, Intermediate, {'right': 300, 'left': 470}),
  252. (im_obj, 481, Intermediate, {'right': 300, 'left': 490}),
  253. (im_obj, 482, Intermediate, {'right': 500, 'left': 470}),
  254. (im_obj, 483, Intermediate, {'right': 500, 'left': 490}),
  255. (im_obj, 484, Intermediate, {'right': 300, 'left': 470, 'extra': "extra"}),
  256. (im_obj, 485, Intermediate, {'right': 300, 'left': 490, 'extra': "extra"}),
  257. (im_obj, 486, Intermediate, {'right': 500, 'left': 470, 'extra': "extra"}),
  258. (im_obj, 487, Intermediate, {'right': 500, 'left': 490, 'extra': "extra"}),
  259. (im2m_obj, 490, M2MIntermediateData, []),
  260. (data_obj, 500, Anchor, "Anchor 3"),
  261. (data_obj, 501, Anchor, "Anchor 4"),
  262. (data_obj, 502, UniqueAnchor, "UAnchor 2"),
  263. (pk_obj, 601, BooleanPKData, True),
  264. (pk_obj, 602, BooleanPKData, False),
  265. (pk_obj, 610, CharPKData, "Test Char PKData"),
  266. (pk_obj, 620, DatePKData, datetime.date(2006, 6, 16)),
  267. (pk_obj, 630, DateTimePKData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  268. (pk_obj, 640, EmailPKData, "hovercraft@example.com"),
  269. # (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
  270. (pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
  271. (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
  272. (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
  273. (pk_obj, 672, DecimalPKData, decimal.Decimal('0.0')),
  274. (pk_obj, 673, FloatPKData, 12.345),
  275. (pk_obj, 674, FloatPKData, -12.345),
  276. (pk_obj, 675, FloatPKData, 0.0),
  277. (pk_obj, 680, IntegerPKData, 123456789),
  278. (pk_obj, 681, IntegerPKData, -123456789),
  279. (pk_obj, 682, IntegerPKData, 0),
  280. # (XX, ImagePKData
  281. (pk_obj, 695, GenericIPAddressPKData, "fe80:1424:2223:6cff:fe8a:2e8a:2151:abcd"),
  282. (pk_obj, 720, PositiveIntegerPKData, 123456789),
  283. (pk_obj, 730, PositiveSmallIntegerPKData, 12),
  284. (pk_obj, 740, SlugPKData, "this-is-a-slug"),
  285. (pk_obj, 750, SmallPKData, 12),
  286. (pk_obj, 751, SmallPKData, -12),
  287. (pk_obj, 752, SmallPKData, 0),
  288. # (pk_obj, 760, TextPKData, """This is a long piece of text.
  289. # It contains line breaks.
  290. # Several of them.
  291. # The end."""),
  292. # (pk_obj, 770, TimePKData, datetime.time(10, 42, 37)),
  293. # (pk_obj, 790, XMLPKData, "<foo></foo>"),
  294. (pk_obj, 791, UUIDData, uuid_obj),
  295. (fk_obj, 792, FKToUUID, uuid_obj),
  296. (data_obj, 800, AutoNowDateTimeData, datetime.datetime(2006, 6, 16, 10, 42, 37)),
  297. (data_obj, 810, ModifyingSaveData, 42),
  298. (inherited_obj, 900, InheritAbstractModel, {'child_data': 37, 'parent_data': 42}),
  299. (inherited_obj, 910, ExplicitInheritBaseModel, {'child_data': 37, 'parent_data': 42}),
  300. (inherited_obj, 920, InheritBaseModel, {'child_data': 37, 'parent_data': 42}),
  301. (data_obj, 1000, BigIntegerData, 9223372036854775807),
  302. (data_obj, 1001, BigIntegerData, -9223372036854775808),
  303. (data_obj, 1002, BigIntegerData, 0),
  304. (data_obj, 1003, BigIntegerData, None),
  305. (data_obj, 1004, LengthModel, 0),
  306. (data_obj, 1005, LengthModel, 1),
  307. ]
  308. # Because Oracle treats the empty string as NULL, Oracle is expected to fail
  309. # when field.empty_strings_allowed is True and the value is None; skip these
  310. # tests.
  311. if connection.features.interprets_empty_strings_as_nulls:
  312. test_data = [data for data in test_data
  313. if not (data[0] == data_obj and
  314. data[2]._meta.get_field('data').empty_strings_allowed and
  315. data[3] is None)]
  316. # Regression test for #8651 -- a FK to an object with PK of 0
  317. # This won't work on MySQL since it won't let you create an object
  318. # with an autoincrement primary key of 0,
  319. if connection.features.allows_auto_pk_0:
  320. test_data.extend([
  321. (data_obj, 0, Anchor, "Anchor 0"),
  322. (fk_obj, 465, FKData, 0),
  323. ])
  324. class SerializerDataTests(TestCase):
  325. pass
  326. def serializerTest(self, format):
  327. # Create all the objects defined in the test data
  328. objects = []
  329. instance_count = {}
  330. for (func, pk, klass, datum) in test_data:
  331. with connection.constraint_checks_disabled():
  332. objects.extend(func[0](pk, klass, datum))
  333. # Get a count of the number of objects created for each class
  334. for klass in instance_count:
  335. instance_count[klass] = klass.objects.count()
  336. # Add the generic tagged objects to the object list
  337. objects.extend(Tag.objects.all())
  338. # Serialize the test database
  339. serialized_data = serializers.serialize(format, objects, indent=2)
  340. for obj in serializers.deserialize(format, serialized_data):
  341. obj.save()
  342. # Assert that the deserialized data is the same
  343. # as the original source
  344. for (func, pk, klass, datum) in test_data:
  345. func[1](self, pk, klass, datum)
  346. # Assert that the number of objects deserialized is the
  347. # same as the number that was serialized.
  348. for klass, count in instance_count.items():
  349. self.assertEqual(count, klass.objects.count())
  350. register_tests(SerializerDataTests, 'test_%s_serializer', serializerTest)