test_avatars.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. from path import Path
  2. from PIL import Image
  3. from django.contrib.auth import get_user_model
  4. from django.core.exceptions import ValidationError
  5. from django.test import TestCase
  6. from misago.conf import settings
  7. from ..avatars import dynamic, gallery, gravatar, store, uploaded
  8. from ..models import Avatar, AvatarGallery
  9. class AvatarsStoreTests(TestCase):
  10. def test_store(self):
  11. """store successfully stores and deletes avatar"""
  12. User = get_user_model()
  13. user = User.objects.create_user('Bob', 'bob@bob.com', 'pass123')
  14. test_image = Image.new("RGBA", (100, 100), 0)
  15. store.store_new_avatar(user, test_image)
  16. # reload user
  17. test_user = User.objects.get(pk=user.pk)
  18. # assert that avatars were stored in media
  19. avatars_dict = {}
  20. for avatar in user.avatar_set.all():
  21. self.assertTrue(avatar.image.url)
  22. self.assertEqual(avatar.url, avatar.image.url)
  23. avatars_dict[avatar.size] = avatar
  24. # asserts that user.avatars cache was set
  25. self.assertEqual(len(avatars_dict), len(settings.MISAGO_AVATARS_SIZES))
  26. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  27. self.assertEqual(len(user.avatars), len(avatars_dict))
  28. for avatar in user.avatars:
  29. self.assertIn(avatar['size'], settings.MISAGO_AVATARS_SIZES)
  30. self.assertEqual(avatar['url'], avatars_dict[avatar['size']].url)
  31. # another avatar change deleted old avatars
  32. store.store_new_avatar(user, test_image)
  33. for old_avatar in avatars_dict.values():
  34. avatar_path = Path(old_avatar.image.path)
  35. self.assertFalse(avatar_path.exists())
  36. self.assertFalse(avatar_path.isfile())
  37. with self.assertRaises(Avatar.DoesNotExist):
  38. Avatar.objects.get(pk=old_avatar.pk)
  39. # and updated user avatars again
  40. new_avatars_dict = {}
  41. for size in settings.MISAGO_AVATARS_SIZES:
  42. avatar = user.avatar_set.get(size=size)
  43. self.assertTrue(avatar.image.url)
  44. self.assertEqual(avatar.url, avatar.image.url)
  45. new_avatars_dict[size] = avatar
  46. self.assertTrue(avatars_dict != new_avatars_dict)
  47. # asserts that user.avatars cache was updated
  48. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  49. for avatar in user.avatars:
  50. self.assertIn(avatar['size'], settings.MISAGO_AVATARS_SIZES)
  51. self.assertEqual(avatar['url'], new_avatars_dict[avatar['size']].url)
  52. # delete avatar
  53. store.delete_avatar(user)
  54. for removed_avatar in new_avatars_dict.values():
  55. avatar_path = Path(removed_avatar.image.path)
  56. self.assertFalse(avatar_path.exists())
  57. self.assertFalse(avatar_path.isfile())
  58. with self.assertRaises(Avatar.DoesNotExist):
  59. Avatar.objects.get(pk=removed_avatar.pk)
  60. class AvatarSetterTests(TestCase):
  61. def setUp(self):
  62. User = get_user_model()
  63. self.user = User.objects.create_user(
  64. 'Bob', 'kontakt@rpiton.com', 'pass123')
  65. self.user.avatars = None
  66. self.user.save()
  67. def tearDown(self):
  68. store.delete_avatar(self.user)
  69. def get_current_user(self):
  70. User = get_user_model()
  71. return User.objects.get(pk=self.user.pk)
  72. def assertNoAvatarIsSet(self):
  73. user = self.get_current_user()
  74. self.assertFalse(user.avatars)
  75. def assertAvatarWasSet(self):
  76. user = self.get_current_user()
  77. avatars_dict = {}
  78. for avatar in user.avatar_set.all():
  79. avatar_path = Path(avatar.image.path)
  80. self.assertTrue(avatar_path.exists())
  81. self.assertTrue(avatar_path.isfile())
  82. avatars_dict[avatar.size] = avatar
  83. self.assertEqual(len(user.avatars), len(avatars_dict))
  84. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  85. def test_dynamic_avatar(self):
  86. """dynamic avatar gets created"""
  87. self.assertNoAvatarIsSet()
  88. dynamic.set_avatar(self.user)
  89. self.assertAvatarWasSet()
  90. def test_random_gallery_avatar_no_gallery(self):
  91. """runtime error is raised when no gallery exists"""
  92. with self.assertRaises(RuntimeError):
  93. gallery.set_random_avatar(self.user)
  94. def test_random_gallery_avatar(self):
  95. """dynamic avatar gets created"""
  96. gallery.load_avatar_galleries()
  97. self.assertNoAvatarIsSet()
  98. gallery.set_random_avatar(self.user)
  99. self.assertAvatarWasSet()
  100. def test_selected_gallery_avatar(self):
  101. """dynamic avatar gets created"""
  102. gallery.load_avatar_galleries()
  103. self.assertNoAvatarIsSet()
  104. test_avatar = AvatarGallery.objects.order_by('id').last()
  105. gallery.set_avatar(self.user, test_avatar)
  106. self.assertAvatarWasSet()
  107. def test_gravatar(self):
  108. """dynamic avatar gets created"""
  109. self.assertNoAvatarIsSet()
  110. gravatar.set_avatar(self.user)
  111. self.assertAvatarWasSet()
  112. class MockAvatarFile(object):
  113. def __init__(self, size=None, name=None, mime=None):
  114. self.size = size
  115. self.name = name
  116. self.content_type = mime
  117. class UploadedAvatarTests(TestCase):
  118. def test_clean_crop(self):
  119. """crop validation and cleaning"""
  120. image = Image.new("RGBA", (200, 200), 0)
  121. with self.assertRaises(ValidationError):
  122. uploaded.clean_crop(image, "abc")
  123. with self.assertRaises(ValidationError):
  124. uploaded.clean_crop(image, {})
  125. with self.assertRaises(ValidationError):
  126. uploaded.clean_crop(image, {'offset': {'x': 'ugabuga'}})
  127. with self.assertRaises(ValidationError):
  128. uploaded.clean_crop(image, {
  129. 'offset': {
  130. 'x': 0,
  131. 'y': 0,
  132. },
  133. 'zoom': -2
  134. })
  135. with self.assertRaises(ValidationError):
  136. uploaded.clean_crop(image, {
  137. 'offset': {
  138. 'x': 0,
  139. 'y': 0,
  140. },
  141. 'zoom': 2
  142. })
  143. def test_uploaded_image_size_validation(self):
  144. """uploaded image size is validated"""
  145. image = MockAvatarFile(size=settings.avatar_upload_limit * 2024)
  146. with self.assertRaises(ValidationError):
  147. uploaded.validate_file_size(image)
  148. image = MockAvatarFile(size=settings.avatar_upload_limit * 1000)
  149. uploaded.validate_file_size(image)
  150. def test_uploaded_image_extension_validation(self):
  151. """uploaded image extension is validated"""
  152. for invalid_extension in ('.txt', '.zip', '.py', '.tiff'):
  153. with self.assertRaises(ValidationError):
  154. image = MockAvatarFile(name='test%s' % invalid_extension)
  155. uploaded.validate_extension(image)
  156. for valid_extension in uploaded.ALLOWED_EXTENSIONS:
  157. image = MockAvatarFile(name='test%s' % valid_extension)
  158. uploaded.validate_extension(image)
  159. def test_uploaded_image_mime_validation(self):
  160. """uploaded image mime type is validated"""
  161. image = MockAvatarFile(mime='fake/mime')
  162. with self.assertRaises(ValidationError):
  163. uploaded.validate_mime(image)
  164. for valid_mime in uploaded.ALLOWED_MIME_TYPES:
  165. image = MockAvatarFile(mime=valid_mime)
  166. uploaded.validate_mime(image)