/hyde/tests/ext/test_images.py

http://github.com/hyde/hyde · Python · 286 lines · 228 code · 47 blank · 11 comment · 12 complexity · 0d521077bd5b60a9ef67ecdab66a75c7 MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. """
  3. Use nose
  4. `$ pip install nose`
  5. `$ nosetests`
  6. Requires PIL
  7. """
  8. from hyde.generator import Generator
  9. from hyde.site import Site
  10. from hyde.ext.plugins.images import thumb_scale_size
  11. from fswrap import File
  12. import yaml
  13. TEST_SITE = File(__file__).parent.parent.child_folder('_test')
  14. IMAGE_SOURCE = File(__file__).parent.child_folder('images')
  15. PORTRAIT_IMAGE = "portrait.jpg"
  16. PORTRAIT_SIZE = (90, 120)
  17. LANDSCAPE_IMAGE = "landscape.jpg"
  18. LANDSCAPE_SIZE = (120, 90)
  19. IMAGES = [PORTRAIT_IMAGE, LANDSCAPE_IMAGE]
  20. SIZES = [PORTRAIT_SIZE, LANDSCAPE_SIZE]
  21. # PIL requirement
  22. try:
  23. from PIL import Image
  24. except ImportError:
  25. # No pillow
  26. import Image
  27. class TestImageSizer(object):
  28. def setUp(self):
  29. TEST_SITE.make()
  30. TEST_SITE.parent.child_folder(
  31. 'sites/test_jinja').copy_contents_to(TEST_SITE)
  32. IMAGES = TEST_SITE.child_folder('content/media/img')
  33. IMAGES.make()
  34. IMAGE_SOURCE.copy_contents_to(IMAGES)
  35. self.site = Site(TEST_SITE)
  36. def tearDown(self):
  37. TEST_SITE.delete()
  38. def _generic_test_image(self, text):
  39. self.site.config.mode = "production"
  40. self.site.config.plugins = ['hyde.ext.plugins.images.ImageSizerPlugin']
  41. tlink = File(self.site.content.source_folder.child('timg.html'))
  42. tlink.write(text)
  43. gen = Generator(self.site)
  44. gen.generate_all()
  45. f = File(self.site.config.deploy_root_path.child(tlink.name))
  46. assert f.exists
  47. html = f.read_all()
  48. assert html
  49. return html
  50. def test_size_image(self):
  51. text = u"""
  52. <img src="/media/img/%s">
  53. """ % PORTRAIT_IMAGE
  54. html = self._generic_test_image(text)
  55. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  56. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  57. def test_size_image_relative(self):
  58. text = u"""
  59. <img src="media/img/%s">
  60. """ % PORTRAIT_IMAGE
  61. html = self._generic_test_image(text)
  62. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  63. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  64. def test_size_image_no_resize(self):
  65. text = u"""
  66. <img src="/media/img/%s" width="2000" height="150">
  67. """ % PORTRAIT_IMAGE
  68. html = self._generic_test_image(text)
  69. assert ' width="%d"' % PORTRAIT_SIZE[0] not in html
  70. assert ' height="%d"' % PORTRAIT_SIZE[1] not in html
  71. def test_size_image_size_proportional(self):
  72. text = u"""
  73. <img src="/media/img/%s" width="%d">
  74. """ % (PORTRAIT_IMAGE, PORTRAIT_SIZE[0]*2)
  75. html = self._generic_test_image(text)
  76. assert ' width="%d"' % (PORTRAIT_SIZE[0]*2) in html
  77. assert ' height="%d"' % (PORTRAIT_SIZE[1]*2) in html
  78. def test_size_image_not_exists(self):
  79. text = u"""
  80. <img src="/media/img/hyde-logo-no.png">
  81. """
  82. self._generic_test_image(text)
  83. def test_size_image_multiline(self):
  84. text = u"""
  85. <img src="/media/img/%s">
  86. """ % PORTRAIT_IMAGE
  87. html = self._generic_test_image(text)
  88. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  89. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  90. def test_size_multiple_images(self):
  91. text = u"""
  92. <img src="/media/img/%s">
  93. <img src="/media/img/%s">Hello <img src="/media/img/%s">
  94. <img src="/media/img/%s">Bye
  95. """ % ((PORTRAIT_IMAGE,)*4)
  96. html = self._generic_test_image(text)
  97. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  98. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  99. assert 'Hello ' in html
  100. assert 'Bye' in html
  101. assert len([f for f in html.split("<img")
  102. if ' width=' in f]) == 4
  103. assert len([f for f in html.split("<img")
  104. if ' height=' in f]) == 4
  105. def test_size_malformed1(self):
  106. text = u"""
  107. <img src="/media/img/%s>
  108. """ % PORTRAIT_IMAGE
  109. html = self._generic_test_image(text)
  110. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  111. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  112. def test_size_malformed2(self):
  113. text = u"""
  114. <img src="/media/img/%s alt="hello">
  115. """ % PORTRAIT_IMAGE
  116. html = self._generic_test_image(text)
  117. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  118. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  119. def test_outside_media_url(self):
  120. self.site.config.media_url = "http://media.example.com/"
  121. text = u"""
  122. <img src="http://media.example.com/img/%s" alt="hello">
  123. """ % PORTRAIT_IMAGE
  124. html = self._generic_test_image(text)
  125. assert ' width="%d"' % PORTRAIT_SIZE[0] in html
  126. assert ' height="%d"' % PORTRAIT_SIZE[1] in html
  127. class TestImageThumbSize(object):
  128. def test_width_only(self):
  129. ow, oh = 100, 200
  130. nw, nh = thumb_scale_size(ow, oh, 50, None)
  131. assert nw == 50
  132. assert nh == 100
  133. def test_width_only_nonintegral(self):
  134. ow, oh = 100, 205
  135. nw, nh = thumb_scale_size(ow, oh, 50, None)
  136. assert nw == 50
  137. assert nh == 103
  138. def test_height_only(self):
  139. ow, oh = 100, 200
  140. nw, nh = thumb_scale_size(ow, oh, None, 100)
  141. assert nw == 50
  142. assert nh == 100
  143. def test_height_only_nonintegral(self):
  144. ow, oh = 105, 200
  145. nw, nh = thumb_scale_size(ow, oh, None, 100)
  146. assert nw == 53
  147. assert nh == 100
  148. def test_height_and_width_portrait(self):
  149. ow, oh = 100, 200
  150. nw, nh = thumb_scale_size(ow, oh, 50, 50)
  151. assert nw == 50
  152. assert nh == 100
  153. def test_height_and_width_landscape(self):
  154. ow, oh = 200, 100
  155. nw, nh = thumb_scale_size(ow, oh, 50, 50)
  156. assert nw == 100
  157. assert nh == 50
  158. class TestImageThumbnails(object):
  159. # TODO: add tests for cropping? (not easy currently)
  160. def setUp(self):
  161. TEST_SITE.make()
  162. TEST_SITE.parent.child_folder(
  163. 'sites/test_jinja').copy_contents_to(TEST_SITE)
  164. IMAGES = TEST_SITE.child_folder('content/media/img')
  165. IMAGES.make()
  166. IMAGE_SOURCE.copy_contents_to(IMAGES)
  167. self.image_folder = IMAGES
  168. self.site = Site(TEST_SITE)
  169. def tearDown(self):
  170. TEST_SITE.delete()
  171. def _generate_site_with_meta(self, meta):
  172. self.site.config.mode = "production"
  173. self.site.config.plugins = ['hyde.ext.plugins.meta.MetaPlugin', 'hyde.ext.plugins.images.ImageThumbnailsPlugin']
  174. mlink = File(self.image_folder.child('meta.yaml'))
  175. meta_text = yaml.dump(meta, default_flow_style=False)
  176. mlink.write(meta_text)
  177. gen = Generator(self.site)
  178. gen.generate_all()
  179. def _test_generic_thumbnails(self, meta):
  180. self._generate_site_with_meta(meta)
  181. thumb_meta = meta.get('thumbnails', [])
  182. for th in thumb_meta:
  183. prefix = th.get('prefix')
  184. if prefix is None:
  185. continue
  186. for fn in [PORTRAIT_IMAGE, LANDSCAPE_IMAGE]:
  187. f = File(self._deployed_image(prefix, fn))
  188. assert f.exists
  189. def _deployed_image(self, prefix, filename):
  190. return self.site.config.deploy_root_path.child('media/img/%s%s'%(prefix,filename))
  191. def test_width(self):
  192. prefix='thumb_'
  193. meta = dict(thumbnails=[dict(width=50, prefix=prefix, include=['*.jpg'])])
  194. self._test_generic_thumbnails(meta)
  195. for fn in IMAGES:
  196. im = Image.open(self._deployed_image(prefix, fn))
  197. assert im.size[0] == 50
  198. def test_height(self):
  199. prefix='thumb_'
  200. meta = dict(thumbnails=[dict(height=50, prefix=prefix, include=['*.jpg'])])
  201. self._test_generic_thumbnails(meta)
  202. for fn in IMAGES:
  203. im = Image.open(self._deployed_image(prefix, fn))
  204. assert im.size[1] == 50
  205. def test_width_and_height(self):
  206. prefix='thumb_'
  207. meta = dict(thumbnails=[dict(width=50, height=50, prefix=prefix, include=['*.jpg'])])
  208. self._test_generic_thumbnails(meta)
  209. for fn in IMAGES:
  210. im = Image.open(self._deployed_image(prefix, fn))
  211. assert im.size[0] == 50
  212. assert im.size[1] == 50
  213. def test_larger(self):
  214. prefix='thumb_'
  215. meta = dict(thumbnails=[dict(larger=50, prefix=prefix, include=['*.jpg'])])
  216. self._test_generic_thumbnails(meta)
  217. im = Image.open(self._deployed_image(prefix, PORTRAIT_IMAGE))
  218. assert im.size[1] == 50
  219. im = Image.open(self._deployed_image(prefix, LANDSCAPE_IMAGE))
  220. assert im.size[0] == 50
  221. def test_smaller(self):
  222. prefix='thumb_'
  223. meta = dict(thumbnails=[dict(smaller=50, prefix=prefix, include=['*.jpg'])])
  224. self._test_generic_thumbnails(meta)
  225. im = Image.open(self._deployed_image(prefix, PORTRAIT_IMAGE))
  226. assert im.size[0] == 50
  227. im = Image.open(self._deployed_image(prefix, LANDSCAPE_IMAGE))
  228. assert im.size[1] == 50
  229. def test_larger_and_smaller(self):
  230. prefix='thumb_'
  231. meta = dict(thumbnails=[dict(larger=100, smaller=50, prefix=prefix, include=['*.jpg'])])
  232. self._test_generic_thumbnails(meta)
  233. im = Image.open(self._deployed_image(prefix, PORTRAIT_IMAGE))
  234. assert im.size[0] == 50
  235. assert im.size[1] == 100
  236. im = Image.open(self._deployed_image(prefix, LANDSCAPE_IMAGE))
  237. assert im.size[0] == 100
  238. assert im.size[1] == 50