PageRenderTime 578ms CodeModel.GetById 121ms app.highlight 354ms RepoModel.GetById 59ms app.codeStats 1ms

/tests/modeltests/serializers/tests.py

https://code.google.com/p/mango-py/
Python | 468 lines | 407 code | 33 blank | 28 comment | 10 complexity | 8d60417ff1bae4d559da1c05d1df91ff MD5 | raw file
  1# -*- coding: utf-8 -*-
  2from datetime import datetime
  3from StringIO import StringIO
  4from xml.dom import minidom
  5
  6from django.conf import settings
  7from django.core import serializers
  8from django.db import transaction
  9from django.test import TestCase, TransactionTestCase, Approximate
 10from django.utils import simplejson, unittest
 11
 12from models import Category, Author, Article, AuthorProfile, Actor, \
 13                                    Movie, Score, Player, Team
 14
 15class SerializerRegistrationTests(unittest.TestCase):
 16    def setUp(self):
 17        self.old_SERIALIZATION_MODULES = getattr(settings, 'SERIALIZATION_MODULES', None)
 18        self.old_serializers = serializers._serializers
 19
 20        serializers._serializers = {}
 21        settings.SERIALIZATION_MODULES = {
 22            "json2" : "django.core.serializers.json",
 23        }
 24
 25    def tearDown(self):
 26        serializers._serializers = self.old_serializers
 27        if self.old_SERIALIZATION_MODULES:
 28            settings.SERIALIZATION_MODULES = self.old_SERIALIZATION_MODULES
 29        else:
 30            delattr(settings, 'SERIALIZATION_MODULES')
 31
 32    def test_register(self):
 33        "Registering a new serializer populates the full registry. Refs #14823"
 34        serializers.register_serializer('json3', 'django.core.serializers.json')
 35
 36        public_formats = serializers.get_public_serializer_formats()
 37        self.assertIn('json3', public_formats)
 38        self.assertIn('json2', public_formats)
 39        self.assertIn('xml', public_formats)
 40
 41    def test_unregister(self):
 42        "Unregistering a serializer doesn't cause the registry to be repopulated. Refs #14823"
 43        serializers.unregister_serializer('xml')
 44        serializers.register_serializer('json3', 'django.core.serializers.json')
 45
 46        public_formats = serializers.get_public_serializer_formats()
 47
 48        self.assertNotIn('xml', public_formats)
 49        self.assertIn('json3', public_formats)
 50
 51    def test_builtin_serializers(self):
 52        "Requesting a list of serializer formats popuates the registry"
 53        all_formats = set(serializers.get_serializer_formats())
 54        public_formats = set(serializers.get_public_serializer_formats())
 55
 56        self.assertIn('xml', all_formats),
 57        self.assertIn('xml', public_formats)
 58
 59        self.assertIn('json2', all_formats)
 60        self.assertIn('json2', public_formats)
 61
 62        self.assertIn('python', all_formats)
 63        self.assertNotIn('python', public_formats)
 64
 65class SerializersTestBase(object):
 66    @staticmethod
 67    def _comparison_value(value):
 68        return value
 69
 70    def setUp(self):
 71        sports = Category.objects.create(name="Sports")
 72        music = Category.objects.create(name="Music")
 73        op_ed = Category.objects.create(name="Op-Ed")
 74
 75        self.joe = Author.objects.create(name="Joe")
 76        self.jane = Author.objects.create(name="Jane")
 77
 78        self.a1 = Article(
 79            author=self.jane,
 80            headline="Poker has no place on ESPN",
 81            pub_date=datetime(2006, 6, 16, 11, 00)
 82        )
 83        self.a1.save()
 84        self.a1.categories = [sports, op_ed]
 85
 86        self.a2 = Article(
 87            author=self.joe,
 88            headline="Time to reform copyright",
 89            pub_date=datetime(2006, 6, 16, 13, 00, 11, 345)
 90        )
 91        self.a2.save()
 92        self.a2.categories = [music, op_ed]
 93
 94    def test_serialize(self):
 95        """Tests that basic serialization works."""
 96        serial_str = serializers.serialize(self.serializer_name,
 97                                           Article.objects.all())
 98        self.assertTrue(self._validate_output(serial_str))
 99
100    def test_serializer_roundtrip(self):
101        """Tests that serialized content can be deserialized."""
102        serial_str = serializers.serialize(self.serializer_name,
103                                           Article.objects.all())
104        models = list(serializers.deserialize(self.serializer_name, serial_str))
105        self.assertEqual(len(models), 2)
106
107    def test_altering_serialized_output(self):
108        """
109        Tests the ability to create new objects by
110        modifying serialized content.
111        """
112        old_headline = "Poker has no place on ESPN"
113        new_headline = "Poker has no place on television"
114        serial_str = serializers.serialize(self.serializer_name,
115                                           Article.objects.all())
116        serial_str = serial_str.replace(old_headline, new_headline)
117        models = list(serializers.deserialize(self.serializer_name, serial_str))
118
119        # Prior to saving, old headline is in place
120        self.assertTrue(Article.objects.filter(headline=old_headline))
121        self.assertFalse(Article.objects.filter(headline=new_headline))
122
123        for model in models:
124            model.save()
125
126        # After saving, new headline is in place
127        self.assertTrue(Article.objects.filter(headline=new_headline))
128        self.assertFalse(Article.objects.filter(headline=old_headline))
129
130    def test_one_to_one_as_pk(self):
131        """
132        Tests that if you use your own primary key field
133        (such as a OneToOneField), it doesn't appear in the
134        serialized field list - it replaces the pk identifier.
135        """
136        profile = AuthorProfile(author=self.joe,
137                                date_of_birth=datetime(1970,1,1))
138        profile.save()
139        serial_str = serializers.serialize(self.serializer_name,
140                                           AuthorProfile.objects.all())
141        self.assertFalse(self._get_field_values(serial_str, 'author'))
142
143        for obj in serializers.deserialize(self.serializer_name, serial_str):
144            self.assertEqual(obj.object.pk, self._comparison_value(self.joe.pk))
145
146    def test_serialize_field_subset(self):
147        """Tests that output can be restricted to a subset of fields"""
148        valid_fields = ('headline','pub_date')
149        invalid_fields = ("author", "categories")
150        serial_str = serializers.serialize(self.serializer_name,
151                                    Article.objects.all(),
152                                    fields=valid_fields)
153        for field_name in invalid_fields:
154            self.assertFalse(self._get_field_values(serial_str, field_name))
155
156        for field_name in valid_fields:
157            self.assertTrue(self._get_field_values(serial_str, field_name))
158
159    def test_serialize_unicode(self):
160        """Tests that unicode makes the roundtrip intact"""
161        actor_name = u"Za\u017c\u00f3\u0142\u0107"
162        movie_title = u'G\u0119\u015bl\u0105 ja\u017a\u0144'
163        ac = Actor(name=actor_name)
164        mv = Movie(title=movie_title, actor=ac)
165        ac.save()
166        mv.save()
167
168        serial_str = serializers.serialize(self.serializer_name, [mv])
169        self.assertEqual(self._get_field_values(serial_str, "title")[0], movie_title)
170        self.assertEqual(self._get_field_values(serial_str, "actor")[0], actor_name)
171
172        obj_list = list(serializers.deserialize(self.serializer_name, serial_str))
173        mv_obj = obj_list[0].object
174        self.assertEqual(mv_obj.title, movie_title)
175
176    def test_serialize_with_null_pk(self):
177        """
178        Tests that serialized data with no primary key results
179        in a model instance with no id
180        """
181        category = Category(name="Reference")
182        serial_str = serializers.serialize(self.serializer_name, [category])
183        pk_value = self._get_pk_values(serial_str)[0]
184        self.assertFalse(pk_value)
185
186        cat_obj = list(serializers.deserialize(self.serializer_name,
187                                               serial_str))[0].object
188        self.assertEqual(cat_obj.id, None)
189
190    def test_float_serialization(self):
191        """Tests that float values serialize and deserialize intact"""
192        sc = Score(score=3.4)
193        sc.save()
194        serial_str = serializers.serialize(self.serializer_name, [sc])
195        deserial_objs = list(serializers.deserialize(self.serializer_name,
196                                                serial_str))
197        self.assertEqual(deserial_objs[0].object.score, Approximate(3.4, places=1))
198
199    def test_custom_field_serialization(self):
200        """Tests that custom fields serialize and deserialize intact"""
201        team_str = "Spartak Moskva"
202        player = Player()
203        player.name = "Soslan Djanaev"
204        player.rank = 1
205        player.team = Team(team_str)
206        player.save()
207        serial_str = serializers.serialize(self.serializer_name,
208                                           Player.objects.all())
209        team = self._get_field_values(serial_str, "team")
210        self.assertTrue(team)
211        self.assertEqual(team[0], team_str)
212
213        deserial_objs = list(serializers.deserialize(self.serializer_name, serial_str))
214        self.assertEqual(deserial_objs[0].object.team.to_string(),
215                         player.team.to_string())
216
217    def test_pre_1000ad_date(self):
218        """Tests that year values before 1000AD are properly formatted"""
219        # Regression for #12524 -- dates before 1000AD get prefixed
220        # 0's on the year
221        a = Article.objects.create(
222        author = self.jane,
223        headline = "Nobody remembers the early years",
224        pub_date = datetime(1, 2, 3, 4, 5, 6))
225
226        serial_str = serializers.serialize(self.serializer_name, [a])
227        date_values = self._get_field_values(serial_str, "pub_date")
228        self.assertEqual(date_values[0], "0001-02-03 04:05:06")
229
230    def test_pkless_serialized_strings(self):
231        """
232        Tests that serialized strings without PKs
233        can be turned into models
234        """
235        deserial_objs = list(serializers.deserialize(self.serializer_name,
236                                                     self.pkless_str))
237        for obj in deserial_objs:
238            self.assertFalse(obj.object.id)
239            obj.save()
240        self.assertEqual(Category.objects.all().count(), 4)
241
242
243class SerializersTransactionTestBase(object):
244    def test_forward_refs(self):
245        """
246        Tests that objects ids can be referenced before they are
247        defined in the serialization data.
248        """
249        # The deserialization process needs to be contained
250        # within a transaction in order to test forward reference
251        # handling.
252        transaction.enter_transaction_management()
253        transaction.managed(True)
254        objs = serializers.deserialize(self.serializer_name, self.fwd_ref_str)
255        for obj in objs:
256            obj.save()
257        transaction.commit()
258        transaction.leave_transaction_management()
259
260        for model_cls in (Category, Author, Article):
261            self.assertEqual(model_cls.objects.all().count(), 1)
262        art_obj = Article.objects.all()[0]
263        self.assertEqual(art_obj.categories.all().count(), 1)
264        self.assertEqual(art_obj.author.name, "Agnes")
265
266
267class XmlSerializerTestCase(SerializersTestBase, TestCase):
268    serializer_name = "xml"
269    pkless_str = """<?xml version="1.0" encoding="utf-8"?>
270<django-objects version="1.0">
271    <object model="serializers.category">
272        <field type="CharField" name="name">Reference</field>
273    </object>
274</django-objects>"""
275
276    @staticmethod
277    def _comparison_value(value):
278        # The XML serializer handles everything as strings, so comparisons
279        # need to be performed on the stringified value
280        return unicode(value)
281
282    @staticmethod
283    def _validate_output(serial_str):
284        try:
285            minidom.parseString(serial_str)
286        except Exception:
287            return False
288        else:
289            return True
290
291    @staticmethod
292    def _get_pk_values(serial_str):
293        ret_list = []
294        dom = minidom.parseString(serial_str)
295        fields = dom.getElementsByTagName("object")
296        for field in fields:
297            ret_list.append(field.getAttribute("pk"))
298        return ret_list
299
300    @staticmethod
301    def _get_field_values(serial_str, field_name):
302        ret_list = []
303        dom = minidom.parseString(serial_str)
304        fields = dom.getElementsByTagName("field")
305        for field in fields:
306            if field.getAttribute("name") == field_name:
307                temp = []
308                for child in field.childNodes:
309                    temp.append(child.nodeValue)
310                ret_list.append("".join(temp))
311        return ret_list
312
313class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
314    serializer_name = "xml"
315    fwd_ref_str = """<?xml version="1.0" encoding="utf-8"?>
316<django-objects version="1.0">
317    <object pk="1" model="serializers.article">
318        <field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
319        <field type="CharField" name="headline">Forward references pose no problem</field>
320        <field type="DateTimeField" name="pub_date">2006-06-16 15:00:00</field>
321        <field to="serializers.category" name="categories" rel="ManyToManyRel">
322            <object pk="1"></object>
323        </field>
324    </object>
325    <object pk="1" model="serializers.author">
326        <field type="CharField" name="name">Agnes</field>
327    </object>
328    <object pk="1" model="serializers.category">
329        <field type="CharField" name="name">Reference</field></object>
330</django-objects>"""
331
332
333class JsonSerializerTestCase(SerializersTestBase, TestCase):
334    serializer_name = "json"
335    pkless_str = """[{"pk": null, "model": "serializers.category", "fields": {"name": "Reference"}}]"""
336
337    @staticmethod
338    def _validate_output(serial_str):
339        try:
340            simplejson.loads(serial_str)
341        except Exception:
342            return False
343        else:
344            return True
345
346    @staticmethod
347    def _get_pk_values(serial_str):
348        ret_list = []
349        serial_list = simplejson.loads(serial_str)
350        for obj_dict in serial_list:
351            ret_list.append(obj_dict["pk"])
352        return ret_list
353
354    @staticmethod
355    def _get_field_values(serial_str, field_name):
356        ret_list = []
357        serial_list = simplejson.loads(serial_str)
358        for obj_dict in serial_list:
359            if field_name in obj_dict["fields"]:
360                ret_list.append(obj_dict["fields"][field_name])
361        return ret_list
362
363class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
364    serializer_name = "json"
365    fwd_ref_str = """[
366    {
367        "pk": 1,
368        "model": "serializers.article",
369        "fields": {
370            "headline": "Forward references pose no problem",
371            "pub_date": "2006-06-16 15:00:00",
372            "categories": [1],
373            "author": 1
374        }
375    },
376    {
377        "pk": 1,
378        "model": "serializers.category",
379        "fields": {
380            "name": "Reference"
381        }
382    },
383    {
384        "pk": 1,
385        "model": "serializers.author",
386        "fields": {
387            "name": "Agnes"
388        }
389    }]"""
390
391try:
392    import yaml
393except ImportError:
394    pass
395else:
396    class YamlSerializerTestCase(SerializersTestBase, TestCase):
397        serializer_name = "yaml"
398        fwd_ref_str = """- fields:
399    headline: Forward references pose no problem
400    pub_date: 2006-06-16 15:00:00
401    categories: [1]
402    author: 1
403  pk: 1
404  model: serializers.article
405- fields:
406    name: Reference
407  pk: 1
408  model: serializers.category
409- fields:
410    name: Agnes
411  pk: 1
412  model: serializers.author"""
413
414        pkless_str = """- fields:
415    name: Reference
416  pk: null
417  model: serializers.category"""
418
419        @staticmethod
420        def _validate_output(serial_str):
421            try:
422                yaml.load(StringIO(serial_str))
423            except Exception:
424                return False
425            else:
426                return True
427
428        @staticmethod
429        def _get_pk_values(serial_str):
430            ret_list = []
431            stream = StringIO(serial_str)
432            for obj_dict in yaml.load(stream):
433                ret_list.append(obj_dict["pk"])
434            return ret_list
435
436        @staticmethod
437        def _get_field_values(serial_str, field_name):
438            ret_list = []
439            stream = StringIO(serial_str)
440            for obj_dict in yaml.load(stream):
441                if "fields" in obj_dict and field_name in obj_dict["fields"]:
442                    field_value = obj_dict["fields"][field_name]
443                    # yaml.load will return non-string objects for some
444                    # of the fields we are interested in, this ensures that
445                    # everything comes back as a string
446                    if isinstance(field_value, basestring):
447                        ret_list.append(field_value)
448                    else:
449                        ret_list.append(str(field_value))
450            return ret_list
451
452    class YamlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
453        serializer_name = "yaml"
454        fwd_ref_str = """- fields:
455    headline: Forward references pose no problem
456    pub_date: 2006-06-16 15:00:00
457    categories: [1]
458    author: 1
459  pk: 1
460  model: serializers.article
461- fields:
462    name: Reference
463  pk: 1
464  model: serializers.category
465- fields:
466    name: Agnes
467  pk: 1
468  model: serializers.author"""