tests.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. from __future__ import division, unicode_literals
  2. from django.template import Context
  3. from django.template import Template
  4. from future.utils import native_str
  5. from unittest import skipUnless
  6. from django.contrib.contenttypes.models import ContentType
  7. from django.core.urlresolvers import reverse
  8. from mezzanine.blog.models import BlogPost
  9. from mezzanine.conf import settings
  10. from mezzanine.core.models import CONTENT_STATUS_PUBLISHED
  11. from mezzanine.generic.forms import RatingForm
  12. from mezzanine.generic.models import AssignedKeyword, Keyword, ThreadedComment
  13. from mezzanine.generic.views import comment
  14. from mezzanine.pages.models import RichTextPage
  15. from mezzanine.utils.tests import TestCase
  16. class GenericTests(TestCase):
  17. @skipUnless("mezzanine.blog" in settings.INSTALLED_APPS,
  18. "blog app required")
  19. def test_rating(self):
  20. """
  21. Test that ratings can be posted and avarage/count are calculated.
  22. """
  23. blog_post = BlogPost.objects.create(title="Ratings", user=self._user,
  24. status=CONTENT_STATUS_PUBLISHED)
  25. if settings.RATINGS_ACCOUNT_REQUIRED:
  26. self.client.login(username=self._username, password=self._password)
  27. data = RatingForm(None, blog_post).initial
  28. for value in settings.RATINGS_RANGE:
  29. data["value"] = value
  30. response = self.client.post(reverse("rating"), data=data)
  31. # Django doesn't seem to support unicode cookie keys correctly on
  32. # Python 2. See https://code.djangoproject.com/ticket/19802
  33. response.delete_cookie(native_str("mezzanine-rating"))
  34. blog_post = BlogPost.objects.get(id=blog_post.id)
  35. count = len(settings.RATINGS_RANGE)
  36. _sum = sum(settings.RATINGS_RANGE)
  37. average = _sum / count
  38. if settings.RATINGS_ACCOUNT_REQUIRED:
  39. self.assertEqual(blog_post.rating_count, 1)
  40. self.assertEqual(blog_post.rating_sum,
  41. settings.RATINGS_RANGE[-1])
  42. self.assertEqual(blog_post.rating_average,
  43. settings.RATINGS_RANGE[-1] / 1)
  44. else:
  45. self.assertEqual(blog_post.rating_count, count)
  46. self.assertEqual(blog_post.rating_sum, _sum)
  47. self.assertEqual(blog_post.rating_average, average)
  48. @skipUnless("mezzanine.blog" in settings.INSTALLED_APPS,
  49. "blog app required")
  50. def test_comment_ratings(self):
  51. """
  52. Test that a generic relation defined on one of Mezzanine's generic
  53. models (in this case ratings of comments) correctly sets its
  54. extra fields.
  55. """
  56. blog_post = BlogPost.objects.create(title="Post with comments",
  57. user=self._user)
  58. content_type = ContentType.objects.get_for_model(blog_post)
  59. kwargs = {"content_type": content_type, "object_pk": blog_post.id,
  60. "site_id": settings.SITE_ID, "comment": "First!!!11"}
  61. comment = ThreadedComment.objects.create(**kwargs)
  62. comment.rating.create(value=settings.RATINGS_RANGE[0])
  63. comment.rating.create(value=settings.RATINGS_RANGE[-1])
  64. comment = ThreadedComment.objects.get(pk=comment.pk)
  65. self.assertEqual(len(comment.rating.all()), comment.rating_count)
  66. self.assertEqual(
  67. comment.rating_average,
  68. (settings.RATINGS_RANGE[0] + settings.RATINGS_RANGE[-1]) / 2)
  69. @skipUnless("mezzanine.blog" in settings.INSTALLED_APPS,
  70. "blog app required")
  71. def test_comment_queries(self):
  72. """
  73. Test that rendering comments executes the same number of
  74. queries, regardless of the number of nested replies.
  75. """
  76. blog_post = BlogPost.objects.create(title="Post", user=self._user)
  77. content_type = ContentType.objects.get_for_model(blog_post)
  78. kwargs = {"content_type": content_type, "object_pk": blog_post.id,
  79. "site_id": settings.SITE_ID}
  80. template = "{% load comment_tags %}{% comment_thread blog_post %}"
  81. context = {
  82. "blog_post": blog_post,
  83. "posted_comment_form": None,
  84. "unposted_comment_form": None,
  85. }
  86. if settings.COMMENTS_ACCOUNT_REQUIRED:
  87. self.queries_used_for_template(template, **context)
  88. before = self.queries_used_for_template(template, **context)
  89. self.assertTrue(before > 0)
  90. self.create_recursive_objects(ThreadedComment, "replied_to", **kwargs)
  91. after = self.queries_used_for_template(template, **context)
  92. self.assertEqual(before, after)
  93. @skipUnless("mezzanine.pages" in settings.INSTALLED_APPS,
  94. "pages app required")
  95. def test_keywords(self):
  96. """
  97. Test that the keywords_string field is correctly populated.
  98. """
  99. page = RichTextPage.objects.create(title="test keywords")
  100. keywords = set(["how", "now", "brown", "cow"])
  101. Keyword.objects.all().delete()
  102. for keyword in keywords:
  103. keyword_id = Keyword.objects.get_or_create(title=keyword)[0].id
  104. page.keywords.get_or_create(keyword_id=keyword_id)
  105. page = RichTextPage.objects.get(id=page.id)
  106. self.assertEqual(keywords, set(page.keywords_string.split()))
  107. # Test removal.
  108. first = Keyword.objects.all()[0]
  109. keywords.remove(first.title)
  110. first.delete()
  111. page = RichTextPage.objects.get(id=page.id)
  112. self.assertEqual(keywords, set(page.keywords_string.split()))
  113. page.delete()
  114. def test_delete_unused(self):
  115. """
  116. Only ``Keyword`` instances without any assignments should be deleted.
  117. """
  118. assigned_keyword = Keyword.objects.create(title="assigned")
  119. Keyword.objects.create(title="unassigned")
  120. AssignedKeyword.objects.create(keyword_id=assigned_keyword.id,
  121. content_object=RichTextPage(pk=1))
  122. Keyword.objects.delete_unused(keyword_ids=[assigned_keyword.id])
  123. self.assertEqual(Keyword.objects.count(), 2)
  124. Keyword.objects.delete_unused()
  125. self.assertEqual(Keyword.objects.count(), 1)
  126. self.assertEqual(Keyword.objects.all()[0].id, assigned_keyword.id)
  127. def test_comment_form_returns_400_when_missing_data(self):
  128. """
  129. Assert 400 status code response when expected data is missing from
  130. the comment form. This simulates typical malicious bot behavior.
  131. """
  132. request = self._request_factory.post(reverse('comment'))
  133. if settings.COMMENTS_ACCOUNT_REQUIRED:
  134. request.user = self._user
  135. request.session = {}
  136. response = comment(request)
  137. self.assertEquals(response.status_code, 400)
  138. def test_multiple_comment_forms(self):
  139. template = Template("""
  140. {% load comment_tags %}
  141. {% comments_for post1 %}
  142. {% comments_for post2 %}
  143. """)
  144. request = self._request_factory.get(reverse('comment'))
  145. request.user = self._user
  146. context = {
  147. 'post1': BlogPost.objects.create(title="Post #1", user=self._user),
  148. 'post2': BlogPost.objects.create(title="Post #2", user=self._user),
  149. 'request': request,
  150. }
  151. result = template.render(Context(context))
  152. self.assertIn(
  153. '<input id="id_object_pk" name="object_pk" '
  154. 'type="hidden" value="%d" />' % context['post2'].pk,
  155. result
  156. )