Completed
Pull Request — master (#114)
by Johannes
48s
created

TestModel.test_variations()   F

Complexity

Conditions 16

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 2 Features 1
Metric Value
c 7
b 2
f 1
dl 0
loc 31
rs 2.7326
cc 16

How to fix   Complexity   

Complexity

Complex classes like TestModel.test_variations() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# coding: utf-8
2
from __future__ import absolute_import, unicode_literals
3
4
import filecmp
5
import io
6
7
import os
8
import pytest
9
import shutil
10
import uuid
11
12
from PIL import Image
13
from django.core.files.storage import default_storage
14
from django.core.files.uploadedfile import SimpleUploadedFile
15
16
17
class UUID4Monkey(object):
18
    hex = '653d1c6863404b9689b75fa930c9d0a0'
19
20
21
uuid.__dict__['uuid4'] = lambda: UUID4Monkey()
22
23
import django  # NoQA
24
from django.conf import settings  # NoQA
25
26
from .models import (
27
    SimpleModel, ResizeModel, AdminDeleteModel,
28
    ThumbnailModel, ResizeCropModel, AutoSlugClassNameDirModel,
29
    UUIDModel,
30
    UtilVariationsModel,
31
    ThumbnailWithoutDirectoryModel,
32
    CustomRenderVariationsModel)  # NoQA
33
34
IMG_DIR = os.path.join(settings.MEDIA_ROOT, 'img')
35
FIXTURES = [
36
    ('100.gif', 'GIF', 100, 100),
37
    ('600x400.gif', 'GIF', 600, 400),
38
    ('600x400.jpg', 'JPEG', 600, 400),
39
    ('600x400.jpg', 'PNG', 600, 400),
40
]
41
42
43
class TestStdImage(object):
44
    fixtures = {}
45
46
    @pytest.fixture(autouse=True)
47
    def setup(self):
48
        for fixture_filename, img_format, width, height in FIXTURES:
49
            with io.BytesIO() as f:
50
                img = Image.new('RGB', (width, height), (255, 55, 255))
51
                img.save(f, format=img_format)
52
                self.fixtures[fixture_filename] = SimpleUploadedFile(fixture_filename, f.getvalue())
53
54
        yield
55
56
        for root, dirs, files in os.walk(settings.MEDIA_ROOT, topdown=False):
57
            for name in files:
58
                os.remove(os.path.join(root, name))
59
            for name in dirs:
60
                os.rmdir(os.path.join(root, name))
61
62
63
class TestModel(TestStdImage):
64
    """Tests StdImage ModelField"""
65
66
    def test_simple(self, db):
67
        """Tests if Field behaves just like Django's ImageField."""
68
        instance = SimpleModel.objects.create(image=self.fixtures['100.gif'])
69
        target_file = os.path.join(IMG_DIR, '100.gif')
70
        source_file = self.fixtures['100.gif']
71
72
        assert SimpleModel.objects.count() == 1
73
        assert SimpleModel.objects.get(pk=1) == instance
74
75
        assert os.path.exists(target_file)
76
77
        with open(target_file, 'rb') as f:
78
            source_file.seek(0)
79
            assert source_file.read() == f.read()
80
81
    def test_variations(self, db):
82
        """Adds image and checks filesystem as well as width and height."""
83
        instance = ResizeModel.objects.create(
84
            image=self.fixtures['600x400.jpg']
85
        )
86
87
        source_file = self.fixtures['600x400.jpg']
88
89
        assert os.path.exists(os.path.join(IMG_DIR, 'image.jpg'))
90
        assert instance.image.width == 600
91
        assert instance.image.height == 400
92
        path = os.path.join(IMG_DIR, 'image.jpg')
93
94
        with open(path, 'rb') as f:
95
            source_file.seek(0)
96
            assert source_file.read() == f.read()
97
98
        path = os.path.join(IMG_DIR, 'image.medium.jpg')
99
        assert os.path.exists(path)
100
        assert instance.image.medium.width == 400
101
        assert instance.image.medium.height <= 400
102
        with open(os.path.join(IMG_DIR, 'image.medium.jpg'), 'rb') as f:
103
            source_file.seek(0)
104
            assert source_file.read() != f.read()
105
106
        assert os.path.exists(os.path.join(IMG_DIR, 'image.thumbnail.jpg'))
107
        assert instance.image.thumbnail.width == 100
108
        assert instance.image.thumbnail.height <= 75
109
        with open(os.path.join(IMG_DIR, 'image.thumbnail.jpg'), 'rb') as f:
110
            source_file.seek(0)
111
            assert source_file.read() != f.read()
112
113
    def test_cropping(self, db):
114
        instance = ResizeCropModel.objects.create(
115
            image=self.fixtures['600x400.jpg']
116
        )
117
        assert instance.image.thumbnail.width == 150
118
        assert instance.image.thumbnail.height == 150
119
120
    def test_variations_override(self, db):
121
        source_file = self.fixtures['600x400.jpg']
122
        target_file = os.path.join(IMG_DIR, 'image.thumbnail.jpg')
123
        os.mkdir(IMG_DIR)
124
        default_storage.save(target_file, source_file)
125
        ResizeModel.objects.create(
126
            image=self.fixtures['600x400.jpg']
127
        )
128
        thumbnail_path = os.path.join(IMG_DIR, 'image.thumbnail.jpg')
129
        assert os.path.exists(thumbnail_path)
130
        thumbnail_path = os.path.join(IMG_DIR, 'image.thumbnail_1.jpg')
131
        assert not os.path.exists(thumbnail_path)
132
133
    def test_delete_thumbnail(self, db):
134
        """Delete an image with thumbnail"""
135
        obj = ThumbnailModel.objects.create(
136
            image=self.fixtures['100.gif']
137
        )
138
        obj.image.delete()
139
        path = os.path.join(IMG_DIR, 'image.gif')
140
        assert not os.path.exists(path)
141
142
        path = os.path.join(IMG_DIR, 'image.thumbnail.gif')
143
        assert not os.path.exists(path)
144
145
    def test_fore_min_size(self, admin_client):
146
        admin_client.post('/admin/tests/forceminsizemodel/add/', {
147
            'image': self.fixtures['100.gif'],
148
        })
149
        path = os.path.join(IMG_DIR, 'image.gif')
150
        assert not os.path.exists(path)
151
152
    def test_thumbnail_save_without_directory(self, db):
153
        obj = ThumbnailWithoutDirectoryModel.objects.create(
154
            image=self.fixtures['100.gif']
155
        )
156
        obj.save()
157
        # Our model saves the images directly into the MEDIA_ROOT directory
158
        # not IMG_DIR, under a custom name
159
        original = os.path.join(settings.MEDIA_ROOT, 'custom.gif')
160
        thumbnail = os.path.join(settings.MEDIA_ROOT, 'custom.thumbnail.gif')
161
        assert os.path.exists(original)
162
        assert os.path.exists(thumbnail)
163
164
    def test_custom_render_variations(self, db):
165
        instance = CustomRenderVariationsModel.objects.create(
166
            image=self.fixtures['600x400.jpg']
167
        )
168
        # Image size must be 100x100 despite variations settings
169
        assert instance.image.thumbnail.width == 100
170
        assert instance.image.thumbnail.height == 100
171
172
173
class TestUtils(TestStdImage):
174
    """Tests Utils"""
175
176
    def test_deletion_singnal_receiver(self, db):
177
        obj = SimpleModel.objects.create(
178
            image=self.fixtures['100.gif']
179
        )
180
        obj.delete()
181
        assert not os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
182
183
    def test_pre_save_delete_callback_clear(self, admin_client):
184
        AdminDeleteModel.objects.create(
185
            image=self.fixtures['100.gif']
186
        )
187
        if django.VERSION >= (1, 9):
188
            admin_client.post('/admin/tests/admindeletemodel/1/change/', {
189
                'image-clear': 'checked',
190
            })
191
        else:
192
            admin_client.post('/admin/tests/admindeletemodel/1/', {
193
                'image-clear': 'checked',
194
            })
195
        assert not os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
196
197
    def test_pre_save_delete_callback_new(self, admin_client):
198
        AdminDeleteModel.objects.create(
199
            image=self.fixtures['100.gif']
200
        )
201
        if django.VERSION >= (1, 9):
202
            admin_client.post('/admin/tests/admindeletemodel/1/change/', {
203
                'image': self.fixtures['600x400.jpg'],
204
            })
205
        else:
206
            admin_client.post('/admin/tests/admindeletemodel/1/', {
207
                'image': self.fixtures['600x400.jpg'],
208
            })
209
        assert not os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
210
211
    def test_upload_to_auto_slug_class_name_dir(self, db):
212
        AutoSlugClassNameDirModel.objects.create(
213
            name='foo bar',
214
            image=self.fixtures['100.gif']
215
        )
216
        file_path = os.path.join(
217
            settings.MEDIA_ROOT,
218
            'autoslugclassnamedirmodel',
219
            'foo-bar.gif'
220
        )
221
        assert os.path.exists(file_path)
222
223
    def test_upload_to_uuid(self, db):
224
        UUIDModel.objects.create(image=self.fixtures['100.gif'])
225
        file_path = os.path.join(
226
            IMG_DIR,
227
            '653d1c6863404b9689b75fa930c9d0a0.gif'
228
        )
229
        assert os.path.exists(file_path)
230
231
    def test_render_variations_callback(self, db):
232
        UtilVariationsModel.objects.create(image=self.fixtures['100.gif'])
233
        file_path = os.path.join(
234
            IMG_DIR,
235
            'image.thumbnail.gif'
236
        )
237
        assert os.path.exists(file_path)
238
239
240
class TestValidators(TestStdImage):
241
    def test_max_size_validator(self, admin_client):
242
        admin_client.post('/admin/tests/maxsizemodel/add/', {
243
            'image': self.fixtures['600x400.jpg'],
244
        })
245
        assert not os.path.exists(os.path.join(IMG_DIR, 'image.jpg'))
246
247
    def test_min_size_validator(self, admin_client):
248
        admin_client.post('/admin/tests/minsizemodel/add/', {
249
            'image': self.fixtures['100.gif'],
250
        })
251
        assert not os.path.exists(os.path.join(IMG_DIR, 'image.gif'))
252