tests.py 17 KB

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