PageRenderTime 42ms CodeModel.GetById 18ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/regressiontests/model_fields/imagefield.py

https://code.google.com/p/mango-py/
Python | 420 lines | 378 code | 15 blank | 27 comment | 8 complexity | c6664304d43876687a0550a56eb403a9 MD5 | raw file
  1import os
  2import shutil
  3
  4from django.core.files import File
  5from django.core.files.base import ContentFile
  6from django.core.files.images import ImageFile
  7from django.test import TestCase
  8
  9from models import Image, Person, PersonWithHeight, PersonWithHeightAndWidth, \
 10        PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile
 11
 12
 13# If PIL available, do these tests.
 14if Image:
 15
 16    from models import temp_storage_dir
 17
 18
 19    class ImageFieldTestMixin(object):
 20        """
 21        Mixin class to provide common functionality to ImageField test classes.
 22        """
 23
 24        # Person model to use for tests.
 25        PersonModel = PersonWithHeightAndWidth
 26        # File class to use for file instances.
 27        File = ImageFile
 28
 29        def setUp(self):
 30            """
 31            Creates a pristine temp directory (or deletes and recreates if it
 32            already exists) that the model uses as its storage directory.
 33
 34            Sets up two ImageFile instances for use in tests.
 35            """
 36            if os.path.exists(temp_storage_dir):
 37                shutil.rmtree(temp_storage_dir)
 38            os.mkdir(temp_storage_dir)
 39
 40            file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png")
 41            self.file1 = self.File(open(file_path1, 'rb'))
 42
 43            file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png")
 44            self.file2 = self.File(open(file_path2, 'rb'))
 45
 46        def tearDown(self):
 47            """
 48            Removes temp directory and all its contents.
 49            """
 50            shutil.rmtree(temp_storage_dir)
 51
 52        def check_dimensions(self, instance, width, height,
 53                             field_name='mugshot'):
 54            """
 55            Asserts that the given width and height values match both the
 56            field's height and width attributes and the height and width fields
 57            (if defined) the image field is caching to.
 58
 59            Note, this method will check for dimension fields named by adding
 60            "_width" or "_height" to the name of the ImageField.  So, the
 61            models used in these tests must have their fields named
 62            accordingly.
 63
 64            By default, we check the field named "mugshot", but this can be
 65            specified by passing the field_name parameter.
 66            """
 67            field = getattr(instance, field_name)
 68            # Check height/width attributes of field.
 69            if width is None and height is None:
 70                self.assertRaises(ValueError, getattr, field, 'width')
 71                self.assertRaises(ValueError, getattr, field, 'height')
 72            else:
 73                self.assertEqual(field.width, width)
 74                self.assertEqual(field.height, height)
 75
 76            # Check height/width fields of model, if defined.
 77            width_field_name = field_name + '_width'
 78            if hasattr(instance, width_field_name):
 79                self.assertEqual(getattr(instance, width_field_name), width)
 80            height_field_name = field_name + '_height'
 81            if hasattr(instance, height_field_name):
 82                self.assertEqual(getattr(instance, height_field_name), height)
 83
 84
 85    class ImageFieldTests(ImageFieldTestMixin, TestCase):
 86        """
 87        Tests for ImageField that don't need to be run with each of the
 88        different test model classes.
 89        """
 90
 91        def test_equal_notequal_hash(self):
 92            """
 93            Bug #9786: Ensure '==' and '!=' work correctly.
 94            Bug #9508: make sure hash() works as expected (equal items must
 95            hash to the same value).
 96            """
 97            # Create two Persons with different mugshots.
 98            p1 = self.PersonModel(name="Joe")
 99            p1.mugshot.save("mug", self.file1)
100            p2 = self.PersonModel(name="Bob")
101            p2.mugshot.save("mug", self.file2)
102            self.assertEqual(p1.mugshot == p2.mugshot, False)
103            self.assertEqual(p1.mugshot != p2.mugshot, True)
104
105            # Test again with an instance fetched from the db.
106            p1_db = self.PersonModel.objects.get(name="Joe")
107            self.assertEqual(p1_db.mugshot == p2.mugshot, False)
108            self.assertEqual(p1_db.mugshot != p2.mugshot, True)
109
110            # Instance from db should match the local instance.
111            self.assertEqual(p1_db.mugshot == p1.mugshot, True)
112            self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
113            self.assertEqual(p1_db.mugshot != p1.mugshot, False)
114
115        def test_instantiate_missing(self):
116            """
117            If the underlying file is unavailable, still create instantiate the
118            object without error.
119            """
120            p = self.PersonModel(name="Joan")
121            p.mugshot.save("shot", self.file1)
122            p = self.PersonModel.objects.get(name="Joan")
123            path = p.mugshot.path
124            shutil.move(path, path + '.moved')
125            p2 = self.PersonModel.objects.get(name="Joan")
126
127        def test_delete_when_missing(self):
128            """
129            Bug #8175: correctly delete an object where the file no longer
130            exists on the file system.
131            """
132            p = self.PersonModel(name="Fred")
133            p.mugshot.save("shot", self.file1)
134            os.remove(p.mugshot.path)
135            p.delete()
136
137        def test_size_method(self):
138            """
139            Bug #8534: FileField.size should not leave the file open.
140            """
141            p = self.PersonModel(name="Joan")
142            p.mugshot.save("shot", self.file1)
143
144            # Get a "clean" model instance
145            p = self.PersonModel.objects.get(name="Joan")
146            # It won't have an opened file.
147            self.assertEqual(p.mugshot.closed, True)
148
149            # After asking for the size, the file should still be closed.
150            _ = p.mugshot.size
151            self.assertEqual(p.mugshot.closed, True)
152
153        def test_pickle(self):
154            """
155            Tests that ImageField can be pickled, unpickled, and that the
156            image of the unpickled version is the same as the original.
157            """
158            import pickle
159
160            p = Person(name="Joe")
161            p.mugshot.save("mug", self.file1)
162            dump = pickle.dumps(p)
163
164            p2 = Person(name="Bob")
165            p2.mugshot = self.file1
166
167            loaded_p = pickle.loads(dump)
168            self.assertEqual(p.mugshot, loaded_p.mugshot)
169
170
171    class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
172        """
173        Tests behavior of an ImageField and its dimensions fields.
174        """
175
176        def test_constructor(self):
177            """
178            Tests assigning an image field through the model's constructor.
179            """
180            p = self.PersonModel(name='Joe', mugshot=self.file1)
181            self.check_dimensions(p, 4, 8)
182            p.save()
183            self.check_dimensions(p, 4, 8)
184
185        def test_image_after_constructor(self):
186            """
187            Tests behavior when image is not passed in constructor.
188            """
189            p = self.PersonModel(name='Joe')
190            # TestImageField value will default to being an instance of its
191            # attr_class, a  TestImageFieldFile, with name == None, which will
192            # cause it to evaluate as False.
193            self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
194            self.assertEqual(bool(p.mugshot), False)
195
196            # Test setting a fresh created model instance.
197            p = self.PersonModel(name='Joe')
198            p.mugshot = self.file1
199            self.check_dimensions(p, 4, 8)
200
201        def test_create(self):
202            """
203            Tests assigning an image in Manager.create().
204            """
205            p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1)
206            self.check_dimensions(p, 4, 8)
207
208        def test_default_value(self):
209            """
210            Tests that the default value for an ImageField is an instance of
211            the field's attr_class (TestImageFieldFile in this case) with no
212            name (name set to None).
213            """
214            p = self.PersonModel()
215            self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
216            self.assertEqual(bool(p.mugshot), False)
217
218        def test_assignment_to_None(self):
219            """
220            Tests that assigning ImageField to None clears dimensions.
221            """
222            p = self.PersonModel(name='Joe', mugshot=self.file1)
223            self.check_dimensions(p, 4, 8)
224
225            # If image assigned to None, dimension fields should be cleared.
226            p.mugshot = None
227            self.check_dimensions(p, None, None)
228
229            p.mugshot = self.file2
230            self.check_dimensions(p, 8, 4)
231
232        def test_field_save_and_delete_methods(self):
233            """
234            Tests assignment using the field's save method and deletion using
235            the field's delete method.
236            """
237            p = self.PersonModel(name='Joe')
238            p.mugshot.save("mug", self.file1)
239            self.check_dimensions(p, 4, 8)
240
241            # A new file should update dimensions.
242            p.mugshot.save("mug", self.file2)
243            self.check_dimensions(p, 8, 4)
244
245            # Field and dimensions should be cleared after a delete.
246            p.mugshot.delete(save=False)
247            self.assertEqual(p.mugshot, None)
248            self.check_dimensions(p, None, None)
249
250        def test_dimensions(self):
251            """
252            Checks that dimensions are updated correctly in various situations.
253            """
254            p = self.PersonModel(name='Joe')
255
256            # Dimensions should get set if file is saved.
257            p.mugshot.save("mug", self.file1)
258            self.check_dimensions(p, 4, 8)
259
260            # Test dimensions after fetching from database.
261            p = self.PersonModel.objects.get(name='Joe')
262            # Bug 11084: Dimensions should not get recalculated if file is
263            # coming from the database.  We test this by checking if the file
264            # was opened.
265            self.assertEqual(p.mugshot.was_opened, False)
266            self.check_dimensions(p, 4, 8)
267            # After checking dimensions on the image field, the file will have
268            # opened.
269            self.assertEqual(p.mugshot.was_opened, True)
270            # Dimensions should now be cached, and if we reset was_opened and
271            # check dimensions again, the file should not have opened.
272            p.mugshot.was_opened = False
273            self.check_dimensions(p, 4, 8)
274            self.assertEqual(p.mugshot.was_opened, False)
275
276            # If we assign a new image to the instance, the dimensions should
277            # update.
278            p.mugshot = self.file2
279            self.check_dimensions(p, 8, 4)
280            # Dimensions were recalculated, and hence file should have opened.
281            self.assertEqual(p.mugshot.was_opened, True)
282
283
284    class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
285        """
286        Tests behavior of an ImageField with no dimension fields.
287        """
288
289        PersonModel = Person
290
291
292    class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
293        """
294        Tests behavior of an ImageField with one dimensions field.
295        """
296
297        PersonModel = PersonWithHeight
298
299
300    class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
301        """
302        Tests behavior of an ImageField where the dimensions fields are
303        defined before the ImageField.
304        """
305
306        PersonModel = PersonDimensionsFirst
307
308
309    class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
310        """
311        Tests behavior of an ImageField when assigning it a File instance
312        rather than an ImageFile instance.
313        """
314
315        PersonModel = PersonDimensionsFirst
316        File = File
317
318
319    class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
320        """
321        Tests a model with two ImageFields.
322        """
323
324        PersonModel = PersonTwoImages
325
326        def test_constructor(self):
327            p = self.PersonModel(mugshot=self.file1, headshot=self.file2)
328            self.check_dimensions(p, 4, 8, 'mugshot')
329            self.check_dimensions(p, 8, 4, 'headshot')
330            p.save()
331            self.check_dimensions(p, 4, 8, 'mugshot')
332            self.check_dimensions(p, 8, 4, 'headshot')
333
334        def test_create(self):
335            p = self.PersonModel.objects.create(mugshot=self.file1,
336                                                headshot=self.file2)
337            self.check_dimensions(p, 4, 8)
338            self.check_dimensions(p, 8, 4, 'headshot')
339
340        def test_assignment(self):
341            p = self.PersonModel()
342            self.check_dimensions(p, None, None, 'mugshot')
343            self.check_dimensions(p, None, None, 'headshot')
344
345            p.mugshot = self.file1
346            self.check_dimensions(p, 4, 8, 'mugshot')
347            self.check_dimensions(p, None, None, 'headshot')
348            p.headshot = self.file2
349            self.check_dimensions(p, 4, 8, 'mugshot')
350            self.check_dimensions(p, 8, 4, 'headshot')
351
352            # Clear the ImageFields one at a time.
353            p.mugshot = None
354            self.check_dimensions(p, None, None, 'mugshot')
355            self.check_dimensions(p, 8, 4, 'headshot')
356            p.headshot = None
357            self.check_dimensions(p, None, None, 'mugshot')
358            self.check_dimensions(p, None, None, 'headshot')
359
360        def test_field_save_and_delete_methods(self):
361            p = self.PersonModel(name='Joe')
362            p.mugshot.save("mug", self.file1)
363            self.check_dimensions(p, 4, 8, 'mugshot')
364            self.check_dimensions(p, None, None, 'headshot')
365            p.headshot.save("head", self.file2)
366            self.check_dimensions(p, 4, 8, 'mugshot')
367            self.check_dimensions(p, 8, 4, 'headshot')
368
369            # We can use save=True when deleting the image field with null=True
370            # dimension fields and the other field has an image.
371            p.headshot.delete(save=True)
372            self.check_dimensions(p, 4, 8, 'mugshot')
373            self.check_dimensions(p, None, None, 'headshot')
374            p.mugshot.delete(save=False)
375            self.check_dimensions(p, None, None, 'mugshot')
376            self.check_dimensions(p, None, None, 'headshot')
377
378        def test_dimensions(self):
379            """
380            Checks that dimensions are updated correctly in various situations.
381            """
382            p = self.PersonModel(name='Joe')
383
384            # Dimensions should get set for the saved file.
385            p.mugshot.save("mug", self.file1)
386            p.headshot.save("head", self.file2)
387            self.check_dimensions(p, 4, 8, 'mugshot')
388            self.check_dimensions(p, 8, 4, 'headshot')
389
390            # Test dimensions after fetching from database.
391            p = self.PersonModel.objects.get(name='Joe')
392            # Bug 11084: Dimensions should not get recalculated if file is
393            # coming from the database.  We test this by checking if the file
394            # was opened.
395            self.assertEqual(p.mugshot.was_opened, False)
396            self.assertEqual(p.headshot.was_opened, False)
397            self.check_dimensions(p, 4, 8,'mugshot')
398            self.check_dimensions(p, 8, 4, 'headshot')
399            # After checking dimensions on the image fields, the files will
400            # have been opened.
401            self.assertEqual(p.mugshot.was_opened, True)
402            self.assertEqual(p.headshot.was_opened, True)
403            # Dimensions should now be cached, and if we reset was_opened and
404            # check dimensions again, the file should not have opened.
405            p.mugshot.was_opened = False
406            p.headshot.was_opened = False
407            self.check_dimensions(p, 4, 8,'mugshot')
408            self.check_dimensions(p, 8, 4, 'headshot')
409            self.assertEqual(p.mugshot.was_opened, False)
410            self.assertEqual(p.headshot.was_opened, False)
411
412            # If we assign a new image to the instance, the dimensions should
413            # update.
414            p.mugshot = self.file2
415            p.headshot = self.file1
416            self.check_dimensions(p, 8, 4, 'mugshot')
417            self.check_dimensions(p, 4, 8, 'headshot')
418            # Dimensions were recalculated, and hence file should have opened.
419            self.assertEqual(p.mugshot.was_opened, True)
420            self.assertEqual(p.headshot.was_opened, True)