parts/django/tests/regressiontests/serializers_regress/tests.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     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 datetime
       
    12 import decimal
       
    13 try:
       
    14     from cStringIO import StringIO
       
    15 except ImportError:
       
    16     from StringIO import StringIO
       
    17 
       
    18 from django.conf import settings
       
    19 from django.core import serializers, management
       
    20 from django.db import transaction, DEFAULT_DB_ALIAS
       
    21 from django.test import TestCase
       
    22 from django.utils.functional import curry
       
    23 
       
    24 from models import *
       
    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     instance.right_id = data['right']
       
    65     instance.left_id = data['left']
       
    66     if 'extra' in data:
       
    67         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)" % (
       
   102             pk, data, type(data), instance.data, type(instance.data))
       
   103     )
       
   104 
       
   105 def generic_compare(testcase, pk, klass, data):
       
   106     instance = klass.objects.get(id=pk)
       
   107     testcase.assertEqual(data[0], instance.data)
       
   108     testcase.assertEqual(data[1:], [t.data for t in instance.tags.order_by('id')])
       
   109 
       
   110 def fk_compare(testcase, pk, klass, data):
       
   111     instance = klass.objects.get(id=pk)
       
   112     testcase.assertEqual(data, instance.data_id)
       
   113 
       
   114 def m2m_compare(testcase, pk, klass, data):
       
   115     instance = klass.objects.get(id=pk)
       
   116     testcase.assertEqual(data, [obj.id for obj in instance.data.order_by('id')])
       
   117 
       
   118 def im2m_compare(testcase, pk, klass, data):
       
   119     instance = klass.objects.get(id=pk)
       
   120     #actually nothing else to check, the instance just should exist
       
   121 
       
   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 
       
   131 def o2o_compare(testcase, pk, klass, data):
       
   132     instance = klass.objects.get(data=data)
       
   133     testcase.assertEqual(data, instance.data_id)
       
   134 
       
   135 def pk_compare(testcase, pk, klass, data):
       
   136     instance = klass.objects.get(data=data)
       
   137     testcase.assertEqual(data, instance.data)
       
   138 
       
   139 def inherited_compare(testcase, pk, klass, data):
       
   140     instance = klass.objects.get(id=pk)
       
   141     for key,value in data.items():
       
   142         testcase.assertEqual(value, getattr(instance,key))
       
   143 
       
   144 # Define some data types. Each data type is
       
   145 # actually a pair of functions; one to create
       
   146 # and one to compare objects of that type
       
   147 data_obj = (data_create, data_compare)
       
   148 generic_obj = (generic_create, generic_compare)
       
   149 fk_obj = (fk_create, fk_compare)
       
   150 m2m_obj = (m2m_create, m2m_compare)
       
   151 im2m_obj = (im2m_create, im2m_compare)
       
   152 im_obj = (im_create, im_compare)
       
   153 o2o_obj = (o2o_create, o2o_compare)
       
   154 pk_obj = (pk_create, pk_compare)
       
   155 inherited_obj = (inherited_create, inherited_compare)
       
   156 
       
   157 test_data = [
       
   158     # Format: (data type, PK value, Model Class, data)
       
   159     (data_obj, 1, BooleanData, True),
       
   160     (data_obj, 2, BooleanData, False),
       
   161     (data_obj, 10, CharData, "Test Char Data"),
       
   162     (data_obj, 11, CharData, ""),
       
   163     (data_obj, 12, CharData, "None"),
       
   164     (data_obj, 13, CharData, "null"),
       
   165     (data_obj, 14, CharData, "NULL"),
       
   166     (data_obj, 15, CharData, None),
       
   167     # (We use something that will fit into a latin1 database encoding here,
       
   168     # because that is still the default used on many system setups.)
       
   169     (data_obj, 16, CharData, u'\xa5'),
       
   170     (data_obj, 20, DateData, datetime.date(2006,6,16)),
       
   171     (data_obj, 21, DateData, None),
       
   172     (data_obj, 30, DateTimeData, datetime.datetime(2006,6,16,10,42,37)),
       
   173     (data_obj, 31, DateTimeData, None),
       
   174     (data_obj, 40, EmailData, "hovercraft@example.com"),
       
   175     (data_obj, 41, EmailData, None),
       
   176     (data_obj, 42, EmailData, ""),
       
   177     (data_obj, 50, FileData, 'file:///foo/bar/whiz.txt'),
       
   178 #     (data_obj, 51, FileData, None),
       
   179     (data_obj, 52, FileData, ""),
       
   180     (data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
       
   181     (data_obj, 61, FilePathData, None),
       
   182     (data_obj, 62, FilePathData, ""),
       
   183     (data_obj, 70, DecimalData, decimal.Decimal('12.345')),
       
   184     (data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
       
   185     (data_obj, 72, DecimalData, decimal.Decimal('0.0')),
       
   186     (data_obj, 73, DecimalData, None),
       
   187     (data_obj, 74, FloatData, 12.345),
       
   188     (data_obj, 75, FloatData, -12.345),
       
   189     (data_obj, 76, FloatData, 0.0),
       
   190     (data_obj, 77, FloatData, None),
       
   191     (data_obj, 80, IntegerData, 123456789),
       
   192     (data_obj, 81, IntegerData, -123456789),
       
   193     (data_obj, 82, IntegerData, 0),
       
   194     (data_obj, 83, IntegerData, None),
       
   195     #(XX, ImageData
       
   196     (data_obj, 90, IPAddressData, "127.0.0.1"),
       
   197     (data_obj, 91, IPAddressData, None),
       
   198     (data_obj, 100, NullBooleanData, True),
       
   199     (data_obj, 101, NullBooleanData, False),
       
   200     (data_obj, 102, NullBooleanData, None),
       
   201     (data_obj, 110, PhoneData, "212-634-5789"),
       
   202     (data_obj, 111, PhoneData, None),
       
   203     (data_obj, 120, PositiveIntegerData, 123456789),
       
   204     (data_obj, 121, PositiveIntegerData, None),
       
   205     (data_obj, 130, PositiveSmallIntegerData, 12),
       
   206     (data_obj, 131, PositiveSmallIntegerData, None),
       
   207     (data_obj, 140, SlugData, "this-is-a-slug"),
       
   208     (data_obj, 141, SlugData, None),
       
   209     (data_obj, 142, SlugData, ""),
       
   210     (data_obj, 150, SmallData, 12),
       
   211     (data_obj, 151, SmallData, -12),
       
   212     (data_obj, 152, SmallData, 0),
       
   213     (data_obj, 153, SmallData, None),
       
   214     (data_obj, 160, TextData, """This is a long piece of text.
       
   215 It contains line breaks.
       
   216 Several of them.
       
   217 The end."""),
       
   218     (data_obj, 161, TextData, ""),
       
   219     (data_obj, 162, TextData, None),
       
   220     (data_obj, 170, TimeData, datetime.time(10,42,37)),
       
   221     (data_obj, 171, TimeData, None),
       
   222     (data_obj, 180, USStateData, "MA"),
       
   223     (data_obj, 181, USStateData, None),
       
   224     (data_obj, 182, USStateData, ""),
       
   225     (data_obj, 190, XMLData, "<foo></foo>"),
       
   226     (data_obj, 191, XMLData, None),
       
   227     (data_obj, 192, XMLData, ""),
       
   228 
       
   229     (generic_obj, 200, GenericData, ['Generic Object 1', 'tag1', 'tag2']),
       
   230     (generic_obj, 201, GenericData, ['Generic Object 2', 'tag2', 'tag3']),
       
   231 
       
   232     (data_obj, 300, Anchor, "Anchor 1"),
       
   233     (data_obj, 301, Anchor, "Anchor 2"),
       
   234     (data_obj, 302, UniqueAnchor, "UAnchor 1"),
       
   235 
       
   236     (fk_obj, 400, FKData, 300), # Post reference
       
   237     (fk_obj, 401, FKData, 500), # Pre reference
       
   238     (fk_obj, 402, FKData, None), # Empty reference
       
   239 
       
   240     (m2m_obj, 410, M2MData, []), # Empty set
       
   241     (m2m_obj, 411, M2MData, [300,301]), # Post reference
       
   242     (m2m_obj, 412, M2MData, [500,501]), # Pre reference
       
   243     (m2m_obj, 413, M2MData, [300,301,500,501]), # Pre and Post reference
       
   244 
       
   245     (o2o_obj, None, O2OData, 300), # Post reference
       
   246     (o2o_obj, None, O2OData, 500), # Pre reference
       
   247 
       
   248     (fk_obj, 430, FKSelfData, 431), # Pre reference
       
   249     (fk_obj, 431, FKSelfData, 430), # Post reference
       
   250     (fk_obj, 432, FKSelfData, None), # Empty reference
       
   251 
       
   252     (m2m_obj, 440, M2MSelfData, []),
       
   253     (m2m_obj, 441, M2MSelfData, []),
       
   254     (m2m_obj, 442, M2MSelfData, [440, 441]),
       
   255     (m2m_obj, 443, M2MSelfData, [445, 446]),
       
   256     (m2m_obj, 444, M2MSelfData, [440, 441, 445, 446]),
       
   257     (m2m_obj, 445, M2MSelfData, []),
       
   258     (m2m_obj, 446, M2MSelfData, []),
       
   259 
       
   260     (fk_obj, 450, FKDataToField, "UAnchor 1"),
       
   261     (fk_obj, 451, FKDataToField, "UAnchor 2"),
       
   262     (fk_obj, 452, FKDataToField, None),
       
   263 
       
   264     (fk_obj, 460, FKDataToO2O, 300),
       
   265 
       
   266     (im2m_obj, 470, M2MIntermediateData, None),
       
   267 
       
   268     #testing post- and prereferences and extra fields
       
   269     (im_obj, 480, Intermediate, {'right': 300, 'left': 470}),
       
   270     (im_obj, 481, Intermediate, {'right': 300, 'left': 490}),
       
   271     (im_obj, 482, Intermediate, {'right': 500, 'left': 470}),
       
   272     (im_obj, 483, Intermediate, {'right': 500, 'left': 490}),
       
   273     (im_obj, 484, Intermediate, {'right': 300, 'left': 470, 'extra': "extra"}),
       
   274     (im_obj, 485, Intermediate, {'right': 300, 'left': 490, 'extra': "extra"}),
       
   275     (im_obj, 486, Intermediate, {'right': 500, 'left': 470, 'extra': "extra"}),
       
   276     (im_obj, 487, Intermediate, {'right': 500, 'left': 490, 'extra': "extra"}),
       
   277 
       
   278     (im2m_obj, 490, M2MIntermediateData, []),
       
   279 
       
   280     (data_obj, 500, Anchor, "Anchor 3"),
       
   281     (data_obj, 501, Anchor, "Anchor 4"),
       
   282     (data_obj, 502, UniqueAnchor, "UAnchor 2"),
       
   283 
       
   284     (pk_obj, 601, BooleanPKData, True),
       
   285     (pk_obj, 602, BooleanPKData, False),
       
   286     (pk_obj, 610, CharPKData, "Test Char PKData"),
       
   287 #     (pk_obj, 620, DatePKData, datetime.date(2006,6,16)),
       
   288 #     (pk_obj, 630, DateTimePKData, datetime.datetime(2006,6,16,10,42,37)),
       
   289     (pk_obj, 640, EmailPKData, "hovercraft@example.com"),
       
   290 #     (pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
       
   291     (pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
       
   292     (pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
       
   293     (pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
       
   294     (pk_obj, 672, DecimalPKData, decimal.Decimal('0.0')),
       
   295     (pk_obj, 673, FloatPKData, 12.345),
       
   296     (pk_obj, 674, FloatPKData, -12.345),
       
   297     (pk_obj, 675, FloatPKData, 0.0),
       
   298     (pk_obj, 680, IntegerPKData, 123456789),
       
   299     (pk_obj, 681, IntegerPKData, -123456789),
       
   300     (pk_obj, 682, IntegerPKData, 0),
       
   301 #     (XX, ImagePKData
       
   302     (pk_obj, 690, IPAddressPKData, "127.0.0.1"),
       
   303     # (pk_obj, 700, NullBooleanPKData, True),
       
   304     # (pk_obj, 701, NullBooleanPKData, False),
       
   305     (pk_obj, 710, PhonePKData, "212-634-5789"),
       
   306     (pk_obj, 720, PositiveIntegerPKData, 123456789),
       
   307     (pk_obj, 730, PositiveSmallIntegerPKData, 12),
       
   308     (pk_obj, 740, SlugPKData, "this-is-a-slug"),
       
   309     (pk_obj, 750, SmallPKData, 12),
       
   310     (pk_obj, 751, SmallPKData, -12),
       
   311     (pk_obj, 752, SmallPKData, 0),
       
   312 #     (pk_obj, 760, TextPKData, """This is a long piece of text.
       
   313 # It contains line breaks.
       
   314 # Several of them.
       
   315 # The end."""),
       
   316 #    (pk_obj, 770, TimePKData, datetime.time(10,42,37)),
       
   317     (pk_obj, 780, USStatePKData, "MA"),
       
   318 #     (pk_obj, 790, XMLPKData, "<foo></foo>"),
       
   319 
       
   320     (data_obj, 800, AutoNowDateTimeData, datetime.datetime(2006,6,16,10,42,37)),
       
   321     (data_obj, 810, ModifyingSaveData, 42),
       
   322 
       
   323     (inherited_obj, 900, InheritAbstractModel, {'child_data':37,'parent_data':42}),
       
   324     (inherited_obj, 910, ExplicitInheritBaseModel, {'child_data':37,'parent_data':42}),
       
   325     (inherited_obj, 920, InheritBaseModel, {'child_data':37,'parent_data':42}),
       
   326 
       
   327     (data_obj, 1000, BigIntegerData, 9223372036854775807),
       
   328     (data_obj, 1001, BigIntegerData, -9223372036854775808),
       
   329     (data_obj, 1002, BigIntegerData, 0),
       
   330     (data_obj, 1003, BigIntegerData, None),
       
   331     (data_obj, 1004, LengthModel, 0),
       
   332     (data_obj, 1005, LengthModel, 1),
       
   333 ]
       
   334 
       
   335 # Because Oracle treats the empty string as NULL, Oracle is expected to fail
       
   336 # when field.empty_strings_allowed is True and the value is None; skip these
       
   337 # tests.
       
   338 if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == 'django.db.backends.oracle':
       
   339     test_data = [data for data in test_data
       
   340                  if not (data[0] == data_obj and
       
   341                          data[2]._meta.get_field('data').empty_strings_allowed and
       
   342                          data[3] is None)]
       
   343 
       
   344 # Regression test for #8651 -- a FK to an object iwth PK of 0
       
   345 # This won't work on MySQL since it won't let you create an object
       
   346 # with a primary key of 0,
       
   347 if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != 'django.db.backends.mysql':
       
   348     test_data.extend([
       
   349         (data_obj, 0, Anchor, "Anchor 0"),
       
   350         (fk_obj, 465, FKData, 0),
       
   351     ])
       
   352 
       
   353 # Dynamically create serializer tests to ensure that all
       
   354 # registered serializers are automatically tested.
       
   355 class SerializerTests(TestCase):
       
   356     pass
       
   357 
       
   358 def serializerTest(format, self):
       
   359 
       
   360     # Create all the objects defined in the test data
       
   361     objects = []
       
   362     instance_count = {}
       
   363     for (func, pk, klass, datum) in test_data:
       
   364         objects.extend(func[0](pk, klass, datum))
       
   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     for obj in serializers.deserialize(format, serialized_data):
       
   377         obj.save()
       
   378 
       
   379     # Assert that the deserialized data is the same
       
   380     # as the original source
       
   381     for (func, pk, klass, datum) in test_data:
       
   382         func[1](self, pk, klass, datum)
       
   383 
       
   384     # Assert that the number of objects deserialized is the
       
   385     # same as the number that was serialized.
       
   386     for klass, count in instance_count.items():
       
   387         self.assertEquals(count, klass.objects.count())
       
   388 
       
   389 def fieldsTest(format, self):
       
   390     obj = ComplexModel(field1='first', field2='second', field3='third')
       
   391     obj.save_base(raw=True)
       
   392 
       
   393     # Serialize then deserialize the test database
       
   394     serialized_data = serializers.serialize(format, [obj], indent=2, fields=('field1','field3'))
       
   395     result = serializers.deserialize(format, serialized_data).next()
       
   396 
       
   397     # Check that the deserialized object contains data in only the serialized fields.
       
   398     self.assertEqual(result.object.field1, 'first')
       
   399     self.assertEqual(result.object.field2, '')
       
   400     self.assertEqual(result.object.field3, 'third')
       
   401 
       
   402 def streamTest(format, self):
       
   403     obj = ComplexModel(field1='first',field2='second',field3='third')
       
   404     obj.save_base(raw=True)
       
   405 
       
   406     # Serialize the test database to a stream
       
   407     stream = StringIO()
       
   408     serializers.serialize(format, [obj], indent=2, stream=stream)
       
   409 
       
   410     # Serialize normally for a comparison
       
   411     string_data = serializers.serialize(format, [obj], indent=2)
       
   412 
       
   413     # Check that the two are the same
       
   414     self.assertEqual(string_data, stream.getvalue())
       
   415     stream.close()
       
   416 
       
   417 for format in serializers.get_serializer_formats():
       
   418     setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
       
   419     setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
       
   420     if format != 'python':
       
   421         setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))