Преглед на файлове

Used skipIf decorator to skip image tests when PIL is not available

Claude Paroz преди 12 години
родител
ревизия
86eb606b88
променени са 2 файла, в които са добавени 404 реда и са изтрити 394 реда
  1. 400 388
      tests/regressiontests/model_fields/imagefield.py
  2. 4 6
      tests/regressiontests/model_fields/tests.py

+ 400 - 388
tests/regressiontests/model_fields/imagefield.py

@@ -6,416 +6,428 @@ import shutil
 from django.core.files import File
 from django.core.files.images import ImageFile
 from django.test import TestCase
+from django.utils.unittest import skipIf
 
-from .models import (Image, Person, PersonWithHeight, PersonWithHeightAndWidth,
-    PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile)
+from .models import Image
 
-
-# If PIL available, do these tests.
 if Image:
-
+    from .models import (Person, PersonWithHeight, PersonWithHeightAndWidth,
+        PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile)
     from .models import temp_storage_dir
+else:
+    # PIL not available, create dummy classes (tests will be skipped anyway)
+    class Person():
+        pass
+    PersonWithHeight = PersonWithHeightAndWidth = PersonDimensionsFirst = Person
+    PersonTwoImages = Person
+
 
+class ImageFieldTestMixin(object):
+    """
+    Mixin class to provide common functionality to ImageField test classes.
+    """
 
-    class ImageFieldTestMixin(object):
+    # Person model to use for tests.
+    PersonModel = PersonWithHeightAndWidth
+    # File class to use for file instances.
+    File = ImageFile
+
+    def setUp(self):
         """
-        Mixin class to provide common functionality to ImageField test classes.
+        Creates a pristine temp directory (or deletes and recreates if it
+        already exists) that the model uses as its storage directory.
+
+        Sets up two ImageFile instances for use in tests.
         """
+        if os.path.exists(temp_storage_dir):
+            shutil.rmtree(temp_storage_dir)
+        os.mkdir(temp_storage_dir)
 
-        # Person model to use for tests.
-        PersonModel = PersonWithHeightAndWidth
-        # File class to use for file instances.
-        File = ImageFile
+        file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png")
+        self.file1 = self.File(open(file_path1, 'rb'))
 
-        def setUp(self):
-            """
-            Creates a pristine temp directory (or deletes and recreates if it
-            already exists) that the model uses as its storage directory.
+        file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png")
+        self.file2 = self.File(open(file_path2, 'rb'))
 
-            Sets up two ImageFile instances for use in tests.
-            """
-            if os.path.exists(temp_storage_dir):
-                shutil.rmtree(temp_storage_dir)
-            os.mkdir(temp_storage_dir)
+    def tearDown(self):
+        """
+        Removes temp directory and all its contents.
+        """
+        shutil.rmtree(temp_storage_dir)
 
-            file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png")
-            self.file1 = self.File(open(file_path1, 'rb'))
+    def check_dimensions(self, instance, width, height,
+                         field_name='mugshot'):
+        """
+        Asserts that the given width and height values match both the
+        field's height and width attributes and the height and width fields
+        (if defined) the image field is caching to.
 
-            file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png")
-            self.file2 = self.File(open(file_path2, 'rb'))
+        Note, this method will check for dimension fields named by adding
+        "_width" or "_height" to the name of the ImageField.  So, the
+        models used in these tests must have their fields named
+        accordingly.
 
-        def tearDown(self):
-            """
-            Removes temp directory and all its contents.
-            """
-            shutil.rmtree(temp_storage_dir)
+        By default, we check the field named "mugshot", but this can be
+        specified by passing the field_name parameter.
+        """
+        field = getattr(instance, field_name)
+        # Check height/width attributes of field.
+        if width is None and height is None:
+            self.assertRaises(ValueError, getattr, field, 'width')
+            self.assertRaises(ValueError, getattr, field, 'height')
+        else:
+            self.assertEqual(field.width, width)
+            self.assertEqual(field.height, height)
+
+        # Check height/width fields of model, if defined.
+        width_field_name = field_name + '_width'
+        if hasattr(instance, width_field_name):
+            self.assertEqual(getattr(instance, width_field_name), width)
+        height_field_name = field_name + '_height'
+        if hasattr(instance, height_field_name):
+            self.assertEqual(getattr(instance, height_field_name), height)
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldTests(ImageFieldTestMixin, TestCase):
+    """
+    Tests for ImageField that don't need to be run with each of the
+    different test model classes.
+    """
+
+    def test_equal_notequal_hash(self):
+        """
+        Bug #9786: Ensure '==' and '!=' work correctly.
+        Bug #9508: make sure hash() works as expected (equal items must
+        hash to the same value).
+        """
+        # Create two Persons with different mugshots.
+        p1 = self.PersonModel(name="Joe")
+        p1.mugshot.save("mug", self.file1)
+        p2 = self.PersonModel(name="Bob")
+        p2.mugshot.save("mug", self.file2)
+        self.assertEqual(p1.mugshot == p2.mugshot, False)
+        self.assertEqual(p1.mugshot != p2.mugshot, True)
+
+        # Test again with an instance fetched from the db.
+        p1_db = self.PersonModel.objects.get(name="Joe")
+        self.assertEqual(p1_db.mugshot == p2.mugshot, False)
+        self.assertEqual(p1_db.mugshot != p2.mugshot, True)
+
+        # Instance from db should match the local instance.
+        self.assertEqual(p1_db.mugshot == p1.mugshot, True)
+        self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
+        self.assertEqual(p1_db.mugshot != p1.mugshot, False)
+
+    def test_instantiate_missing(self):
+        """
+        If the underlying file is unavailable, still create instantiate the
+        object without error.
+        """
+        p = self.PersonModel(name="Joan")
+        p.mugshot.save("shot", self.file1)
+        p = self.PersonModel.objects.get(name="Joan")
+        path = p.mugshot.path
+        shutil.move(path, path + '.moved')
+        p2 = self.PersonModel.objects.get(name="Joan")
+
+    def test_delete_when_missing(self):
+        """
+        Bug #8175: correctly delete an object where the file no longer
+        exists on the file system.
+        """
+        p = self.PersonModel(name="Fred")
+        p.mugshot.save("shot", self.file1)
+        os.remove(p.mugshot.path)
+        p.delete()
 
-        def check_dimensions(self, instance, width, height,
-                             field_name='mugshot'):
-            """
-            Asserts that the given width and height values match both the
-            field's height and width attributes and the height and width fields
-            (if defined) the image field is caching to.
-
-            Note, this method will check for dimension fields named by adding
-            "_width" or "_height" to the name of the ImageField.  So, the
-            models used in these tests must have their fields named
-            accordingly.
-
-            By default, we check the field named "mugshot", but this can be
-            specified by passing the field_name parameter.
-            """
-            field = getattr(instance, field_name)
-            # Check height/width attributes of field.
-            if width is None and height is None:
-                self.assertRaises(ValueError, getattr, field, 'width')
-                self.assertRaises(ValueError, getattr, field, 'height')
-            else:
-                self.assertEqual(field.width, width)
-                self.assertEqual(field.height, height)
-
-            # Check height/width fields of model, if defined.
-            width_field_name = field_name + '_width'
-            if hasattr(instance, width_field_name):
-                self.assertEqual(getattr(instance, width_field_name), width)
-            height_field_name = field_name + '_height'
-            if hasattr(instance, height_field_name):
-                self.assertEqual(getattr(instance, height_field_name), height)
-
-
-    class ImageFieldTests(ImageFieldTestMixin, TestCase):
-        """
-        Tests for ImageField that don't need to be run with each of the
-        different test model classes.
-        """
-
-        def test_equal_notequal_hash(self):
-            """
-            Bug #9786: Ensure '==' and '!=' work correctly.
-            Bug #9508: make sure hash() works as expected (equal items must
-            hash to the same value).
-            """
-            # Create two Persons with different mugshots.
-            p1 = self.PersonModel(name="Joe")
-            p1.mugshot.save("mug", self.file1)
-            p2 = self.PersonModel(name="Bob")
-            p2.mugshot.save("mug", self.file2)
-            self.assertEqual(p1.mugshot == p2.mugshot, False)
-            self.assertEqual(p1.mugshot != p2.mugshot, True)
-
-            # Test again with an instance fetched from the db.
-            p1_db = self.PersonModel.objects.get(name="Joe")
-            self.assertEqual(p1_db.mugshot == p2.mugshot, False)
-            self.assertEqual(p1_db.mugshot != p2.mugshot, True)
-
-            # Instance from db should match the local instance.
-            self.assertEqual(p1_db.mugshot == p1.mugshot, True)
-            self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
-            self.assertEqual(p1_db.mugshot != p1.mugshot, False)
-
-        def test_instantiate_missing(self):
-            """
-            If the underlying file is unavailable, still create instantiate the
-            object without error.
-            """
-            p = self.PersonModel(name="Joan")
-            p.mugshot.save("shot", self.file1)
-            p = self.PersonModel.objects.get(name="Joan")
-            path = p.mugshot.path
-            shutil.move(path, path + '.moved')
-            p2 = self.PersonModel.objects.get(name="Joan")
-
-        def test_delete_when_missing(self):
-            """
-            Bug #8175: correctly delete an object where the file no longer
-            exists on the file system.
-            """
-            p = self.PersonModel(name="Fred")
-            p.mugshot.save("shot", self.file1)
-            os.remove(p.mugshot.path)
-            p.delete()
-
-        def test_size_method(self):
-            """
-            Bug #8534: FileField.size should not leave the file open.
-            """
-            p = self.PersonModel(name="Joan")
-            p.mugshot.save("shot", self.file1)
-
-            # Get a "clean" model instance
-            p = self.PersonModel.objects.get(name="Joan")
-            # It won't have an opened file.
-            self.assertEqual(p.mugshot.closed, True)
-
-            # After asking for the size, the file should still be closed.
-            _ = p.mugshot.size
-            self.assertEqual(p.mugshot.closed, True)
-
-        def test_pickle(self):
-            """
-            Tests that ImageField can be pickled, unpickled, and that the
-            image of the unpickled version is the same as the original.
-            """
-            import pickle
-
-            p = Person(name="Joe")
-            p.mugshot.save("mug", self.file1)
-            dump = pickle.dumps(p)
-
-            p2 = Person(name="Bob")
-            p2.mugshot = self.file1
-
-            loaded_p = pickle.loads(dump)
-            self.assertEqual(p.mugshot, loaded_p.mugshot)
-
-
-    class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
-        """
-        Tests behavior of an ImageField and its dimensions fields.
-        """
-
-        def test_constructor(self):
-            """
-            Tests assigning an image field through the model's constructor.
-            """
-            p = self.PersonModel(name='Joe', mugshot=self.file1)
-            self.check_dimensions(p, 4, 8)
-            p.save()
-            self.check_dimensions(p, 4, 8)
-
-        def test_image_after_constructor(self):
-            """
-            Tests behavior when image is not passed in constructor.
-            """
-            p = self.PersonModel(name='Joe')
-            # TestImageField value will default to being an instance of its
-            # attr_class, a  TestImageFieldFile, with name == None, which will
-            # cause it to evaluate as False.
-            self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
-            self.assertEqual(bool(p.mugshot), False)
-
-            # Test setting a fresh created model instance.
-            p = self.PersonModel(name='Joe')
-            p.mugshot = self.file1
-            self.check_dimensions(p, 4, 8)
-
-        def test_create(self):
-            """
-            Tests assigning an image in Manager.create().
-            """
-            p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1)
-            self.check_dimensions(p, 4, 8)
-
-        def test_default_value(self):
-            """
-            Tests that the default value for an ImageField is an instance of
-            the field's attr_class (TestImageFieldFile in this case) with no
-            name (name set to None).
-            """
-            p = self.PersonModel()
-            self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
-            self.assertEqual(bool(p.mugshot), False)
-
-        def test_assignment_to_None(self):
-            """
-            Tests that assigning ImageField to None clears dimensions.
-            """
-            p = self.PersonModel(name='Joe', mugshot=self.file1)
-            self.check_dimensions(p, 4, 8)
+    def test_size_method(self):
+        """
+        Bug #8534: FileField.size should not leave the file open.
+        """
+        p = self.PersonModel(name="Joan")
+        p.mugshot.save("shot", self.file1)
 
-            # If image assigned to None, dimension fields should be cleared.
-            p.mugshot = None
-            self.check_dimensions(p, None, None)
+        # Get a "clean" model instance
+        p = self.PersonModel.objects.get(name="Joan")
+        # It won't have an opened file.
+        self.assertEqual(p.mugshot.closed, True)
 
-            p.mugshot = self.file2
-            self.check_dimensions(p, 8, 4)
+        # After asking for the size, the file should still be closed.
+        _ = p.mugshot.size
+        self.assertEqual(p.mugshot.closed, True)
 
-        def test_field_save_and_delete_methods(self):
-            """
-            Tests assignment using the field's save method and deletion using
-            the field's delete method.
-            """
-            p = self.PersonModel(name='Joe')
-            p.mugshot.save("mug", self.file1)
-            self.check_dimensions(p, 4, 8)
+    def test_pickle(self):
+        """
+        Tests that ImageField can be pickled, unpickled, and that the
+        image of the unpickled version is the same as the original.
+        """
+        import pickle
 
-            # A new file should update dimensions.
-            p.mugshot.save("mug", self.file2)
-            self.check_dimensions(p, 8, 4)
+        p = Person(name="Joe")
+        p.mugshot.save("mug", self.file1)
+        dump = pickle.dumps(p)
 
-            # Field and dimensions should be cleared after a delete.
-            p.mugshot.delete(save=False)
-            self.assertEqual(p.mugshot, None)
-            self.check_dimensions(p, None, None)
+        p2 = Person(name="Bob")
+        p2.mugshot = self.file1
 
-        def test_dimensions(self):
-            """
-            Checks that dimensions are updated correctly in various situations.
-            """
-            p = self.PersonModel(name='Joe')
+        loaded_p = pickle.loads(dump)
+        self.assertEqual(p.mugshot, loaded_p.mugshot)
 
-            # Dimensions should get set if file is saved.
-            p.mugshot.save("mug", self.file1)
-            self.check_dimensions(p, 4, 8)
 
-            # Test dimensions after fetching from database.
-            p = self.PersonModel.objects.get(name='Joe')
-            # Bug 11084: Dimensions should not get recalculated if file is
-            # coming from the database.  We test this by checking if the file
-            # was opened.
-            self.assertEqual(p.mugshot.was_opened, False)
-            self.check_dimensions(p, 4, 8)
-            # After checking dimensions on the image field, the file will have
-            # opened.
-            self.assertEqual(p.mugshot.was_opened, True)
-            # Dimensions should now be cached, and if we reset was_opened and
-            # check dimensions again, the file should not have opened.
-            p.mugshot.was_opened = False
-            self.check_dimensions(p, 4, 8)
-            self.assertEqual(p.mugshot.was_opened, False)
-
-            # If we assign a new image to the instance, the dimensions should
-            # update.
-            p.mugshot = self.file2
-            self.check_dimensions(p, 8, 4)
-            # Dimensions were recalculated, and hence file should have opened.
-            self.assertEqual(p.mugshot.was_opened, True)
-
-
-    class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
-        """
-        Tests behavior of an ImageField with no dimension fields.
-        """
-
-        PersonModel = Person
-
-
-    class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
-        """
-        Tests behavior of an ImageField with one dimensions field.
-        """
-
-        PersonModel = PersonWithHeight
-
-
-    class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
-        """
-        Tests behavior of an ImageField where the dimensions fields are
-        defined before the ImageField.
-        """
-
-        PersonModel = PersonDimensionsFirst
-
-
-    class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
-        """
-        Tests behavior of an ImageField when assigning it a File instance
-        rather than an ImageFile instance.
-        """
-
-        PersonModel = PersonDimensionsFirst
-        File = File
-
-
-    class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
-        """
-        Tests a model with two ImageFields.
-        """
-
-        PersonModel = PersonTwoImages
-
-        def test_constructor(self):
-            p = self.PersonModel(mugshot=self.file1, headshot=self.file2)
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-            p.save()
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-
-        def test_create(self):
-            p = self.PersonModel.objects.create(mugshot=self.file1,
-                                                headshot=self.file2)
-            self.check_dimensions(p, 4, 8)
-            self.check_dimensions(p, 8, 4, 'headshot')
-
-        def test_assignment(self):
-            p = self.PersonModel()
-            self.check_dimensions(p, None, None, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
-
-            p.mugshot = self.file1
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
-            p.headshot = self.file2
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-
-            # Clear the ImageFields one at a time.
-            p.mugshot = None
-            self.check_dimensions(p, None, None, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-            p.headshot = None
-            self.check_dimensions(p, None, None, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
-
-        def test_field_save_and_delete_methods(self):
-            p = self.PersonModel(name='Joe')
-            p.mugshot.save("mug", self.file1)
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
-            p.headshot.save("head", self.file2)
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-
-            # We can use save=True when deleting the image field with null=True
-            # dimension fields and the other field has an image.
-            p.headshot.delete(save=True)
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
-            p.mugshot.delete(save=False)
-            self.check_dimensions(p, None, None, 'mugshot')
-            self.check_dimensions(p, None, None, 'headshot')
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
+    """
+    Tests behavior of an ImageField and its dimensions fields.
+    """
 
-        def test_dimensions(self):
-            """
-            Checks that dimensions are updated correctly in various situations.
-            """
-            p = self.PersonModel(name='Joe')
+    def test_constructor(self):
+        """
+        Tests assigning an image field through the model's constructor.
+        """
+        p = self.PersonModel(name='Joe', mugshot=self.file1)
+        self.check_dimensions(p, 4, 8)
+        p.save()
+        self.check_dimensions(p, 4, 8)
 
-            # Dimensions should get set for the saved file.
-            p.mugshot.save("mug", self.file1)
-            p.headshot.save("head", self.file2)
-            self.check_dimensions(p, 4, 8, 'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-
-            # Test dimensions after fetching from database.
-            p = self.PersonModel.objects.get(name='Joe')
-            # Bug 11084: Dimensions should not get recalculated if file is
-            # coming from the database.  We test this by checking if the file
-            # was opened.
-            self.assertEqual(p.mugshot.was_opened, False)
-            self.assertEqual(p.headshot.was_opened, False)
-            self.check_dimensions(p, 4, 8,'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-            # After checking dimensions on the image fields, the files will
-            # have been opened.
-            self.assertEqual(p.mugshot.was_opened, True)
-            self.assertEqual(p.headshot.was_opened, True)
-            # Dimensions should now be cached, and if we reset was_opened and
-            # check dimensions again, the file should not have opened.
-            p.mugshot.was_opened = False
-            p.headshot.was_opened = False
-            self.check_dimensions(p, 4, 8,'mugshot')
-            self.check_dimensions(p, 8, 4, 'headshot')
-            self.assertEqual(p.mugshot.was_opened, False)
-            self.assertEqual(p.headshot.was_opened, False)
-
-            # If we assign a new image to the instance, the dimensions should
-            # update.
-            p.mugshot = self.file2
-            p.headshot = self.file1
-            self.check_dimensions(p, 8, 4, 'mugshot')
-            self.check_dimensions(p, 4, 8, 'headshot')
-            # Dimensions were recalculated, and hence file should have opened.
-            self.assertEqual(p.mugshot.was_opened, True)
-            self.assertEqual(p.headshot.was_opened, True)
+    def test_image_after_constructor(self):
+        """
+        Tests behavior when image is not passed in constructor.
+        """
+        p = self.PersonModel(name='Joe')
+        # TestImageField value will default to being an instance of its
+        # attr_class, a  TestImageFieldFile, with name == None, which will
+        # cause it to evaluate as False.
+        self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
+        self.assertEqual(bool(p.mugshot), False)
+
+        # Test setting a fresh created model instance.
+        p = self.PersonModel(name='Joe')
+        p.mugshot = self.file1
+        self.check_dimensions(p, 4, 8)
+
+    def test_create(self):
+        """
+        Tests assigning an image in Manager.create().
+        """
+        p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1)
+        self.check_dimensions(p, 4, 8)
+
+    def test_default_value(self):
+        """
+        Tests that the default value for an ImageField is an instance of
+        the field's attr_class (TestImageFieldFile in this case) with no
+        name (name set to None).
+        """
+        p = self.PersonModel()
+        self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
+        self.assertEqual(bool(p.mugshot), False)
+
+    def test_assignment_to_None(self):
+        """
+        Tests that assigning ImageField to None clears dimensions.
+        """
+        p = self.PersonModel(name='Joe', mugshot=self.file1)
+        self.check_dimensions(p, 4, 8)
+
+        # If image assigned to None, dimension fields should be cleared.
+        p.mugshot = None
+        self.check_dimensions(p, None, None)
+
+        p.mugshot = self.file2
+        self.check_dimensions(p, 8, 4)
+
+    def test_field_save_and_delete_methods(self):
+        """
+        Tests assignment using the field's save method and deletion using
+        the field's delete method.
+        """
+        p = self.PersonModel(name='Joe')
+        p.mugshot.save("mug", self.file1)
+        self.check_dimensions(p, 4, 8)
+
+        # A new file should update dimensions.
+        p.mugshot.save("mug", self.file2)
+        self.check_dimensions(p, 8, 4)
+
+        # Field and dimensions should be cleared after a delete.
+        p.mugshot.delete(save=False)
+        self.assertEqual(p.mugshot, None)
+        self.check_dimensions(p, None, None)
+
+    def test_dimensions(self):
+        """
+        Checks that dimensions are updated correctly in various situations.
+        """
+        p = self.PersonModel(name='Joe')
+
+        # Dimensions should get set if file is saved.
+        p.mugshot.save("mug", self.file1)
+        self.check_dimensions(p, 4, 8)
+
+        # Test dimensions after fetching from database.
+        p = self.PersonModel.objects.get(name='Joe')
+        # Bug 11084: Dimensions should not get recalculated if file is
+        # coming from the database.  We test this by checking if the file
+        # was opened.
+        self.assertEqual(p.mugshot.was_opened, False)
+        self.check_dimensions(p, 4, 8)
+        # After checking dimensions on the image field, the file will have
+        # opened.
+        self.assertEqual(p.mugshot.was_opened, True)
+        # Dimensions should now be cached, and if we reset was_opened and
+        # check dimensions again, the file should not have opened.
+        p.mugshot.was_opened = False
+        self.check_dimensions(p, 4, 8)
+        self.assertEqual(p.mugshot.was_opened, False)
+
+        # If we assign a new image to the instance, the dimensions should
+        # update.
+        p.mugshot = self.file2
+        self.check_dimensions(p, 8, 4)
+        # Dimensions were recalculated, and hence file should have opened.
+        self.assertEqual(p.mugshot.was_opened, True)
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
+    """
+    Tests behavior of an ImageField with no dimension fields.
+    """
+
+    PersonModel = Person
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
+    """
+    Tests behavior of an ImageField with one dimensions field.
+    """
+
+    PersonModel = PersonWithHeight
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
+    """
+    Tests behavior of an ImageField where the dimensions fields are
+    defined before the ImageField.
+    """
+
+    PersonModel = PersonDimensionsFirst
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
+    """
+    Tests behavior of an ImageField when assigning it a File instance
+    rather than an ImageFile instance.
+    """
+
+    PersonModel = PersonDimensionsFirst
+    File = File
+
+
+@skipIf(Image is None, "PIL is required to test ImageField")
+class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
+    """
+    Tests a model with two ImageFields.
+    """
+
+    PersonModel = PersonTwoImages
+
+    def test_constructor(self):
+        p = self.PersonModel(mugshot=self.file1, headshot=self.file2)
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+        p.save()
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+
+    def test_create(self):
+        p = self.PersonModel.objects.create(mugshot=self.file1,
+                                            headshot=self.file2)
+        self.check_dimensions(p, 4, 8)
+        self.check_dimensions(p, 8, 4, 'headshot')
+
+    def test_assignment(self):
+        p = self.PersonModel()
+        self.check_dimensions(p, None, None, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+
+        p.mugshot = self.file1
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+        p.headshot = self.file2
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+
+        # Clear the ImageFields one at a time.
+        p.mugshot = None
+        self.check_dimensions(p, None, None, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+        p.headshot = None
+        self.check_dimensions(p, None, None, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+
+    def test_field_save_and_delete_methods(self):
+        p = self.PersonModel(name='Joe')
+        p.mugshot.save("mug", self.file1)
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+        p.headshot.save("head", self.file2)
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+
+        # We can use save=True when deleting the image field with null=True
+        # dimension fields and the other field has an image.
+        p.headshot.delete(save=True)
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+        p.mugshot.delete(save=False)
+        self.check_dimensions(p, None, None, 'mugshot')
+        self.check_dimensions(p, None, None, 'headshot')
+
+    def test_dimensions(self):
+        """
+        Checks that dimensions are updated correctly in various situations.
+        """
+        p = self.PersonModel(name='Joe')
+
+        # Dimensions should get set for the saved file.
+        p.mugshot.save("mug", self.file1)
+        p.headshot.save("head", self.file2)
+        self.check_dimensions(p, 4, 8, 'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+
+        # Test dimensions after fetching from database.
+        p = self.PersonModel.objects.get(name='Joe')
+        # Bug 11084: Dimensions should not get recalculated if file is
+        # coming from the database.  We test this by checking if the file
+        # was opened.
+        self.assertEqual(p.mugshot.was_opened, False)
+        self.assertEqual(p.headshot.was_opened, False)
+        self.check_dimensions(p, 4, 8,'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+        # After checking dimensions on the image fields, the files will
+        # have been opened.
+        self.assertEqual(p.mugshot.was_opened, True)
+        self.assertEqual(p.headshot.was_opened, True)
+        # Dimensions should now be cached, and if we reset was_opened and
+        # check dimensions again, the file should not have opened.
+        p.mugshot.was_opened = False
+        p.headshot.was_opened = False
+        self.check_dimensions(p, 4, 8,'mugshot')
+        self.check_dimensions(p, 8, 4, 'headshot')
+        self.assertEqual(p.mugshot.was_opened, False)
+        self.assertEqual(p.headshot.was_opened, False)
+
+        # If we assign a new image to the instance, the dimensions should
+        # update.
+        p.mugshot = self.file2
+        p.headshot = self.file1
+        self.check_dimensions(p, 8, 4, 'mugshot')
+        self.check_dimensions(p, 4, 8, 'headshot')
+        # Dimensions were recalculated, and hence file should have opened.
+        self.assertEqual(p.mugshot.was_opened, True)
+        self.assertEqual(p.headshot.was_opened, True)

+ 4 - 6
tests/regressiontests/model_fields/tests.py

@@ -13,12 +13,10 @@ from django.utils import unittest
 from .models import (Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post,
     NullBooleanModel, BooleanModel, Document, RenamedField)
 
-# If PIL available, do these tests.
-if Image:
-    from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests,
-        TwoImageFieldTests, ImageFieldNoDimensionsTests,
-        ImageFieldOneDimensionTests, ImageFieldDimensionsFirstTests,
-        ImageFieldUsingFileTests)
+from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests,
+    TwoImageFieldTests, ImageFieldNoDimensionsTests,
+    ImageFieldOneDimensionTests, ImageFieldDimensionsFirstTests,
+    ImageFieldUsingFileTests)
 
 
 class BasicFieldTests(test.TestCase):