~mhall119/ubuntu-api-website/content-editing

« back to all changes in this revision

Viewing changes to developer_network/rest_framework/tests/test_serializer_nested.py

  • Committer: Michael Hall
  • Date: 2013-12-19 21:14:27 UTC
  • Revision ID: mhall119@ubuntu.com-20131219211427-3s5a6tmr7yx69rbv
Add REST service with token authentication

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Tests to cover nested serializers.
 
3
 
 
4
Doesn't cover model serializers.
 
5
"""
 
6
from __future__ import unicode_literals
 
7
from django.test import TestCase
 
8
from rest_framework import serializers
 
9
 
 
10
 
 
11
class WritableNestedSerializerBasicTests(TestCase):
 
12
    """
 
13
    Tests for deserializing nested entities.
 
14
    Basic tests that use serializers that simply restore to dicts.
 
15
    """
 
16
 
 
17
    def setUp(self):
 
18
        class TrackSerializer(serializers.Serializer):
 
19
            order = serializers.IntegerField()
 
20
            title = serializers.CharField(max_length=100)
 
21
            duration = serializers.IntegerField()
 
22
 
 
23
        class AlbumSerializer(serializers.Serializer):
 
24
            album_name = serializers.CharField(max_length=100)
 
25
            artist = serializers.CharField(max_length=100)
 
26
            tracks = TrackSerializer(many=True)
 
27
 
 
28
        self.AlbumSerializer = AlbumSerializer
 
29
 
 
30
    def test_nested_validation_success(self):
 
31
        """
 
32
        Correct nested serialization should return the input data.
 
33
        """
 
34
 
 
35
        data = {
 
36
            'album_name': 'Discovery',
 
37
            'artist': 'Daft Punk',
 
38
            'tracks': [
 
39
                {'order': 1, 'title': 'One More Time', 'duration': 235},
 
40
                {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
 
41
                {'order': 3, 'title': 'Digital Love', 'duration': 239}
 
42
            ]
 
43
        }
 
44
 
 
45
        serializer = self.AlbumSerializer(data=data)
 
46
        self.assertEqual(serializer.is_valid(), True)
 
47
        self.assertEqual(serializer.object, data)
 
48
 
 
49
    def test_nested_validation_error(self):
 
50
        """
 
51
        Incorrect nested serialization should return appropriate error data.
 
52
        """
 
53
 
 
54
        data = {
 
55
            'album_name': 'Discovery',
 
56
            'artist': 'Daft Punk',
 
57
            'tracks': [
 
58
                {'order': 1, 'title': 'One More Time', 'duration': 235},
 
59
                {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
 
60
                {'order': 3, 'title': 'Digital Love', 'duration': 'foobar'}
 
61
            ]
 
62
        }
 
63
        expected_errors = {
 
64
            'tracks': [
 
65
                {},
 
66
                {},
 
67
                {'duration': ['Enter a whole number.']}
 
68
            ]
 
69
        }
 
70
 
 
71
        serializer = self.AlbumSerializer(data=data)
 
72
        self.assertEqual(serializer.is_valid(), False)
 
73
        self.assertEqual(serializer.errors, expected_errors)
 
74
 
 
75
    def test_many_nested_validation_error(self):
 
76
        """
 
77
        Incorrect nested serialization should return appropriate error data
 
78
        when multiple entities are being deserialized.
 
79
        """
 
80
 
 
81
        data = [
 
82
            {
 
83
                'album_name': 'Russian Red',
 
84
                'artist': 'I Love Your Glasses',
 
85
                'tracks': [
 
86
                    {'order': 1, 'title': 'Cigarettes', 'duration': 121},
 
87
                    {'order': 2, 'title': 'No Past Land', 'duration': 198},
 
88
                    {'order': 3, 'title': 'They Don\'t Believe', 'duration': 191}
 
89
                ]
 
90
            },
 
91
            {
 
92
                'album_name': 'Discovery',
 
93
                'artist': 'Daft Punk',
 
94
                'tracks': [
 
95
                    {'order': 1, 'title': 'One More Time', 'duration': 235},
 
96
                    {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
 
97
                    {'order': 3, 'title': 'Digital Love', 'duration': 'foobar'}
 
98
                ]
 
99
            }
 
100
        ]
 
101
        expected_errors = [
 
102
            {},
 
103
            {
 
104
                'tracks': [
 
105
                    {},
 
106
                    {},
 
107
                    {'duration': ['Enter a whole number.']}
 
108
                ]
 
109
            }
 
110
        ]
 
111
 
 
112
        serializer = self.AlbumSerializer(data=data, many=True)
 
113
        self.assertEqual(serializer.is_valid(), False)
 
114
        self.assertEqual(serializer.errors, expected_errors)
 
115
 
 
116
 
 
117
class WritableNestedSerializerObjectTests(TestCase):
 
118
    """
 
119
    Tests for deserializing nested entities.
 
120
    These tests use serializers that restore to concrete objects.
 
121
    """
 
122
 
 
123
    def setUp(self):
 
124
        # Couple of concrete objects that we're going to deserialize into
 
125
        class Track(object):
 
126
            def __init__(self, order, title, duration):
 
127
                self.order, self.title, self.duration = order, title, duration
 
128
 
 
129
            def __eq__(self, other):
 
130
                return (
 
131
                    self.order == other.order and
 
132
                    self.title == other.title and
 
133
                    self.duration == other.duration
 
134
                )
 
135
 
 
136
        class Album(object):
 
137
            def __init__(self, album_name, artist, tracks):
 
138
                self.album_name, self.artist, self.tracks = album_name, artist, tracks
 
139
 
 
140
            def __eq__(self, other):
 
141
                return (
 
142
                    self.album_name == other.album_name and
 
143
                    self.artist == other.artist and
 
144
                    self.tracks == other.tracks
 
145
                )
 
146
 
 
147
        # And their corresponding serializers
 
148
        class TrackSerializer(serializers.Serializer):
 
149
            order = serializers.IntegerField()
 
150
            title = serializers.CharField(max_length=100)
 
151
            duration = serializers.IntegerField()
 
152
 
 
153
            def restore_object(self, attrs, instance=None):
 
154
                return Track(attrs['order'], attrs['title'], attrs['duration'])
 
155
 
 
156
        class AlbumSerializer(serializers.Serializer):
 
157
            album_name = serializers.CharField(max_length=100)
 
158
            artist = serializers.CharField(max_length=100)
 
159
            tracks = TrackSerializer(many=True)
 
160
 
 
161
            def restore_object(self, attrs, instance=None):
 
162
                return Album(attrs['album_name'], attrs['artist'], attrs['tracks'])
 
163
 
 
164
        self.Album, self.Track = Album, Track
 
165
        self.AlbumSerializer = AlbumSerializer
 
166
 
 
167
    def test_nested_validation_success(self):
 
168
        """
 
169
        Correct nested serialization should return a restored object
 
170
        that corresponds to the input data.
 
171
        """
 
172
 
 
173
        data = {
 
174
            'album_name': 'Discovery',
 
175
            'artist': 'Daft Punk',
 
176
            'tracks': [
 
177
                {'order': 1, 'title': 'One More Time', 'duration': 235},
 
178
                {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
 
179
                {'order': 3, 'title': 'Digital Love', 'duration': 239}
 
180
            ]
 
181
        }
 
182
        expected_object = self.Album(
 
183
            album_name='Discovery',
 
184
            artist='Daft Punk',
 
185
            tracks=[
 
186
                self.Track(order=1, title='One More Time', duration=235),
 
187
                self.Track(order=2, title='Aerodynamic', duration=184),
 
188
                self.Track(order=3, title='Digital Love', duration=239),
 
189
            ]
 
190
        )
 
191
 
 
192
        serializer = self.AlbumSerializer(data=data)
 
193
        self.assertEqual(serializer.is_valid(), True)
 
194
        self.assertEqual(serializer.object, expected_object)
 
195
 
 
196
    def test_many_nested_validation_success(self):
 
197
        """
 
198
        Correct nested serialization should return multiple restored objects
 
199
        that corresponds to the input data when multiple objects are
 
200
        being deserialized.
 
201
        """
 
202
 
 
203
        data = [
 
204
            {
 
205
                'album_name': 'Russian Red',
 
206
                'artist': 'I Love Your Glasses',
 
207
                'tracks': [
 
208
                    {'order': 1, 'title': 'Cigarettes', 'duration': 121},
 
209
                    {'order': 2, 'title': 'No Past Land', 'duration': 198},
 
210
                    {'order': 3, 'title': 'They Don\'t Believe', 'duration': 191}
 
211
                ]
 
212
            },
 
213
            {
 
214
                'album_name': 'Discovery',
 
215
                'artist': 'Daft Punk',
 
216
                'tracks': [
 
217
                    {'order': 1, 'title': 'One More Time', 'duration': 235},
 
218
                    {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
 
219
                    {'order': 3, 'title': 'Digital Love', 'duration': 239}
 
220
                ]
 
221
            }
 
222
        ]
 
223
        expected_object = [
 
224
            self.Album(
 
225
                album_name='Russian Red',
 
226
                artist='I Love Your Glasses',
 
227
                tracks=[
 
228
                    self.Track(order=1, title='Cigarettes', duration=121),
 
229
                    self.Track(order=2, title='No Past Land', duration=198),
 
230
                    self.Track(order=3, title='They Don\'t Believe', duration=191),
 
231
                ]
 
232
            ),
 
233
            self.Album(
 
234
                album_name='Discovery',
 
235
                artist='Daft Punk',
 
236
                tracks=[
 
237
                    self.Track(order=1, title='One More Time', duration=235),
 
238
                    self.Track(order=2, title='Aerodynamic', duration=184),
 
239
                    self.Track(order=3, title='Digital Love', duration=239),
 
240
                ]
 
241
            )
 
242
        ]
 
243
 
 
244
        serializer = self.AlbumSerializer(data=data, many=True)
 
245
        self.assertEqual(serializer.is_valid(), True)
 
246
        self.assertEqual(serializer.object, expected_object)
 
247
 
 
248
 
 
249
class ForeignKeyNestedSerializerUpdateTests(TestCase):
 
250
    def setUp(self):
 
251
        class Artist(object):
 
252
            def __init__(self, name):
 
253
                self.name = name
 
254
 
 
255
            def __eq__(self, other):
 
256
                return self.name == other.name
 
257
 
 
258
        class Album(object):
 
259
            def __init__(self, name, artist):
 
260
                self.name, self.artist = name, artist
 
261
 
 
262
            def __eq__(self, other):
 
263
                return self.name == other.name and self.artist == other.artist
 
264
 
 
265
        class ArtistSerializer(serializers.Serializer):
 
266
            name = serializers.CharField()
 
267
 
 
268
            def restore_object(self, attrs, instance=None):
 
269
                if instance:
 
270
                    instance.name = attrs['name']
 
271
                else:
 
272
                    instance = Artist(attrs['name'])
 
273
                return instance
 
274
 
 
275
        class AlbumSerializer(serializers.Serializer):
 
276
            name = serializers.CharField()
 
277
            by = ArtistSerializer(source='artist')
 
278
 
 
279
            def restore_object(self, attrs, instance=None):
 
280
                if instance:
 
281
                    instance.name = attrs['name']
 
282
                    instance.artist = attrs['artist']
 
283
                else:
 
284
                    instance = Album(attrs['name'], attrs['artist'])
 
285
                return instance
 
286
 
 
287
        self.Artist = Artist
 
288
        self.Album = Album
 
289
        self.AlbumSerializer = AlbumSerializer
 
290
 
 
291
    def test_create_via_foreign_key_with_source(self):
 
292
        """
 
293
        Check that we can both *create* and *update* into objects across
 
294
        ForeignKeys that have a `source` specified.
 
295
        Regression test for #1170
 
296
        """
 
297
        data = {
 
298
            'name': 'Discovery',
 
299
            'by': {'name': 'Daft Punk'},
 
300
        }
 
301
 
 
302
        expected = self.Album(artist=self.Artist('Daft Punk'), name='Discovery')
 
303
 
 
304
        # create
 
305
        serializer = self.AlbumSerializer(data=data)
 
306
        self.assertEqual(serializer.is_valid(), True)
 
307
        self.assertEqual(serializer.object, expected)
 
308
 
 
309
        # update
 
310
        original = self.Album(artist=self.Artist('The Bats'), name='Free All the Monsters')
 
311
        serializer = self.AlbumSerializer(instance=original, data=data)
 
312
        self.assertEqual(serializer.is_valid(), True)
 
313
        self.assertEqual(serializer.object, expected)