1import os
2import unittest
3
4from django import forms, template
5from django.conf import settings
6from django.core.exceptions import ImproperlyConfigured
7from django.test import TestCase, override_settings
8from django.urls import reverse
9from taggit.forms import TagField, TagWidget
10
11from wagtail.images import get_image_model, get_image_model_string
12from wagtail.images.fields import WagtailImageField
13from wagtail.images.formats import Format, get_image_format, register_image_format
14from wagtail.images.forms import get_image_form
15from wagtail.images.models import Image as WagtailImage
16from wagtail.images.rect import Rect, Vector
17from wagtail.images.utils import generate_signature, verify_signature
18from wagtail.images.views.serve import ServeView
19from wagtail.tests.testapp.models import CustomImage, CustomImageFilePath
20from wagtail.tests.utils import WagtailTestUtils
21
22from .utils import Image, get_test_image_file
23
24
25try:
26    import sendfile  # noqa
27    sendfile_mod = True
28except ImportError:
29    sendfile_mod = False
30
31
32class TestImageTag(TestCase):
33    def setUp(self):
34        # Create an image for running tests on
35        self.image = Image.objects.create(
36            title="Test image",
37            file=get_test_image_file(),
38        )
39
40    def render_image_tag(self, image, filter_spec):
41        temp = template.Template('{% load wagtailimages_tags %}{% image image_obj ' + filter_spec + '%}')
42        context = template.Context({'image_obj': image})
43        return temp.render(context)
44
45    def test_image_tag(self):
46        result = self.render_image_tag(self.image, 'width-400')
47
48        # Check that all the required HTML attributes are set
49        self.assertTrue('width="400"' in result)
50        self.assertTrue('height="300"' in result)
51        self.assertTrue('alt="Test image"' in result)
52
53    def test_image_tag_none(self):
54        result = self.render_image_tag(None, "width-500")
55        self.assertEqual(result, '')
56
57    def test_image_tag_wrong_type(self):
58        with self.assertRaises(ValueError):
59            self.render_image_tag("foobar", "width-500")
60
61    def render_image_tag_as(self, image, filter_spec):
62        temp = template.Template(
63            '{% load wagtailimages_tags %}{% image image_obj ' + filter_spec
64            + ' as test_img %}<img {{ test_img.attrs }} />'
65        )
66        context = template.Context({'image_obj': image})
67        return temp.render(context)
68
69    def test_image_tag_attrs(self):
70        result = self.render_image_tag_as(self.image, 'width-400')
71
72        # Check that all the required HTML attributes are set
73        self.assertTrue('width="400"' in result)
74        self.assertTrue('height="300"' in result)
75        self.assertTrue('alt="Test image"' in result)
76
77    def render_image_tag_with_extra_attributes(self, image, title):
78        temp = template.Template(
79            '{% load wagtailimages_tags %}{% image image_obj width-400 \
80            class="photo" title=title|lower alt="Alternate" %}'
81        )
82        context = template.Context({'image_obj': image, 'title': title})
83        return temp.render(context)
84
85    def test_image_tag_with_extra_attributes(self):
86        result = self.render_image_tag_with_extra_attributes(self.image, 'My Wonderful Title')
87
88        # Check that all the required HTML attributes are set
89        self.assertTrue('width="400"' in result)
90        self.assertTrue('height="300"' in result)
91        self.assertTrue('class="photo"' in result)
92        self.assertTrue('alt="Alternate"' in result)
93        self.assertTrue('title="my wonderful title"' in result)
94
95    def render_image_tag_with_filters(self, image):
96        temp = template.Template(
97            '{% load wagtailimages_tags %}{% image image_primary|default:image_alternate width-400 %}'
98        )
99        context = template.Context({'image_primary': None, 'image_alternate': image})
100        return temp.render(context)
101
102    def test_image_tag_with_filters(self):
103        result = self.render_image_tag_with_filters(self.image)
104        self.assertTrue('width="400"' in result)
105        self.assertTrue('height="300"' in result)
106
107    def test_image_tag_with_chained_filters(self):
108        result = self.render_image_tag(self.image, 'fill-200x200 height-150')
109        self.assertTrue('width="150"' in result)
110        self.assertTrue('height="150"' in result)
111
112    def test_filter_specs_must_match_allowed_pattern(self):
113        with self.assertRaises(template.TemplateSyntaxError):
114            self.render_image_tag(self.image, 'fill-200x200|height-150')
115
116        with self.assertRaises(template.TemplateSyntaxError):
117            self.render_image_tag(self.image, 'fill-800x600 alt"test"')
118
119    def test_context_may_only_contain_one_argument(self):
120        with self.assertRaises(template.TemplateSyntaxError):
121            temp = template.Template(
122                '{% load wagtailimages_tags %}{% image image_obj fill-200x200'
123                ' as test_img this_one_should_not_be_there %}<img {{ test_img.attrs }} />'
124            )
125            context = template.Context({'image_obj': self.image})
126            temp.render(context)
127
128    def test_no_image_filter_provided(self):
129        # if image template gets the image but no filters
130        with self.assertRaises(template.TemplateSyntaxError):
131            temp = template.Template(
132                '{% load wagtailimages_tags %}{% image image_obj %}'
133            )
134            context = template.Context({'image_obj': self.image})
135            temp.render(context)
136
137    def test_no_image_filter_provided_when_using_as(self):
138        # if image template gets the image but no filters
139        with self.assertRaises(template.TemplateSyntaxError):
140            temp = template.Template(
141                '{% load wagtailimages_tags %}{% image image_obj as foo %}'
142            )
143            context = template.Context({'image_obj': self.image})
144            temp.render(context)
145
146    def test_no_image_filter_provided_but_attributes_provided(self):
147        # if image template gets the image but no filters
148        with self.assertRaises(template.TemplateSyntaxError):
149            temp = template.Template(
150                '{% load wagtailimages_tags %}{% image image_obj class="cover-image"%}'
151            )
152            context = template.Context({'image_obj': self.image})
153            temp.render(context)
154
155    def render_image_url_tag(self, image, view_name):
156        temp = template.Template(
157            '{% load wagtailimages_tags %}{% image_url image_obj "width-400" "' + view_name + '" %}'
158        )
159        context = template.Context({'image_obj': image})
160        return temp.render(context)
161
162    def test_image_url(self):
163        result = self.render_image_url_tag(self.image, 'wagtailimages_serve')
164        self.assertRegex(
165            result,
166            '/images/.*/width-400/{}'.format(self.image.file.name.split('/')[-1]),
167        )
168
169    def test_image_url_custom_view(self):
170        result = self.render_image_url_tag(self.image, 'wagtailimages_serve_custom_view')
171
172        self.assertRegex(
173            result,
174            '/testimages/custom_view/.*/width-400/{}'.format(self.image.file.name.split('/')[-1]),
175        )
176
177    def test_image_url_no_imageserve_view_added(self):
178        # if image_url tag is used, but the image serve view was not defined.
179        with self.assertRaises(ImproperlyConfigured):
180            temp = template.Template(
181                '{% load wagtailimages_tags %}{% image_url image_obj "width-400" "mynonexistingimageserve_view" %}'
182            )
183            context = template.Context({'image_obj': self.image})
184            temp.render(context)
185
186
187class TestMissingImage(TestCase):
188    """
189    Missing image files in media/original_images should be handled gracefully, to cope with
190    pulling live databases to a development instance without copying the corresponding image files.
191    In this case, it's acceptable to render broken images, but not to fail rendering the page outright.
192    """
193    fixtures = ['test.json']
194
195    def test_image_tag_with_missing_image(self):
196        # the page /events/christmas/ has a missing image as the feed image
197        response = self.client.get('/events/christmas/')
198        self.assertContains(
199            response,
200            '<img src="/media/not-found" width="0" height="0" alt="A missing image" class="feed-image">',
201            html=True
202        )
203
204    def test_rich_text_with_missing_image(self):
205        # the page /events/final-event/ has a missing image in the rich text body
206        response = self.client.get('/events/final-event/')
207        self.assertContains(
208            response,
209            '<img class="richtext-image full-width" src="/media/not-found" \
210            width="0" height="0" alt="where did my image go?">',
211            html=True
212        )
213
214
215class TestFormat(TestCase, WagtailTestUtils):
216    def setUp(self):
217        # test format
218        self.format = Format(
219            'test name',
220            'test label',
221            'test classnames',
222            'original'
223        )
224        # test image
225        self.image = Image.objects.create(
226            title="Test image",
227            file=get_test_image_file(),
228        )
229
230    def test_editor_attributes(self):
231        result = self.format.editor_attributes(
232            self.image,
233            'test alt text'
234        )
235        self.assertEqual(result,
236                         {'data-alt': 'test alt text', 'data-embedtype': 'image',
237                          'data-format': 'test name', 'data-id': self.image.pk})
238
239    def test_image_to_editor_html(self):
240        result = self.format.image_to_editor_html(
241            self.image,
242            'test alt text'
243        )
244        self.assertTagInHTML(
245            '<img data-embedtype="image" data-id="%d" data-format="test name" '
246            'data-alt="test alt text" class="test classnames" '
247            'width="640" height="480" alt="test alt text" >' % self.image.pk,
248            result, allow_extra_attrs=True)
249
250    def test_image_to_editor_html_with_quoting(self):
251        result = self.format.image_to_editor_html(
252            self.image,
253            'Arthur "two sheds" Jackson'
254        )
255        expected_html = (
256            '<img data-embedtype="image" data-id="%d" data-format="test name" '
257            'data-alt="Arthur &quot;two sheds&quot; Jackson" class="test classnames" '
258            'width="640" height="480" alt="Arthur &quot;two sheds&quot; Jackson" >'
259            % self.image.pk
260        )
261        self.assertTagInHTML(expected_html, result, allow_extra_attrs=True)
262
263    def test_image_to_html_no_classnames(self):
264        self.format.classnames = None
265        result = self.format.image_to_html(self.image, 'test alt text')
266        self.assertTagInHTML(
267            '<img width="640" height="480" alt="test alt text">', result, allow_extra_attrs=True)
268        self.format.classnames = 'test classnames'
269
270    def test_image_to_html_with_quoting(self):
271        result = self.format.image_to_html(self.image, 'Arthur "two sheds" Jackson')
272        self.assertTagInHTML(
273            '<img class="test classnames" width="640" height="480" '
274            'alt="Arthur &quot;two sheds&quot; Jackson">', result, allow_extra_attrs=True)
275
276    def test_get_image_format(self):
277        register_image_format(self.format)
278        result = get_image_format('test name')
279        self.assertEqual(result, self.format)
280
281
282class TestSignatureGeneration(TestCase):
283    def test_signature_generation(self):
284        self.assertEqual(generate_signature(100, 'fill-800x600'), 'xnZOzQyUg6pkfciqcfRJRosOrGg=')
285
286    def test_signature_verification(self):
287        self.assertTrue(verify_signature('xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x600'))
288
289    def test_signature_changes_on_image_id(self):
290        self.assertFalse(verify_signature('xnZOzQyUg6pkfciqcfRJRosOrGg=', 200, 'fill-800x600'))
291
292    def test_signature_changes_on_filter_spec(self):
293        self.assertFalse(verify_signature('xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x700'))
294
295
296class TestFrontendServeView(TestCase):
297    def setUp(self):
298        # Create an image for running tests on
299        self.image = Image.objects.create(
300            title="Test image",
301            file=get_test_image_file(),
302        )
303
304    def test_get(self):
305        """
306        Test a valid GET request to the view
307        """
308        # Generate signature
309        signature = generate_signature(self.image.id, 'fill-800x600')
310
311        # Get the image
312        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
313
314        # Check response
315        self.assertEqual(response.status_code, 200)
316        self.assertTrue(response.streaming)
317        self.assertEqual(response['Content-Type'], 'image/png')
318
319    def test_get_with_extra_component(self):
320        """
321        Test that a filename can be optionally added to the end of the URL.
322        """
323        # Generate signature
324        signature = generate_signature(self.image.id, 'fill-800x600')
325
326        # Get the image
327        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')) + 'test.png')
328
329        # Check response
330        self.assertEqual(response.status_code, 200)
331        self.assertTrue(response.streaming)
332        self.assertEqual(response['Content-Type'], 'image/png')
333
334    def test_get_with_too_many_extra_components(self):
335        """
336        A filename can be appended to the end of the URL, but it must not contain a '/'
337        """
338        # Generate signature
339        signature = generate_signature(self.image.id, 'fill-800x600')
340
341        # Get the image
342        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')) + 'test/test.png')
343
344        # URL pattern should not match
345        self.assertEqual(response.status_code, 404)
346
347    def test_get_with_serve_action(self):
348        signature = generate_signature(self.image.id, 'fill-800x600')
349        response = self.client.get(reverse('wagtailimages_serve_action_serve', args=(signature, self.image.id, 'fill-800x600')))
350
351        self.assertEqual(response.status_code, 200)
352        self.assertTrue(response.streaming)
353        self.assertEqual(response['Content-Type'], 'image/png')
354
355    def test_get_with_redirect_action(self):
356        signature = generate_signature(self.image.id, 'fill-800x600')
357        response = self.client.get(reverse('wagtailimages_serve_action_redirect', args=(signature, self.image.id, 'fill-800x600')))
358
359        expected_redirect_url = '/media/images/{filename[0]}.2e16d0ba.fill-800x600{filename[1]}'.format(
360            filename=os.path.splitext(os.path.basename(self.image.file.path))
361        )
362
363        self.assertRedirects(response, expected_redirect_url, status_code=301, fetch_redirect_response=False)
364
365    def test_init_with_unknown_action_raises_error(self):
366        with self.assertRaises(ImproperlyConfigured):
367            ServeView.as_view(action='unknown')
368
369    def test_get_with_custom_key(self):
370        """
371        Test that that the key can be changed on the view
372        """
373        # Generate signature
374        signature = generate_signature(self.image.id, 'fill-800x600', key='custom')
375
376        # Get the image
377        response = self.client.get(reverse('wagtailimages_serve_custom_key', args=(signature, self.image.id, 'fill-800x600')) + 'test.png')
378
379        # Check response
380        self.assertEqual(response.status_code, 200)
381
382    def test_get_with_custom_key_using_default_key(self):
383        """
384        Test that that the key can be changed on the view
385
386        This tests that the default key no longer works when the key is changed on the view
387        """
388        # Generate signature
389        signature = generate_signature(self.image.id, 'fill-800x600')
390
391        # Get the image
392        response = self.client.get(reverse('wagtailimages_serve_custom_key', args=(signature, self.image.id, 'fill-800x600')) + 'test.png')
393
394        # Check response
395        self.assertEqual(response.status_code, 403)
396
397    def test_get_invalid_signature(self):
398        """
399        Test that an invalid signature returns a 403 response
400        """
401        # Generate a signature for the incorrect image id
402        signature = generate_signature(self.image.id + 1, 'fill-800x600')
403
404        # Get the image
405        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
406
407        # Check response
408        self.assertEqual(response.status_code, 403)
409
410    def test_get_invalid_filter_spec(self):
411        """
412        Test that an invalid filter spec returns a 400 response
413
414        This is very unlikely to happen in reality. A user would have
415        to create signature for the invalid filter spec which can't be
416        done with Wagtails built in URL generator. We should test it
417        anyway though.
418        """
419        # Generate a signature with the invalid filterspec
420        signature = generate_signature(self.image.id, 'bad-filter-spec')
421
422        # Get the image
423        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'bad-filter-spec')))
424
425        # Check response
426        self.assertEqual(response.status_code, 400)
427
428    def test_get_missing_source_image_file(self):
429        """
430        Test that a missing image file gives a 410 response
431
432        When the source image file is missing, it is presumed deleted so we
433        return a 410 "Gone" response.
434        """
435        # Delete the image file
436        os.remove(self.image.file.path)
437
438        # Get the image
439        signature = generate_signature(self.image.id, 'fill-800x600')
440        response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
441
442        # Check response
443        self.assertEqual(response.status_code, 410)
444
445
446class TestFrontendSendfileView(TestCase):
447
448    def setUp(self):
449        self.image = Image.objects.create(
450            title="Test image",
451            file=get_test_image_file(),
452        )
453
454    @override_settings(SENDFILE_BACKEND='sendfile.backends.development')
455    @unittest.skipIf(not sendfile_mod, 'Missing django-sendfile app.')
456    def test_sendfile_nobackend(self):
457        signature = generate_signature(self.image.id, 'fill-800x600')
458        response = self.client.get(reverse('wagtailimages_sendfile',
459                                           args=(signature, self.image.id,
460                                                 'fill-800x600')))
461
462        self.assertEqual(response.status_code, 200)
463        self.assertEqual(response['Content-Type'], 'image/png')
464
465    @override_settings(SENDFILE_BACKEND='sendfile.backends.development')
466    def test_sendfile_dummy_backend(self):
467        signature = generate_signature(self.image.id, 'fill-800x600')
468        response = self.client.get(reverse('wagtailimages_sendfile_dummy',
469                                           args=(signature, self.image.id,
470                                                 'fill-800x600')))
471
472        self.assertEqual(response.status_code, 200)
473        self.assertTrue(response.content, 'Dummy backend response')
474
475
476class TestRect(TestCase):
477    def test_init(self):
478        rect = Rect(100, 150, 200, 250)
479        self.assertEqual(rect.left, 100)
480        self.assertEqual(rect.top, 150)
481        self.assertEqual(rect.right, 200)
482        self.assertEqual(rect.bottom, 250)
483
484    def test_equality(self):
485        self.assertEqual(Rect(100, 150, 200, 250), Rect(100, 150, 200, 250))
486        self.assertNotEqual(Rect(100, 150, 200, 250), Rect(10, 15, 20, 25))
487
488    def test_getitem(self):
489        rect = Rect(100, 150, 200, 250)
490        self.assertEqual(rect[0], 100)
491        self.assertEqual(rect[1], 150)
492        self.assertEqual(rect[2], 200)
493        self.assertEqual(rect[3], 250)
494        self.assertRaises(IndexError, rect.__getitem__, 4)
495
496    def test_as_tuple(self):
497        rect = Rect(100, 150, 200, 250)
498        self.assertEqual(rect.as_tuple(), (100, 150, 200, 250))
499
500    def test_size(self):
501        rect = Rect(100, 150, 200, 350)
502        self.assertIsInstance(rect.size, Vector)
503        self.assertEqual(rect.size, (100, 200))
504        self.assertEqual(rect.width, 100)
505        self.assertEqual(rect.height, 200)
506
507    def test_set_size_with_tuple(self):
508        rect = Rect(100, 150, 200, 350)
509        rect.size = (200, 400)
510        self.assertEqual(rect, (50, 50, 250, 450))
511
512    def test_set_size_with_vector(self):
513        rect = Rect(100, 150, 200, 350)
514        rect.size = Vector(200, 400)
515        self.assertEqual(rect, (50, 50, 250, 450))
516
517    def test_centroid(self):
518        rect = Rect(100, 150, 200, 350)
519        self.assertIsInstance(rect.centroid, Vector)
520        self.assertEqual(rect.centroid, (150, 250))
521        self.assertEqual(rect.x, 150)
522        self.assertEqual(rect.y, 250)
523        self.assertEqual(rect.centroid_x, 150)
524        self.assertEqual(rect.centroid_y, 250)
525
526    def test_set_centroid_with_tuple(self):
527        rect = Rect(100, 150, 200, 350)
528        rect.centroid = (500, 500)
529        self.assertEqual(rect, (450, 400, 550, 600))
530
531    def test_set_centroid_with_vector(self):
532        rect = Rect(100, 150, 200, 350)
533        rect.centroid = Vector(500, 500)
534        self.assertEqual(rect, (450, 400, 550, 600))
535
536    def test_repr(self):
537        rect = Rect(100, 150, 200, 250)
538        self.assertEqual(repr(rect), "Rect(left: 100, top: 150, right: 200, bottom: 250)")
539
540    def test_from_point(self):
541        rect = Rect.from_point(100, 200, 50, 20)
542        self.assertEqual(rect, Rect(75, 190, 125, 210))
543
544
545class TestGetImageForm(TestCase, WagtailTestUtils):
546    def test_fields(self):
547        form = get_image_form(Image)
548
549        self.assertEqual(list(form.base_fields.keys()), [
550            'title',
551            'file',
552            'collection',
553            'tags',
554            'focal_point_x',
555            'focal_point_y',
556            'focal_point_width',
557            'focal_point_height',
558        ])
559
560    def test_admin_form_fields_attribute(self):
561        form = get_image_form(CustomImage)
562
563        self.assertEqual(list(form.base_fields.keys()), [
564            'title',
565            'file',
566            'collection',
567            'tags',
568            'focal_point_x',
569            'focal_point_y',
570            'focal_point_width',
571            'focal_point_height',
572            'caption',
573            'fancy_caption',
574        ])
575
576    def test_file_field(self):
577        form = get_image_form(WagtailImage)
578
579        self.assertIsInstance(form.base_fields['file'], WagtailImageField)
580        self.assertIsInstance(form.base_fields['file'].widget, forms.FileInput)
581
582    def test_tags_field(self):
583        form = get_image_form(WagtailImage)
584
585        self.assertIsInstance(form.base_fields['tags'], TagField)
586        self.assertIsInstance(form.base_fields['tags'].widget, TagWidget)
587
588    def test_focal_point_fields(self):
589        form = get_image_form(WagtailImage)
590
591        self.assertIsInstance(form.base_fields['focal_point_x'], forms.IntegerField)
592        self.assertIsInstance(form.base_fields['focal_point_y'], forms.IntegerField)
593        self.assertIsInstance(form.base_fields['focal_point_width'], forms.IntegerField)
594        self.assertIsInstance(form.base_fields['focal_point_height'], forms.IntegerField)
595
596        self.assertIsInstance(form.base_fields['focal_point_x'].widget, forms.HiddenInput)
597        self.assertIsInstance(form.base_fields['focal_point_y'].widget, forms.HiddenInput)
598        self.assertIsInstance(form.base_fields['focal_point_width'].widget, forms.HiddenInput)
599        self.assertIsInstance(form.base_fields['focal_point_height'].widget, forms.HiddenInput)
600
601
602class TestRenditionFilenames(TestCase):
603    # Can't create image in setUp as we need a unique filename for each test.
604    # This stops Django appending some rubbish to the filename which makes
605    # the assertions difficult.
606
607    def test_normal_filter(self):
608        image = Image.objects.create(
609            title="Test image",
610            file=get_test_image_file(filename='test_rf1.png'),
611        )
612        rendition = image.get_rendition('width-100')
613
614        self.assertEqual(rendition.file.name, 'images/test_rf1.width-100.png')
615
616    def test_fill_filter(self):
617        image = Image.objects.create(
618            title="Test image",
619            file=get_test_image_file(filename='test_rf2.png'),
620        )
621        rendition = image.get_rendition('fill-100x100')
622
623        self.assertEqual(rendition.file.name, 'images/test_rf2.2e16d0ba.fill-100x100.png')
624
625    def test_fill_filter_with_focal_point(self):
626        image = Image.objects.create(
627            title="Test image",
628            file=get_test_image_file(filename='test_rf3.png'),
629        )
630        image.set_focal_point(Rect(100, 100, 200, 200))
631        image.save()
632
633        rendition = image.get_rendition('fill-100x100')
634
635        self.assertEqual(rendition.file.name, 'images/test_rf3.15ee4958.fill-100x100.png')
636
637    def test_filter_with_pipe_gets_dotted(self):
638        image = Image.objects.create(
639            title="Test image",
640            file=get_test_image_file(filename='test_rf4.png'),
641        )
642        image.set_focal_point(Rect(100, 100, 200, 200))
643        image.save()
644
645        rendition = image.get_rendition('fill-200x200|height-150')
646
647        self.assertEqual(rendition.file.name, 'images/test_rf4.15ee4958.fill-200x200.height-150.png')
648
649
650class TestDifferentUpload(TestCase):
651    def test_upload_path(self):
652        image = CustomImageFilePath.objects.create(
653            title="Test image",
654            file=get_test_image_file(),
655        )
656
657        second_image = CustomImageFilePath.objects.create(
658            title="Test Image",
659            file=get_test_image_file(colour='black'),
660
661        )
662
663        # The files should be uploaded based on it's content, not just
664        # it's filename
665        self.assertFalse(image.file.url == second_image.file.url)
666
667
668class TestGetImageModel(WagtailTestUtils, TestCase):
669    @override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
670    def test_custom_get_image_model(self):
671        """Test get_image_model with a custom image model"""
672        self.assertIs(get_image_model(), CustomImage)
673
674    @override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.CustomImage')
675    def test_custom_get_image_model_string(self):
676        """Test get_image_model_string with a custom image model"""
677        self.assertEqual(get_image_model_string(), 'tests.CustomImage')
678
679    @override_settings()
680    def test_standard_get_image_model(self):
681        """Test get_image_model with no WAGTAILIMAGES_IMAGE_MODEL"""
682        del settings.WAGTAILIMAGES_IMAGE_MODEL
683        from wagtail.images.models import Image
684        self.assertIs(get_image_model(), Image)
685
686    @override_settings()
687    def test_standard_get_image_model_string(self):
688        """Test get_image_model_STRING with no WAGTAILIMAGES_IMAGE_MODEL"""
689        del settings.WAGTAILIMAGES_IMAGE_MODEL
690        self.assertEqual(get_image_model_string(), 'wagtailimages.Image')
691
692    @override_settings(WAGTAILIMAGES_IMAGE_MODEL='tests.UnknownModel')
693    def test_unknown_get_image_model(self):
694        """Test get_image_model with an unknown model"""
695        with self.assertRaises(ImproperlyConfigured):
696            get_image_model()
697
698    @override_settings(WAGTAILIMAGES_IMAGE_MODEL='invalid-string')
699    def test_invalid_get_image_model(self):
700        """Test get_image_model with an invalid model string"""
701        with self.assertRaises(ImproperlyConfigured):
702            get_image_model()
703