tests.py 25 KB

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