~ubuntu-branches/debian/squeeze/python-django/squeeze

« back to all changes in this revision

Viewing changes to tests/regressiontests/serializers_regress/tests.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb, Chris Lamb, David Spreen, Sandro Tosi
  • Date: 2008-11-19 21:31:00 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20081119213100-gp0lqhxl1qxa6dgl
Tags: 1.0.2-1
[ Chris Lamb ]
* New upstream bugfix release. Closes: #505783
* Add myself to Uploaders with ACK from Brett.

[ David Spreen ]
* Remove python-pysqlite2 from Recommends because Python 2.5 includes
  sqlite library used by Django. Closes: 497886

[ Sandro Tosi ]
* debian/control
  - switch Vcs-Browser field to viewsvn

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
A test spanning all the capabilities of all the serializers.
3
 
 
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.
8
 
"""
9
 
 
10
 
 
11
 
import unittest, datetime
12
 
from cStringIO import StringIO
13
 
 
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
19
 
 
20
 
from models import *
21
 
try:
22
 
    import decimal
23
 
except ImportError:
24
 
    from django.utils import _decimal as decimal
25
 
 
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
30
 
# exact test case.
31
 
def data_create(pk, klass, data):
32
 
    instance = klass(id=pk)
33
 
    instance.data = data
34
 
    models.Model.save_base(instance, raw=True)
35
 
    return [instance]
36
 
 
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)
41
 
    for tag in data[1:]:
42
 
        instance.tags.create(data=tag)
43
 
    return [instance]
44
 
 
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)
49
 
    return [instance]
50
 
 
51
 
def m2m_create(pk, klass, data):
52
 
    instance = klass(id=pk)
53
 
    models.Model.save_base(instance, raw=True)
54
 
    instance.data = data
55
 
    return [instance]
56
 
 
57
 
def im2m_create(pk, klass, data):
58
 
    instance = klass(id=pk)
59
 
    models.Model.save_base(instance, raw=True)
60
 
    return [instance]
61
 
 
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'])
66
 
    if 'extra' in data:
67
 
        setattr(instance, 'extra', data['extra'])
68
 
    models.Model.save_base(instance, raw=True)
69
 
    return [instance]
70
 
 
71
 
def o2o_create(pk, klass, data):
72
 
    instance = klass()
73
 
    instance.data_id = data
74
 
    models.Model.save_base(instance, raw=True)
75
 
    return [instance]
76
 
 
77
 
def pk_create(pk, klass, data):
78
 
    instance = klass()
79
 
    instance.data = data
80
 
    models.Model.save_base(instance, raw=True)
81
 
    return [instance]
82
 
 
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)
91
 
    created = [instance]
92
 
    for klass,field in instance._meta.parents.items():
93
 
        created.append(klass.objects.get(id=pk))
94
 
    return created
95
 
 
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)))
102
 
 
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()])
107
 
 
108
 
def fk_compare(testcase, pk, klass, data):
109
 
    instance = klass.objects.get(id=pk)
110
 
    testcase.assertEqual(data, instance.data_id)
111
 
 
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()])
115
 
 
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
119
 
 
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)
124
 
    if 'extra' in data:
125
 
        testcase.assertEqual(data['extra'], instance.extra)
126
 
    else:
127
 
        testcase.assertEqual("doesn't matter", instance.extra)
128
 
 
129
 
def o2o_compare(testcase, pk, klass, data):
130
 
    instance = klass.objects.get(data=data)
131
 
    testcase.assertEqual(data, instance.data_id)
132
 
 
133
 
def pk_compare(testcase, pk, klass, data):
134
 
    instance = klass.objects.get(data=data)
135
 
    testcase.assertEqual(data, instance.data)
136
 
 
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))
141
 
 
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)
154
 
 
155
 
test_data = [
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),
193
 
    #(XX, ImageData
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.
214
 
Several of them.
215
 
The end."""),
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, ""),
226
 
 
227
 
    (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
228
 
    (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
229
 
 
230
 
    (data_obj, 300, Anchor, "Anchor 1"),
231
 
    (data_obj, 301, Anchor, "Anchor 2"),
232
 
    (data_obj, 302, UniqueAnchor, "UAnchor 1"),
233
 
 
234
 
    (fk_obj, 400, FKData, 300), # Post reference
235
 
    (fk_obj, 401, FKData, 500), # Pre reference
236
 
    (fk_obj, 402, FKData, None), # Empty reference
237
 
 
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
242
 
 
243
 
    (o2o_obj, None, O2OData, 300), # Post reference
244
 
    (o2o_obj, None, O2OData, 500), # Pre reference
245
 
 
246
 
    (fk_obj, 430, FKSelfData, 431), # Pre reference
247
 
    (fk_obj, 431, FKSelfData, 430), # Post reference
248
 
    (fk_obj, 432, FKSelfData, None), # Empty reference
249
 
 
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, []),
257
 
 
258
 
    (fk_obj, 450, FKDataToField, "UAnchor 1"),
259
 
    (fk_obj, 451, FKDataToField, "UAnchor 2"),
260
 
    (fk_obj, 452, FKDataToField, None),
261
 
 
262
 
    (fk_obj, 460, FKDataToO2O, 300),
263
 
        
264
 
    (im2m_obj, 470, M2MIntermediateData, None),
265
 
    
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"}), 
275
 
    
276
 
    (im2m_obj, 490, M2MIntermediateData, []),
277
 
 
278
 
    (data_obj, 500, Anchor, "Anchor 3"),
279
 
    (data_obj, 501, Anchor, "Anchor 4"),
280
 
    (data_obj, 502, UniqueAnchor, "UAnchor 2"),
281
 
 
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),
299
 
#     (XX, ImagePKData
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.
312
 
# Several of them.
313
 
# The end."""),
314
 
#    (pk_obj, 770, TimePKData, datetime.time(10,42,37)),
315
 
    (pk_obj, 780, USStatePKData, "MA"),
316
 
#     (pk_obj, 790, XMLPKData, "<foo></foo>"),
317
 
 
318
 
    (data_obj, 800, AutoNowDateTimeData, datetime.datetime(2006,6,16,10,42,37)),
319
 
    (data_obj, 810, ModifyingSaveData, 42),
320
 
 
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}),
324
 
]
325
 
 
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
328
 
# tests.
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
333
 
                         data[3] is None)]
334
 
 
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':
339
 
    test_data.extend([
340
 
        (data_obj, 0, Anchor, "Anchor 0"),
341
 
        (fk_obj, 465, FKData, 0),
342
 
    ])
343
 
 
344
 
# Dynamically create serializer tests to ensure that all
345
 
# registered serializers are automatically tested.
346
 
class SerializerTests(unittest.TestCase):
347
 
    pass
348
 
 
349
 
def serializerTest(format, self):
350
 
    # Clear the database first
351
 
    management.call_command('flush', verbosity=0, interactive=False)
352
 
 
353
 
    # Create all the objects defined in the test data
354
 
    objects = []
355
 
    instance_count = {}
356
 
    transaction.enter_transaction_management()
357
 
    try:
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
362
 
        transaction.commit()
363
 
    finally:
364
 
        transaction.leave_transaction_management()
365
 
 
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()
369
 
 
370
 
    # Add the generic tagged objects to the object list
371
 
    objects.extend(Tag.objects.all())
372
 
 
373
 
    # Serialize the test database
374
 
    serialized_data = serializers.serialize(format, objects, indent=2)
375
 
 
376
 
    # Flush the database and recreate from the serialized data
377
 
    management.call_command('flush', verbosity=0, interactive=False)
378
 
    transaction.enter_transaction_management()
379
 
    try:
380
 
        transaction.managed(True)
381
 
        for obj in serializers.deserialize(format, serialized_data):
382
 
            obj.save()
383
 
        transaction.commit()
384
 
    finally:
385
 
        transaction.leave_transaction_management()
386
 
 
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)
391
 
 
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())
396
 
 
397
 
def fieldsTest(format, self):
398
 
    # Clear the database first
399
 
    management.call_command('flush', verbosity=0, interactive=False)
400
 
 
401
 
    obj = ComplexModel(field1='first',field2='second',field3='third')
402
 
    obj.save_base(raw=True)
403
 
 
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()
407
 
 
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')
412
 
 
413
 
def streamTest(format, self):
414
 
    # Clear the database first
415
 
    management.call_command('flush', verbosity=0, interactive=False)
416
 
 
417
 
    obj = ComplexModel(field1='first',field2='second',field3='third')
418
 
    obj.save_base(raw=True)
419
 
 
420
 
    # Serialize the test database to a stream
421
 
    stream = StringIO()
422
 
    serializers.serialize(format, [obj], indent=2, stream=stream)
423
 
 
424
 
    # Serialize normally for a comparison
425
 
    string_data = serializers.serialize(format, [obj], indent=2)
426
 
 
427
 
    # Check that the two are the same
428
 
    self.assertEqual(string_data, stream.getvalue())
429
 
    stream.close()
430
 
 
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))