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