From bdfdea180680b0f83730e4fdf350eed5411b539e Mon Sep 17 00:00:00 2001 From: abhiabhi94 <13880786+abhiabhi94@users.noreply.github.com> Date: Tue, 30 Mar 2021 19:51:25 +0530 Subject: [PATCH] ref: Refactor tests for better debugging - almost all tests now aim to tests just one thing. - make namesapce for DRF URLs consistent with that used for django. - change use of raw URLs in the codebase to use url names. --- comment/api/urls.py | 14 +- comment/models/flags.py | 2 +- comment/service/email.py | 2 +- comment/tests/base.py | 18 + comment/tests/test_api/test_permissions.py | 164 +++++ comment/tests/test_api/test_serializers.py | 88 ++- comment/tests/test_api/test_views.py | 605 +++++++++--------- comment/tests/test_mixins.py | 32 +- comment/tests/test_models/test_comments.py | 169 +++-- comment/tests/test_models/test_flags.py | 194 +++--- comment/tests/test_models/test_followers.py | 9 +- comment/tests/test_models/test_reactions.py | 10 + comment/tests/test_service.py | 24 +- comment/tests/test_signals.py | 11 + comment/tests/test_template_tags.py | 183 +++--- comment/tests/test_utils.py | 130 ++-- comment/tests/test_validators.py | 14 +- comment/tests/test_views/test_comments.py | 14 + comment/tests/test_views/test_flags.py | 13 + comment/tests/test_views/test_reactions.py | 8 + comment/tests/test_views/test_subscription.py | 7 +- 21 files changed, 1051 insertions(+), 660 deletions(-) create mode 100644 comment/tests/test_api/test_permissions.py diff --git a/comment/api/urls.py b/comment/api/urls.py index 956f0b0..4f86c7a 100644 --- a/comment/api/urls.py +++ b/comment/api/urls.py @@ -3,16 +3,18 @@ from comment.api import views +app_name = 'comment-api' + urlpatterns = [ - path('comments/', views.CommentList.as_view(), name='comments-list'), - path('comments/create/', views.CommentCreate.as_view(), name='comments-create'), - path('comments//', views.CommentDetail.as_view(), name='comment-detail'), - path('comments//react//', views.CommentDetailForReaction.as_view(), name='comments-react'), - path('comments//flag/', views.CommentDetailForFlag.as_view(), name='comments-flag'), + path('comments/', views.CommentList.as_view(), name='list'), + path('comments/create/', views.CommentCreate.as_view(), name='create'), + path('comments//', views.CommentDetail.as_view(), name='detail'), + path('comments//react//', views.CommentDetailForReaction.as_view(), name='react'), + path('comments//flag/', views.CommentDetailForFlag.as_view(), name='flag'), path( 'comments//flag/state/change/', views.CommentDetailForFlagStateChange.as_view(), - name='comments-flag-state-change' + name='flag-state-change' ), re_path(r'^comments/confirm/(?P[^/]+)/$', views.ConfirmComment.as_view(), name='confirm-comment'), path('comments/toggle-subscription/', views.ToggleFollowAPI.as_view(), name='toggle-subscription'), diff --git a/comment/models/flags.py b/comment/models/flags.py index 63480a9..adef866 100644 --- a/comment/models/flags.py +++ b/comment/models/flags.py @@ -88,7 +88,7 @@ def toggle_state(self, state, moderator): self.save() def toggle_flagged_state(self): - allowed_flags = getattr(settings, 'COMMENT_FLAGS_ALLOWED', 0) + allowed_flags = settings.COMMENT_FLAGS_ALLOWED if not allowed_flags: return self.refresh_from_db() diff --git a/comment/service/email.py b/comment/service/email.py index 5d16171..1c0071a 100644 --- a/comment/service/email.py +++ b/comment/service/email.py @@ -53,7 +53,7 @@ def send_confirmation_request(self, api=False): html_template = 'comment/anonymous/confirmation_request.html' subject = EmailInfo.CONFIRMATION_SUBJECT if api: - confirmation_url = f'/api/comments/confirm/{key}/' + confirmation_url = reverse('comment-api:confirm-comment', args=[key]) else: confirmation_url = reverse('comment:confirm-comment', args=[key]) diff --git a/comment/tests/base.py b/comment/tests/base.py index c66c741..676649e 100644 --- a/comment/tests/base.py +++ b/comment/tests/base.py @@ -217,6 +217,24 @@ def transform(x): return super().assertQuerysetEqual(qs, values, transform=transform, ordered=True, msg=msg) +class BaseAPITest(BaseCommentTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.comment = cls.create_comment(cls.content_object_1) + cls.comment_1 = cls.create_comment(cls.content_object_1) + cls.comment_2 = cls.create_comment(cls.content_object_1) + cls.comment_3 = cls.create_comment(cls.content_object_1) + cls.comment_4 = cls.create_comment(cls.content_object_1, parent=cls.comment_1) + cls.reaction_1 = cls.create_reaction_instance(cls.user_1, cls.comment_1, 'like') + + cls.comment_5 = cls.create_comment(cls.content_object_2) + cls.comment_6 = cls.create_comment(cls.content_object_2) + cls.comment_7 = cls.create_comment(cls.content_object_2, parent=cls.comment_5) + cls.comment_8 = cls.create_comment(cls.content_object_2, parent=cls.comment_5) + cls.reaction_2 = cls.create_reaction_instance(cls.user_1, cls.comment_5, 'dislike') + + class BaseCommentManagerTest(BaseCommentTest): content_object_2 = None diff --git a/comment/tests/test_api/test_permissions.py b/comment/tests/test_api/test_permissions.py new file mode 100644 index 0000000..9e01fb9 --- /dev/null +++ b/comment/tests/test_api/test_permissions.py @@ -0,0 +1,164 @@ +from unittest.mock import patch + +from django.test import RequestFactory + +from comment.tests.test_api.test_views import BaseAPITest +from comment.api.permissions import ( + IsOwnerOrReadOnly, FlagEnabledPermission, CanChangeFlaggedCommentState, SubscriptionEnabled, + CanGetSubscribers) +from comment.api.views import CommentList +from comment.models import FlagInstanceManager +from comment.conf import settings + + +class BaseAPIPermissionsTest(BaseAPITest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.factory = RequestFactory() + + def setUp(self): + super().setUp() + self.view = CommentList() + + +class OwnerPermissionTest(BaseAPIPermissionsTest): + def setUp(self): + super().setUp() + self.permission = IsOwnerOrReadOnly() + + def test_get_request(self): + request = self.factory.get('/') + + self.assertTrue(self.permission.has_object_permission(request, self.view, self.comment_1)) + + def test_put_method_from_different_user(self): + request = self.factory.put('/') + request.user = self.user_2 + self.assertEqual(self.comment_1.user, self.user_1) + + self.assertFalse(self.permission.has_object_permission(request, self.view, self.comment_1)) + + def test_put_method_from_admin(self): + request = self.factory.put('/') + request.user = self.admin + self.assertEqual(self.comment_1.user, self.user_1) + + self.assertFalse(self.permission.has_object_permission(request, self.view, self.comment_1)) + + def test_put_method_from_same_user(self): + request = self.factory.put('/') + request.user = self.user_1 + self.assertEqual(self.comment_1.user, self.user_1) + + self.assertTrue(self.permission.has_object_permission(request, self.view, self.comment_1)) + + +class FlagEnabledPermissionTest(BaseAPIPermissionsTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.request = cls.factory.get('/') + + def setUp(self): + super().setUp() + self.permission = FlagEnabledPermission() + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0) + def test_flagging_disabled(self): + self.assertIs(False, self.permission.has_permission(self.request, self.view)) + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) + def test_flagging_enabled(self): + self.assertIs(True, self.permission.has_permission(self.request, self.view)) + + +class CanChangeFlaggedCommentStateTest(BaseAPIPermissionsTest): + @classmethod + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) + def setUpTestData(cls): + super().setUpTestData() + cls.flag_data = { + 'reason': FlagInstanceManager.reason_values[0], + 'info': '', + } + cls.create_flag_instance(cls.user_1, cls.comment_1, **cls.flag_data) + cls.create_flag_instance(cls.user_2, cls.comment_1, **cls.flag_data) + cls.comment_1.flag.refresh_from_db() + cls.flagged_comment = cls.comment_1 + cls.unflagged_comment = cls.comment_2 + + def setUp(self): + super().setUp() + self.permission = CanChangeFlaggedCommentState() + self.request = self.factory.get('/') + self.request.user = self.user_1 + + def test_normal_user(self): + self.assertFalse(self.permission.has_permission(self.request, self.view)) + + def test_moderator(self): + self.request.user = self.moderator + + self.assertTrue(self.permission.has_permission(self.request, self.view)) + + def test_moderator_for_unflagged_comment(self): + self.request.user = self.moderator + + self.assertFalse( + self.permission.has_object_permission(self.request, self.view, self.unflagged_comment) + ) + + def test_moderator_for_flagged_comment(self): + self.request.user = self.moderator + + self.assertIs( + True, + self.permission.has_object_permission(self.request, self.view, self.flagged_comment) + ) + + def test_normal_user_for_flagged_comment(self): + self.assertIs( + False, + self.permission.has_object_permission(self.request, self.view, self.flagged_comment) + ) + + +class CanGetSubscribersTest(BaseAPIPermissionsTest): + def setUp(self): + super().setUp() + self.permission = CanGetSubscribers() + self.request = self.factory.get('/') + + @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) + def test_normal_users_cannot_retrieve_subscribers(self): + self.request.user = self.user_1 + + self.assertFalse(self.permission.has_permission(self.request, self.view)) + + @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) + def test_only_moderators_can_retrieve_subscribers(self): + self.request.user = self.moderator + + self.assertTrue(self.permission.has_permission(self.request, self.view)) + + @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) + def test_cannot_retrieve_subscribers_when_system_disabled(self): + self.request.user = self.moderator + + self.assertFalse(self.permission.has_permission(self.request, self.view)) + + +class SubscriptionEnabledTest(BaseAPIPermissionsTest): + def setUp(self): + super().setUp() + self.request = self.factory.post('/') + self.permission = SubscriptionEnabled() + + @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) + def test_when_subscription_disabled(self): + self.assertFalse(self.permission.has_permission(self.request, self.view)) + + @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) + def test_when_permission(self): + self.assertTrue(self.permission.has_permission(self.request, self.view)) diff --git a/comment/tests/test_api/test_serializers.py b/comment/tests/test_api/test_serializers.py index cb744d2..ccb3cc8 100644 --- a/comment/tests/test_api/test_serializers.py +++ b/comment/tests/test_api/test_serializers.py @@ -7,10 +7,10 @@ from comment.models import Comment, Follower from comment.api.serializers import get_profile_model, get_user_fields, UserSerializerDAB, CommentCreateSerializer, \ CommentSerializer -from comment.tests.test_api.test_views import APIBaseTest +from comment.tests.test_api.test_views import BaseAPITest -class APICommentSerializers(APIBaseTest): +class APICommentSerializersTest(BaseAPITest): def setUp(self): super().setUp() self.parent_count = Comment.objects.filter_parents_by_object(self.post_1).count() @@ -25,48 +25,9 @@ def comment_count_test(self): self.assertEqual(Comment.objects.filter_parents_by_object(self.post_1).count(), self.parent_count) self.assertEqual(Comment.objects.all().count(), self.all_count) - def test_get_profile_model(self): - # missing settings attrs - with patch.object(settings, 'PROFILE_APP_NAME', None): - profile = get_profile_model() - self.assertIsNone(profile) - - # providing wrong attribute value, an exception is raised - with patch.object(settings, 'PROFILE_APP_NAME', 'wrong'): - self.assertRaises(LookupError, get_profile_model) - - # attribute value is None - with patch.object(settings, 'PROFILE_APP_NAME', None): - profile = get_profile_model() - self.assertIsNone(profile) - - # success - with patch.object(settings, 'PROFILE_APP_NAME', 'user_profile'): - profile = get_profile_model() - self.assertIsNotNone(profile) - - def test_user_serializer(self): - # PROFILE_MODEL_NAME not provided - with patch.object(settings, 'PROFILE_MODEL_NAME', None): - profile = UserSerializerDAB.get_profile(self.user_1) - self.assertIsNone(profile) - - # PROFILE_MODEL_NAME is wrong - with patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong'): - profile = UserSerializerDAB.get_profile(self.user_1) - self.assertIsNone(profile) - - # success - with patch.object(settings, 'PROFILE_MODEL_NAME', 'userprofile'): - profile = UserSerializerDAB.get_profile(self.user_1) - self.assertIsNotNone(profile) - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', False) def test_create_parent_comment_serializer(self): - self.assertEqual(self.parent_count, 3) - self.assertEqual(self.all_count, 8) - factory = RequestFactory() request = factory.get('/') request.user = self.user_1 @@ -96,9 +57,6 @@ def test_create_parent_comment_serializer(self): @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', False) def test_create_child_comment_serializer(self): - self.assertEqual(self.parent_count, 3) - self.assertEqual(self.all_count, 8) - factory = RequestFactory() request = factory.get('/') request.user = self.user_1 @@ -188,9 +146,10 @@ def test_passing_context_to_serializer(self): self.assertTrue(serializer.fields['content'].read_only) -class TestProfileSerializer(APIBaseTest): +class TestProfileSerializer(BaseAPITest): def test_default_fields(self): fields = get_user_fields() + self.assertSetEqual(set(fields), set(settings.COMMENT_USER_API_FIELDS + ['profile'])) @patch('comment.api.serializers.isinstance') @@ -199,4 +158,43 @@ def test_has_image_field(self, mocked_hasattr, mocked_isinstance): mocked_isinstance.return_value = True mocked_hasattr.return_value = True fields = get_user_fields() + self.assertIs('logentry' in fields, True) + + +class GetProfileTest(BaseAPITest): + @patch.object(settings, 'PROFILE_APP_NAME', None) + def test_setting_attribute_not_set(self): + profile = get_profile_model() + + self.assertIsNone(profile) + + @patch.object(settings, 'PROFILE_APP_NAME', 'wrong') + def test_setting_attribute_set_wrong(self): + self.assertRaises(LookupError, get_profile_model) + + @patch.object(settings, 'PROFILE_APP_NAME', 'user_profile') + def tests_success(self): + profile = get_profile_model() + + self.assertIsNotNone(profile) + + +class TestUserSerializer(BaseAPITest): + @patch.object(settings, 'PROFILE_MODEL_NAME', None) + def test_profile_model_name_not_provided(self): + profile = UserSerializerDAB.get_profile(self.user_1) + + self.assertIsNone(profile) + + @patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong') + def test_profile_model_wrong(self): + profile = UserSerializerDAB.get_profile(self.user_1) + + self.assertIsNone(profile) + + @patch.object(settings, 'PROFILE_MODEL_NAME', 'userprofile') + def test_success(self): + profile = UserSerializerDAB.get_profile(self.user_1) + + self.assertIsNotNone(profile) diff --git a/comment/tests/test_api/test_views.py b/comment/tests/test_api/test_views.py index 02b5e19..00147e4 100644 --- a/comment/tests/test_api/test_views.py +++ b/comment/tests/test_api/test_views.py @@ -1,166 +1,19 @@ from time import sleep from unittest.mock import patch -from django.test import RequestFactory from django.core import signing, mail - +from django.urls import reverse_lazy from rest_framework import status from comment.conf import settings -from comment.models import Comment, FlagInstanceManager -from comment.messages import ContentTypeError, EmailError +from comment.models import Comment, FlagInstanceManager, ReactionInstance +from comment.messages import ContentTypeError, EmailError, ReactionError from comment.api.serializers import CommentSerializer -from comment.api.permissions import ( - IsOwnerOrReadOnly, FlagEnabledPermission, CanChangeFlaggedCommentState, SubscriptionEnabled, - CanGetSubscribers) -from comment.api.views import CommentList -from comment.tests.base import BaseCommentTest, timezone +from comment.tests.base import BaseAPITest, timezone from comment.tests.test_utils import BaseAnonymousCommentTest -from comment.utils import is_comment_admin, is_comment_moderator - - -class APIBaseTest(BaseCommentTest): - @classmethod - def setUpTestData(cls): - super().setUpTestData() - cls.comment_1 = cls.create_comment(cls.content_object_1) - cls.comment_2 = cls.create_comment(cls.content_object_1) - cls.comment_3 = cls.create_comment(cls.content_object_1) - cls.comment_4 = cls.create_comment(cls.content_object_1, parent=cls.comment_1) - cls.reaction_1 = cls.create_reaction_instance(cls.user_1, cls.comment_1, 'like') - - cls.comment_5 = cls.create_comment(cls.content_object_2) - cls.comment_6 = cls.create_comment(cls.content_object_2) - cls.comment_7 = cls.create_comment(cls.content_object_2, parent=cls.comment_5) - cls.comment_8 = cls.create_comment(cls.content_object_2, parent=cls.comment_5) - cls.reaction_2 = cls.create_reaction_instance(cls.user_1, cls.comment_5, 'dislike') - - def setUp(self): - super().setUp() - self.addCleanup(patch.stopall) - - -class APIPermissionsTest(APIBaseTest): - def setUp(self): - super().setUp() - self.owner_permission = IsOwnerOrReadOnly() - self.flag_enabled_permission = FlagEnabledPermission() - self.can_change_flagged_comment_state = CanChangeFlaggedCommentState() - self.subscription_enabled = SubscriptionEnabled() - self.get_subscribers_permission = CanGetSubscribers() - self.factory = RequestFactory() - self.view = CommentList() - - @classmethod - def setUpTestData(cls): - super().setUpTestData() - cls.flag_data = { - 'reason': FlagInstanceManager.reason_values[0], - 'info': '', - } - cls.create_flag_instance(cls.user_1, cls.comment_1, **cls.flag_data) - cls.create_flag_instance(cls.user_2, cls.comment_1, **cls.flag_data) - - def test_owner_permission(self): - # self.client.login(username='test-2', password='1234') - request = self.factory.get('/') - # get is in the safe methods - self.assertTrue(self.owner_permission.has_object_permission(request, self.view, self.comment_1)) - - # PUT method from different user - request = self.factory.put('/') - request.user = self.user_2 - self.assertEqual(self.comment_1.user, self.user_1) - self.assertFalse(self.owner_permission.has_object_permission(request, self.view, self.comment_1)) - - # DELETE method from admin - request = self.factory.put('/') - request.user = self.admin - self.assertEqual(self.comment_1.user, self.user_1) - self.assertFalse(self.owner_permission.has_object_permission(request, self.view, self.comment_1)) - - # PUT method from same user - request = self.factory.put('/') - request.user = self.user_1 - self.assertEqual(self.comment_1.user, self.user_1) - self.assertTrue(self.owner_permission.has_object_permission(request, self.view, self.comment_1)) - - def test_flag_enabled_permission(self): - request = self.factory.get('/') - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0): - self.assertIs(False, self.flag_enabled_permission.has_permission(request, self.view)) - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1): - self.assertIs(True, self.flag_enabled_permission.has_permission(request, self.view)) - - def test_can_change_flagged_comment_state(self): - request = self.factory.get('/') - user = self.user_1 - request.user = user # not moderator user - self.assertFalse(self.can_change_flagged_comment_state.has_permission(request, self.view)) - - user = self.moderator - request.user = user - self.assertTrue(self.can_change_flagged_comment_state.has_permission(request, self.view)) - - comment = self.comment_2 - self.assertFalse(comment.is_flagged) - self.assertFalse( - self.can_change_flagged_comment_state.has_object_permission(request, self.view, comment) - ) - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1): - self.set_flag(self.user_1, comment, **self.flag_data) - self.set_flag(self.user_2, comment, **self.flag_data) - self.assertIs(True, comment.is_flagged) - self.assertIs( - True, - self.can_change_flagged_comment_state.has_object_permission(request, self.view, comment) - ) - - request.user = self.user_1 - self.assertIs( - False, - self.can_change_flagged_comment_state.has_object_permission(request, self.view, comment) - ) - - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) - def test_normal_users_cannot_retrieve_subscribers(self): - request = self.factory.get('/') - request.user = self.user_1 - self.assertFalse(is_comment_admin(self.user_1)) - self.assertFalse(is_comment_moderator(self.user_1)) - self.assertTrue(settings.COMMENT_ALLOW_SUBSCRIPTION) - self.assertFalse(self.get_subscribers_permission.has_permission(request, self.view)) - - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) - def test_only_moderators_can_retrieve_subscribers(self): - request = self.factory.get('/') - request.user = self.moderator - self.assertTrue(is_comment_moderator(self.moderator)) - self.assertTrue(settings.COMMENT_ALLOW_SUBSCRIPTION) - self.assertTrue(self.get_subscribers_permission.has_permission(request, self.view)) - - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) - def test_cannot_retrieve_subscribers_when_system_disabled(self): - request = self.factory.get('/') - request.user = self.moderator - self.assertTrue(is_comment_moderator(self.moderator)) - self.assertFalse(settings.COMMENT_ALLOW_SUBSCRIPTION) - self.assertFalse(self.get_subscribers_permission.has_permission(request, self.view)) - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) - def test_cannot_subscribe_when_system_disabled(self): - request = self.factory.post('/') - self.assertFalse(settings.COMMENT_ALLOW_SUBSCRIPTION) - self.assertFalse(self.subscription_enabled.has_permission(request, self.view)) - - @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) - def test_can_subscribe(self): - request = self.factory.post('/') - self.assertTrue(settings.COMMENT_ALLOW_SUBSCRIPTION) - self.assertTrue(self.subscription_enabled.has_permission(request, self.view)) - -class APICommentViewsTest(APIBaseTest): +class BaseAPIViewTest(BaseAPITest): def setUp(self): super().setUp() self.url_data = { @@ -168,13 +21,14 @@ def setUp(self): 'app_name': 'post', 'model_id': 1 } - self.comment_count = Comment.objects.filter_parents_by_object(self.post_1).count() + self.parents = Comment.objects.filter_parents_by_object(self.post_1).count() self.all_comments = Comment.objects.all().count() + def get_base_url(self): + raise NotImplementedError + @staticmethod - def get_url(base_url=None, **kwargs): - if not base_url: - base_url = '/api/comments/' + def get_url(base_url, **kwargs): if kwargs: base_url += '?' for (key, val) in kwargs.items(): @@ -183,77 +37,88 @@ def get_url(base_url=None, **kwargs): def increase_count(self, parent=False): if parent: - self.comment_count += 1 + self.parents += 1 self.all_comments += 1 def comment_count_test(self): - self.assertEqual(Comment.objects.filter_parents_by_object(self.post_1).count(), self.comment_count) + self.assertEqual(Comment.objects.filter_parents_by_object(self.post_1).count(), self.parents) self.assertEqual(Comment.objects.all().count(), self.all_comments) - def test_can_retrieve_comments_list(self): - response = self.client.get(self.get_url(**self.url_data)) + +class CommentListTest(BaseAPIViewTest): + @staticmethod + def get_base_url(): + return reverse_lazy('comment-api:list') + + def test_can_retrieve_all_comments(self): + response = self.client.get(self.get_url(self.get_base_url(), **self.url_data)) + self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.data), 3) # 3 parent comment, child comment will be nested in the parent. + self.assertEqual(len(response.data), self.parents) - def test_retrieving_comment_list_without_app_name(self): + def test_retrieving_without_app_name(self): data = self.url_data.copy() data.pop('app_name') - url = self.get_url(**data) + url = self.get_url(self.get_base_url(), **data) response = self.client.get(url) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.APP_NAME_MISSING) self.assertTextTranslated(response.data['detail'], url) - def test_retrieving_comment_list_without_model_name(self): + def test_retrieving_without_model_name(self): data = self.url_data.copy() data.pop('model_name') - url = self.get_url(**data) + url = self.get_url(self.get_base_url(), **data) response = self.client.get(url) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.MODEL_NAME_MISSING) self.assertTextTranslated(response.data['detail'], url) - def test_retrieving_comment_list_without_model_id(self): + def test_retrieving_without_model_id(self): url_data = self.url_data.copy() url_data.pop('model_id') - url = self.get_url(**url_data) + url = self.get_url(self.get_base_url(), **url_data) response = self.client.get(url) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.MODEL_ID_MISSING) self.assertTextTranslated(response.data['detail'], url) - def test_retrieving_comment_list_with_invalid_app_name(self): + def test_retrieving_with_invalid_app_name(self): data = self.url_data.copy() app_name = 'invalid' data['app_name'] = app_name - url = self.get_url(**data) + url = self.get_url(self.get_base_url(), **data) response = self.client.get(url) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.APP_NAME_INVALID.format(app_name=app_name)) self.assertTextTranslated(response.data['detail'], url) - def test_retrieving_comment_list_with_invalid_model_name(self): - # not exist model type + def test_retrieving_with_invalid_model_name(self): url_data = self.url_data.copy() model_name = 'does_not_exists' url_data['model_name'] = model_name - url = self.get_url(**url_data) + url = self.get_url(self.get_base_url(), **url_data) + response = self.client.get(url) self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.MODEL_NAME_INVALID.format(model_name=model_name)) self.assertTextTranslated(response.data['detail'], url) - def test_retrieving_comment_list_with_invalid_model_id(self): - # not exist model id + def test_retrieving_with_non_exitsting_model_id(self): url_data = self.url_data.copy() model_id = 100 url_data['model_id'] = model_id - url = self.get_url(**url_data) + url = self.get_url(self.get_base_url(), **url_data) + response = self.client.get(url) self.assertEqual(response.status_code, 400) @@ -263,10 +128,12 @@ def test_retrieving_comment_list_with_invalid_model_id(self): ) self.assertTextTranslated(response.data['detail'], url) - # not integer model id + def test_retrieving_with_non_int_model_id(self): + url_data = self.url_data.copy() model_id = 'c' url_data['model_id'] = model_id - url = self.get_url(**url_data) + url = self.get_url(self.get_base_url(), **url_data) + response = self.client.get(url) self.assertEqual(response.status_code, 400) @@ -276,16 +143,17 @@ def test_retrieving_comment_list_with_invalid_model_id(self): ) self.assertTextTranslated(response.data['detail'], url) - def test_create_parent_comment(self): - # create parent comment - self.assertEqual(self.comment_count, 3) - self.assertEqual(self.all_comments, 8) - base_url = '/api/comments/create/' +class CommentCreateTest(BaseAPIViewTest): + def get_base_url(self): + return reverse_lazy('comment-api:create') + + def test_create_parent_comment(self): data = {'content': 'new parent comment from api'} url_data = self.url_data.copy() - response = self.client.post(self.get_url(base_url, **url_data), data=data) + response = self.client.post(self.get_url(self.get_base_url(), **url_data), data=data) + self.assertEqual(response.status_code, 201) comment_id = response.json()['id'] # test email in database for authenticated user @@ -294,40 +162,35 @@ def test_create_parent_comment(self): self.comment_count_test() def test_create_child_comment(self): - # create parent comment - self.assertEqual(self.comment_count, 3) - self.assertEqual(self.all_comments, 8) - - base_url = '/api/comments/create/' url_data = self.url_data.copy() - # create child comment url_data['parent_id'] = 1 data = {'content': 'new child comment from api'} - response = self.client.post(self.get_url(base_url, **url_data), data=data) + response = self.client.post(self.get_url(self.get_base_url(), **url_data), data=data) + self.assertEqual(response.status_code, 201) self.increase_count() self.comment_count_test() - # create comment with parent value = 0 + def create_parent_comment_with_parent_id_0(self): + url_data = self.url_data.copy() url_data['parent_id'] = 0 data = {'content': 'new comment from api'} - response = self.client.post(self.get_url(base_url, **url_data), data=data) + + response = self.client.post(self.get_url(self.get_base_url(), **url_data), data=data) + self.assertEqual(response.status_code, 201) self.increase_count(parent=True) self.comment_count_test() @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', True) - def test_create_comment_for_anonymous_with_invalid_data(self): - base_url = '/api/comments/create/' + def test_for_anonymous_with_invalid_data(self): + base_url = self.get_base_url() url_data = self.url_data.copy() - - # test anonymous commenting - self.client.logout() - - # test invalid data data = {'content': 'new anonymous comment from api', 'email': ''} url = self.get_url(base_url, **url_data) + self.client.logout() + response = self.client.post(url, data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -335,29 +198,27 @@ def test_create_comment_for_anonymous_with_invalid_data(self): self.assertTextTranslated(response.json()['email'][0], base_url) @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', True) - def test_create_comment_for_anonymous_with_valid_data(self): - base_url = '/api/comments/create/' + def test_for_anonymous_with_valid_data(self): url_data = self.url_data.copy() - url = self.get_url(base_url, **url_data) + url = self.get_url(self.get_base_url(), **url_data) - # test anonymous commenting self.client.logout() - # test valid data data = {'content': 'new anonymous comment from api', 'email': 'a@a.com'} response = self.client.post(url, data=data) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) # no count should change self.comment_count_test() - def test_cannot_create_child_comment(self): - # parent id not integer - base_url = '/api/comments/create/' + def test_parent_id_not_integer(self): + base_url = self.get_base_url() url_data = self.url_data.copy() parent_id = 'c' url_data['parent_id'] = parent_id data = {'content': 'new child comment from api'} + response = self.client.post(self.get_url(base_url, **url_data), data=data) self.assertEqual(response.status_code, 400) @@ -367,97 +228,154 @@ def test_cannot_create_child_comment(self): ) self.assertTextTranslated(response.data['detail'], base_url) - # parent id not exist + def test_parent_id_does_not_exist(self): + base_url = self.get_base_url() + url_data = self.url_data.copy() parent_id = 100 url_data['parent_id'] = parent_id data = {'content': 'new child comment from api'} + response = self.client.post(self.get_url(base_url, **url_data), data=data) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.PARENT_ID_INVALID.format(parent_id=parent_id)) self.assertTextTranslated(response.data['detail'], base_url) - # parent id doesn't belong to the model object + def test_parent_id_does_not_belong_to_model_object(self): + base_url = self.get_base_url() + url_data = self.url_data.copy() parent_id = 1 url_data.update({ 'parent_id': parent_id, 'model_id': 2 }) data = {'content': 'new child comment from api'} + response = self.client.post(self.get_url(base_url, **url_data), data=data) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], ContentTypeError.PARENT_ID_INVALID.format(parent_id=parent_id)) + self.assertTextTranslated(response.data['detail'], base_url) + + +class CommentDetailTest(BaseAPIViewTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.c_id = cls.create_comment(cls.content_object_1).id + + def get_base_url(self, c_id=None): + if not c_id: + c_id = self.c_id + return reverse_lazy('comment-api:detail', args=[c_id]) + + def test_retrieval(self): + response = self.client.get(self.get_base_url()) - def test_can_retrieve_update_delete_comment(self): - count = Comment.objects.all().count() - self.assertEqual(count, 8) - # retrieve - response = self.client.get('/api/comments/2/') self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['id'], 2) - self.assertEqual(response.data['content'], 'comment 2') + self.assertEqual(response.data['id'], self.c_id) + self.assertEqual(response.data['content'], Comment.objects.get(id=self.c_id).content) - # update + def test_update(self): data = {'content': 'updated comment'} - response = self.client.put('/api/comments/2/', data=data, content_type='application/json') + + response = self.client.put(self.get_base_url(), data=data, content_type='application/json') + self.assertEqual(response.status_code, 200) - self.assertEqual(response.data['id'], 2) + self.assertEqual(response.data['id'], self.c_id) self.assertEqual(response.data['content'], data['content']) - self.assertEqual(count, Comment.objects.all().count()) + self.assertEqual(self.all_comments, Comment.objects.all().count()) + + def test_delete_child(self): + c_id = Comment.objects.exclude(parent=None).first().id + response = self.client.delete(self.get_base_url(c_id)) - # delete - response = self.client.delete('/api/comments/2/') self.assertEqual(response.status_code, 204) - self.assertEqual(Comment.objects.all().count(), count - 1) + self.assertEqual(Comment.objects.all().count(), self.all_comments - 1) + def test_delete_parent(self): # delete parent will delete its children as well - count = Comment.objects.all().count() - self.assertEqual(count, 7) - comment = Comment.objects.get(id=1) - self.assertEqual(comment.replies().count(), 1) - response = self.client.delete('/api/comments/1/') + parent = Comment.objects.filter(parent=None).first() + reply_count = parent.replies().count() + + response = self.client.delete(self.get_base_url(parent.id)) + self.assertEqual(response.status_code, 204) - self.assertEqual(Comment.objects.all().count(), count - 2) + # test database change (1 is for the parent comment) + self.assertEqual(Comment.objects.all().count() + 1 + reply_count, self.all_comments) + + +class CommentDetailForReactionTest(BaseAPIViewTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.user = cls.user_1 + cls.comment = cls.create_comment(cls.content_object_1) + cls.like = ReactionInstance.ReactionType.LIKE.name.lower() + cls.dislike = ReactionInstance.ReactionType.DISLIKE.name.lower() + + def get_base_url(self, reaction, c_id=None): + if not c_id: + c_id = self.comment.id + return reverse_lazy('comment-api:react', args=[c_id, reaction]) + + def test_like(self): + response = self.client.post(self.get_base_url(self.like)) - def test_react_to_comment_success(self): - # post like - comment has no reaction - self.assertEqual(self.comment_3.likes, 0) - self.assertEqual(self.comment_3.dislikes, 0) - response = self.client.post(f'/api/comments/{self.comment_3.id}/react/like/') self.assertEqual(response.status_code, 200) - self.comment_3.reaction.refresh_from_db() - self.assertEqual(self.comment_3.likes, 1) - self.assertEqual(self.comment_3.dislikes, 0) + self.comment.reaction.refresh_from_db() + + self.assertEqual(self.comment.likes, 1) + self.assertEqual(self.comment.dislikes, 0) + + def test_dislike_on_liked_comment(self): + """user has already previously liked the same comment""" + self.create_reaction_instance(self.user, self.comment, self.like) + + response = self.client.post(self.get_base_url(self.dislike)) - # post dislike - comment is liked by the user - response = self.client.post(f'/api/comments/{self.comment_3.id}/react/dislike/') self.assertEqual(response.status_code, 200) - self.comment_3.reaction.refresh_from_db() - self.assertEqual(self.comment_3.likes, 0) - self.assertEqual(self.comment_3.dislikes, 1) + self.comment.reaction.refresh_from_db() + + self.assertEqual(self.comment.likes, 0) + self.assertEqual(self.comment.dislikes, 1) + + def test_dislike_on_disliked_comment(self): + """posting the same reaction twice remvoes the reaction""" + self.create_reaction_instance(self.user, self.comment, self.dislike) + + response = self.client.post(self.get_base_url(self.dislike)) - # post dislike - comment is disliked by the user => comment reaction is removed - response = self.client.post(f'/api/comments/{self.comment_3.id}/react/dislike/') self.assertEqual(response.status_code, 200) - self.comment_3.reaction.refresh_from_db() - self.assertEqual(self.comment_3.likes, 0) - self.assertEqual(self.comment_3.dislikes, 0) + self.comment.reaction.refresh_from_db() + + self.assertEqual(self.comment.likes, 0) + self.assertEqual(self.comment.dislikes, 0) + + def test_invalid_reaction_type(self): + reaction = 'invalid_type' + url = self.get_base_url(reaction) + + response = self.client.post(url) - def test_react_to_comment_with_invalid_reaction_type(self): - response = self.client.post(f'/api/comments/{self.comment_3.id}/react/invalid_type/') self.assertEqual(response.status_code, 400) + error, = response.data['detail'] -class APICommentFlagViewTest(APIBaseTest): + self.assertEqual(error, ReactionError.TYPE_INVALID.format(reaction_type=reaction)) + self.assertTextTranslated(error, url) - def get_url(self, c_id=None): + +class CommentDetailForFlagTest(BaseAPITest): + + def get_base_url(self, c_id=None): if not c_id: c_id = self.comment.id - return f'/api/comments/{c_id}/flag/' + return reverse_lazy('comment-api:flag', args=[c_id]) def setUp(self): super().setUp() - self.comment = self.comment_1 self.user = self.user_1 self.flag_data = { 'reason': FlagInstanceManager.reason_values[0], @@ -467,57 +385,65 @@ def setUp(self): @classmethod def setUpTestData(cls): super().setUpTestData() - cls.flag = cls.create_flag_instance(cls.user_2, cls.comment_2) + cls.comment = cls.create_comment(cls.content_object_1) - def test_flag_to_comment(self): + def test_flagging_unflagged_comment(self): comment = self.comment + # this is done as the flag object is deleted in one of the functions and hence sometimes has issues here. + comment.refresh_from_db() data = self.flag_data - # flag - comment has no flags - url = self.get_url() - self.assertEqual(comment.flag.count, 0) + url = self.get_base_url() + response = self.client.post(url, data=data) + self.assertEqual(response.status_code, 200) self.assertFalse(response.json()['is_flagged']) comment.flag.refresh_from_db() + self.assertEqual(comment.flag.count, 1) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0) def test_flag_comment_when_flagging_not_enabled(self): - comment = self.comment data = self.flag_data - url = self.get_url() - self.assertEqual(comment.flag.count, 0) + url = self.get_base_url() + response = self.client.post(url, data=data) + self.assertEqual(response.status_code, 403) - def test_unflag_to_comment(self): + def test_unflagging_a_flagged_comment(self): comment = self.comment_2 user = self.user_2 + self.create_flag_instance(user, comment) + self.client.force_login(user) - url = self.get_url(comment.id) - # un-flag - comment is flagged by the user and no reason is passed + url = self.get_base_url(comment.id) + response = self.client.post(url) + self.assertEqual(response.status_code, 200) comment.flag.refresh_from_db() self.assertEqual(comment.flag.count, 0) - def test_flag_to_previous_comments(self): - """Maintains backward compatibility""" + def test_flagging_previous_comments(self): + """Tries to flag comments created before the flagging migration. + Maintains backward compatibility""" comment = self.comment - url = self.get_url() + url = self.get_base_url() data = self.flag_data comment.flag.delete() # delete the flag object + response = self.client.post(url, data=data) + self.assertEqual(response.status_code, 200) comment.refresh_from_db() self.assertEqual(comment.flag.count, 1) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) - def test_is_flagged_value(self): - # test is_flagged property + def test_is_flagged_property(self): comment = self.create_comment(self.content_object_1) data = self.flag_data - url = self.get_url(comment.id) + url = self.get_base_url(comment.id) response = self.client.post(url, data=data) self.assertEqual(response.status_code, 200) @@ -537,14 +463,16 @@ def test_is_flagged_value(self): self.assertEqual(comment.flag.count, 2) - def test_flag_to_comment_with_invalid_reason(self): - data = self.flag_data + def test_flagging_with_invalid_reason(self): + data = self.flag_data.copy() data.update({'reason': -1}) - response = self.client.post(self.get_url(), data=data) + + response = self.client.post(self.get_base_url(), data=data) + self.assertEqual(response.status_code, 400) -class APICommentDetailForFlagStateChangeTest(APIBaseTest): +class APICommentDetailForFlagStateChangeTest(BaseAPITest): def setUp(self): super().setUp() self.client.force_login(self.moderator) @@ -564,61 +492,75 @@ def setUpTestData(cls): cls.create_flag_instance(cls.user_1, cls.comment_1, **cls.flag_data) cls.create_flag_instance(cls.user_2, cls.comment_1, **cls.flag_data) - def get_url(self, c_id=None): + def get_base_url(self, c_id=None): if not c_id: c_id = self.comment_1.id - return f'/api/comments/{c_id}/flag/state/change/' + return reverse_lazy('comment-api:flag-state-change', args=[c_id]) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0) - def test_change_state_when_flagging_is_disabled(self): - response = self.client.post(self.get_url(), data=self.data) + def test_when_flagging_is_disabled(self): + response = self.client.post(self.get_base_url(), data=self.data) + self.assertEqual(response.status_code, 403) - def test_change_state_when_comment_is_not_flagged(self): + def test_when_comment_is_not_flagged(self): comment = self.comment_2 - self.assertIs(False, comment.is_flagged) - response = self.client.post(self.get_url(comment.id), data=self.data) + + response = self.client.post(self.get_base_url(comment.id), data=self.data) + self.assertEqual(response.status_code, 400) - def test_change_state_by_not_permitted_user(self): - comment = self.comment_1 - self.assertIs(True, comment.is_flagged) + def test_by_not_permitted_user(self): self.client.force_login(self.user_1) - response = self.client.post(self.get_url(), data=self.data) + + response = self.client.post(self.get_base_url(), data=self.data) + self.assertEqual(response.status_code, 403) - def test_change_state_with_wrong_state_value(self): + def test_with_wrong_int_value(self): data = self.data.copy() - comment = self.comment_1 - self.assertIs(True, comment.is_flagged) data['state'] = 100 - response = self.client.post(self.get_url(), data=data) + + response = self.client.post(self.get_base_url(), data=data) + self.assertEqual(response.status_code, 400) + def test_with_non_int_value(self): + data = self.data.copy() data['state'] = "Not Int" - response = self.client.post(self.get_url(), data=data) + + response = self.client.post(self.get_base_url(), data=data) + self.assertEqual(response.status_code, 400) - response = self.client.post(self.get_url(), data={}) + def test_without_data(self): + response = self.client.post(self.get_base_url(), data={}) + self.assertEqual(response.status_code, 400) + def test_with_state_as_resolved_on_non_edited_comment(self): + data = self.data.copy() + comment = self.comment_1 data['state'] = comment.flag.RESOLVED + comment.refresh_from_db() self.assertFalse(comment.is_edited) - response = self.client.post(self.get_url(), data=data) + + response = self.client.post(self.get_base_url(), data=data) + self.assertEqual(response.status_code, 400) - def test_change_state_success(self): + def test_success(self): comment = self.comment_1 - self.assertIs(True, comment.is_flagged) - self.assertEqual(comment.flag.state, comment.flag.FLAGGED) - data = self.data.copy() data['state'] = comment.flag.REJECTED - response = self.client.post(self.get_url(), data=data) + + response = self.client.post(self.get_base_url(), data=data) + self.assertEqual(response.status_code, 200) comment.flag.refresh_from_db() + self.assertEqual(comment.flag.state, comment.flag.REJECTED) sleep(1) @@ -628,20 +570,20 @@ def test_change_state_success(self): # First request data['state'] = comment.flag.RESOLVED - response = self.client.post(self.get_url(), data=data) + response = self.client.post(self.get_base_url(), data=data) self.assertEqual(response.status_code, 200) comment.flag.refresh_from_db() self.assertEqual(comment.flag.state, comment.flag.RESOLVED) # Second request of same state changes state to FLAGGED data['state'] = comment.flag.RESOLVED - response = self.client.post(self.get_url(), data=data) + response = self.client.post(self.get_base_url(), data=data) self.assertEqual(response.status_code, 200) comment.flag.refresh_from_db() self.assertEqual(comment.flag.state, comment.flag.FLAGGED) -class APIConfirmCommentViewTest(BaseAnonymousCommentTest, APIBaseTest): +class APIConfirmCommentViewTest(BaseAnonymousCommentTest, BaseAPITest): def setUp(self): super().setUp() self.client.logout() @@ -652,16 +594,18 @@ def setUpTestData(cls): super().setUpTestData() cls.comment = cls.create_anonymous_comment(posted=timezone.now(), email='a@a.com') - def get_url(self, key=None): + def get_base_url(self, key=None): if not key: key = self.key - return f'/api/comments/confirm/{key}/' + return reverse_lazy('comment-api:confirm-comment', args=[key]) def test_bad_signature(self): key = self.key + 'invalid' - url = self.get_url(key) + url = self.get_base_url(key) + response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.json()['detail'], EmailError.BROKEN_VERIFICATION_LINK) self.assertTextTranslated(response.data['detail'], url) @@ -675,9 +619,10 @@ def test_comment_exists(self): 'email': self.comment.email }) key = signing.dumps(comment_dict) - url = self.get_url(key) + url = self.get_base_url(key) response = self.client.get(url) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.json()['detail'], EmailError.USED_VERIFICATION_LINK) self.assertTextTranslated(response.data['detail'], url) @@ -685,22 +630,28 @@ def test_comment_exists(self): @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) def test_success_without_notification(self): - response = self.client.get(self.get_url()) + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + comment = Comment.objects.get(email=self.comment_obj.email, posted=self.time_posted) + self.assertEqual(response.data, CommentSerializer(comment).data) self.assertEqual(Comment.objects.all().count(), self.init_count + 1) self.assertEqual(len(mail.outbox), 0) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_success_with_notification(self): - response = self.client.get(self.get_url()) + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + response.renderer_context['view'].email_service._email_thread.join() + self.assertEqual(len(mail.outbox), 1) -class APIToggleFollowTest(APIBaseTest): +class APIToggleFollowTest(BaseAPITest): @classmethod def setUpTestData(cls): super().setUpTestData() @@ -709,26 +660,33 @@ def setUpTestData(cls): cls.model_name = cls.comment_toggle_follow.__class__.__name__ cls.model_id = cls.comment_toggle_follow.id - def get_url(self): + def get_base_url(self): params = [f'app_name={self.app_name}', f'model_name={self.model_name}', f'model_id={self.model_id}'] - return f'/api/comments/toggle-subscription/?{"&".join(params)}' + base_url = reverse_lazy('comment-api:toggle-subscription') + return base_url + '?' + '&'.join(params) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_unauthenticated_users(self): self.client.logout() - response = self.client.post(self.get_url()) + + response = self.client.post(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) def test_system_is_not_enabled(self): - response = self.client.post(self.get_url()) + response = self.client.post(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_toggle_follow(self): self.client.force_login(self.user_2) + self.assertIsNotNone(self.user_2.email) - response = self.client.post(self.get_url()) + + response = self.client.post(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_200_OK) data = response.json().get('data') self.assertEqual(data['app_name'], self.app_name) @@ -737,7 +695,7 @@ def test_toggle_follow(self): self.assertTrue(data['following']) -class APIGetSubscribersTest(APIBaseTest): +class APIGetSubscribersTest(BaseAPITest): @classmethod def setUpTestData(cls): super().setUpTestData() @@ -746,25 +704,31 @@ def setUpTestData(cls): cls.model_name = cls.comment_get_followers.__class__.__name__ cls.model_id = cls.comment_get_followers.id - def get_url(self): + def get_base_url(self): params = [f'app_name={self.app_name}', f'model_name={self.model_name}', f'model_id={self.model_id}'] - return f'/api/comments/subscribers/?{"&".join(params)}' + base_url = reverse_lazy('comment-api:subscribers') + return base_url + '?' + '&'.join(params) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_unauthenticated_users(self): self.client.logout() - response = self.client.get(self.get_url()) + + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', False) def test_system_is_not_enabled(self): - response = self.client.get(self.get_url()) + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_only_moderators_can_get_followers(self): self.client.force_login(self.moderator) - response = self.client.get(self.get_url()) + + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['app_name'], self.app_name) self.assertEqual(response.data['model_name'], self.model_name) @@ -775,6 +739,7 @@ def test_only_moderators_can_get_followers(self): @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) def test_normal_users_cannot_get_followers(self): self.client.force_login(self.user_1) - self.assertFalse(is_comment_moderator(self.user_1)) - response = self.client.get(self.get_url()) + + response = self.client.get(self.get_base_url()) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/comment/tests/test_mixins.py b/comment/tests/test_mixins.py index 9203493..78d2064 100644 --- a/comment/tests/test_mixins.py +++ b/comment/tests/test_mixins.py @@ -18,6 +18,7 @@ def setUp(self): def test_non_ajax_request(self): request = self.factory.get('/') response = self.mixin.dispatch(request) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.content.decode('utf-8'), ErrorMessage.NON_AJAX_REQUEST) @@ -29,6 +30,7 @@ def test_has_permission(self): def test_has_object_permission(self): request = self.factory.get('/') + self.assertTrue(BasePermission().has_object_permission(request, 'object')) @@ -40,12 +42,14 @@ def setUp(self): def test_logged_in_user_permission(self): response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', False) def test_logged_out_user_permission(self, ): self.client.logout() response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 302) # user will be redirected to login self.assertEqual(response.url, settings.LOGIN_URL + '?next=/comment/create/') @@ -55,12 +59,14 @@ def test_permission_when_anonymous_comment_allowed(self): self.client.logout() self.data['email'] = 'test@test.come' response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) class ObjectLevelMixinTest(BaseCommentMixinTest): def test_get_object_without_overriding(self): object_mixin = ObjectLevelMixin() + self.assertRaises(ImproperlyConfigured, object_mixin.get_object) @@ -72,18 +78,21 @@ def setUp(self): def test_comment_owner_can_edit(self): response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) def test_edit_comment_by_non_owner(self): self.assertNotEqual(self.comment.user.id, self.user_2.id) self.client.force_login(self.user_2) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) def test_edit_comment_by_anonymous(self): """anonymous will be redirected to login page""" self.client.logout() response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 302) self.assertEqual(response.url, settings.LOGIN_URL + f'?next=/comment/edit/{self.comment.id}/') @@ -97,18 +106,21 @@ def setUp(self): def test_delete_comment_by_owner(self): self.assertEqual(self.comment.user.id, self.user_1.id) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) def test_delete_comment_by_non_owner(self): self.assertNotEqual(self.comment.user.id, self.user_2.id) self.client.force_login(self.user_2) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) def test_delete_comment_by_admin(self): self.assertNotEqual(self.comment.user.id, self.admin.id) self.client.force_login(self.admin) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) def test_delete_comment_by_moderator(self): @@ -116,18 +128,20 @@ def test_delete_comment_by_moderator(self): self.assertNotEqual(self.comment.user.id, self.moderator.id) self.client.force_login(self.moderator) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) def test_delete_flagged_comment_by_moderator(self): """moderator cannot delete comment unless it's flagged""" self.assertNotEqual(self.comment.user.id, self.moderator.id) self.client.force_login(self.moderator) - self.create_flag_instance(self.user_2, self.comment) - self.create_flag_instance(self.admin, self.comment) self.create_flag_instance(self.moderator, self.comment) - self.assertEqual(self.flags, 3) + self.create_flag_instance(self.admin, self.comment) + self.assertEqual(self.flags, 2) self.assertTrue(self.comment.is_flagged) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) @@ -142,12 +156,14 @@ def test_flag_not_enabled_permission(self, _): """permission denied when flagging not enabled""" self.client.force_login(self.user_2) response = self.client.post(self.url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) @patch('comment.mixins.settings', COMMENT_FLAGS_ALLOWED=2) def test_flag_enabled_permission(self, _): self.client.force_login(self.user_2) response = self.client.post(self.url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) @@ -161,6 +177,7 @@ def test_user_cannot_flag_their_own_comment(self): self.assertEqual(self.comment.user.id, self.user_1.id) self.client.force_login(self.user_1) response = self.client.post(self.url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) @@ -173,22 +190,25 @@ def setUp(self): def test_change_state_of_unflagged_comment(self): response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 400) + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) def test_moderator_can_change_flag_state(self): - self.create_flag_instance(self.user_2, self.comment) self.create_flag_instance(self.admin, self.comment) self.create_flag_instance(self.moderator, self.comment) self.comment.flag.refresh_from_db() - self.assertEqual(self.flags, 3) + self.assertEqual(self.flags, 2) self.assertTrue(self.comment.is_flagged) # normal user cannot change flag state self.client.force_login(self.user_2) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) self.client.force_login(self.moderator) response = self.client.post(self.url, data=self.data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) @@ -204,6 +224,7 @@ def test_user_cannot_subscribe(self): self.client.force_login(self.user_1) self.assertFalse(settings.COMMENT_ALLOW_SUBSCRIPTION) response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 403) @patch.object(settings, 'COMMENT_ALLOW_SUBSCRIPTION', True) @@ -211,4 +232,5 @@ def test_user_can_subscribe(self): self.client.force_login(self.user_1) self.assertTrue(settings.COMMENT_ALLOW_SUBSCRIPTION) response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) diff --git a/comment/tests/test_models/test_comments.py b/comment/tests/test_models/test_comments.py index 13dcb05..0cb6e95 100644 --- a/comment/tests/test_models/test_comments.py +++ b/comment/tests/test_models/test_comments.py @@ -5,49 +5,73 @@ from comment.conf import settings from comment.models import Comment -from comment.tests.base import BaseCommentManagerTest +from comment.tests.base import BaseCommentManagerTest, RequestFactory class CommentModelTest(BaseCommentManagerTest): - def test_can_create_comment(self): - parent_comment = self.create_comment(self.content_object_1) - self.assertIsNotNone(parent_comment) - self.assertEqual(str(parent_comment), f'comment by {parent_comment.user}: {parent_comment.content[:20]}') - self.assertEqual(repr(parent_comment), f'comment by {parent_comment.user}: {parent_comment.content[:20]}') - self.assertTrue(parent_comment.is_parent) - self.assertEqual(parent_comment.replies().count(), 0) - self.assertIsNotNone(parent_comment.urlhash) - - child_comment = self.create_comment(self.content_object_1, parent=parent_comment) - self.assertIsNotNone(child_comment) - self.assertEqual(str(child_comment), f'reply by {child_comment.user}: {child_comment.content[:20]}') - self.assertEqual(repr(child_comment), f'reply by {child_comment.user}: {child_comment.content[:20]}') - self.assertFalse(child_comment.is_parent) - self.assertEqual(parent_comment.replies().count(), 1) - self.assertIsNotNone(child_comment.urlhash) + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.parent_comment = cls.create_comment(cls.content_object_1) + + def test_parent_comment_properties(self): + comment = self.parent_comment + + self.assertIsNotNone(comment) + self.assertEqual(str(comment), f'comment by {comment.user}: {comment.content[:20]}') + self.assertEqual(repr(comment), f'comment by {comment.user}: {comment.content[:20]}') + self.assertTrue(comment.is_parent) + self.assertEqual(comment.replies().count(), 0) + self.assertIsNotNone(comment.urlhash) + + def test_child_comment_properties(self): + comment = self.create_comment(self.content_object_1, parent=self.parent_comment) + + self.assertIsNotNone(comment) + self.assertEqual(str(comment), f'reply by {comment.user}: {comment.content[:20]}') + self.assertEqual(repr(comment), f'reply by {comment.user}: {comment.content[:20]}') + self.assertFalse(comment.is_parent) + self.assertEqual(self.parent_comment.replies().count(), 1) + self.assertIsNotNone(comment.urlhash) def test_is_edited(self): comment = self.create_comment(self.content_object_1) self.assertFalse(comment.is_edited) + comment.content = 'updated' sleep(1) comment.save() + self.assertTrue(comment.is_edited) def test_is_edited_for_anonymous_comment(self): comment = self.create_anonymous_comment(posted=timezone.now() - timezone.timedelta(days=1)) + self.assertFalse(comment.is_edited) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) @patch.object(settings, 'COMMENT_SHOW_FLAGGED', False) - def test_replies_method(self): - self.assertEqual(self.parent_comment_2.replies().count(), 3) + def test_replies_method_without_any_flags(self): + init_count = self.parent_comment_2.replies().count() reply = self.parent_comment_2.replies().first() + self.create_flag_instance(self.user_1, reply) self.create_flag_instance(self.user_2, reply) + # default replies method hides flagged comment - self.assertEqual(self.parent_comment_2.replies().count(), 2) - self.assertEqual(self.parent_comment_2.replies(include_flagged=True).count(), 3) + self.assertEqual(self.parent_comment_2.replies(include_flagged=True).count(), init_count) + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) + @patch.object(settings, 'COMMENT_SHOW_FLAGGED', False) + def test_replies_method_with_flags(self): + init_count = self.parent_comment_2.replies().count() + reply = self.parent_comment_2.replies().first() + + self.create_flag_instance(self.user_1, reply) + self.create_flag_instance(self.user_2, reply) + + # the comment is hidden, since it is flagged. + self.assertEqual(self.parent_comment_2.replies().count(), init_count - 1) @patch('comment.models.comments.hasattr') def test_is_flagged_property(self, mocked_hasattr): @@ -106,40 +130,19 @@ def test_has_resolved_state(self, mocked_hasattr): def test_urlhash_is_unique(self, mocked_generate_urlhash): mocked_generate_urlhash.side_effect = ['first_urlhash', 'first_urlhash', 'second_urlhash'] first_comment = self.create_comment(self.content_object_1) + self.assertEqual(first_comment.urlhash, 'first_urlhash') + mocked_generate_urlhash.assert_called_once() second_comment = self.create_comment(self.content_object_1) + self.assertEqual(second_comment.urlhash, 'second_urlhash') self.assertEqual(mocked_generate_urlhash.call_count, 3) def test_comment_email(self): comment = self.parent_comment_1 - self.assertEqual(comment.email, comment.user.email) - - def test_get_url(self): - from comment.tests.base import RequestFactory - - factory = RequestFactory() - request = factory.get('/') - request.user = self.user_1 - attr = 'COMMENT_PER_PAGE' - comment = self.parent_comment_3 - - # no pagination(parent comment 3, 2, 1 belong to the same content_object_1) - with patch.object(settings, attr, 0): - comment_url = comment.content_object.get_absolute_url() + '#' + comment.urlhash - - self.assertEqual(comment_url, comment.get_url(request)) - - # with pagination - with patch.object(settings, attr, 3): - # comment on first page - self.assertEqual(comment_url, comment.get_url(request)) - # comment on the second page - comment = self.parent_comment_1 - comment_url = comment.content_object.get_absolute_url() + '?page=2' + '#' + comment.urlhash - self.assertEqual(comment_url, comment.get_url(request)) + self.assertEqual(comment.email, comment.user.email) def test_get_username_for_non_anonymous_comment(self): comment = self.create_comment(self.content_object_1, user=self.user_1) @@ -158,30 +161,14 @@ def test_get_username_for_anonymous_comment(self): class CommentModelManagerTest(BaseCommentManagerTest): - class OrderForParentCommentsTest(BaseCommentManagerTest): - def setUp(self): - super().setUp() - self.all_parents_qs = Comment.objects.all_exclude_flagged().filter(parent=None) - self.all_comments_qs = Comment.objects.all_exclude_flagged() - - def test_default_value(self): - self.assertQuerysetEqual( - Comment.objects._filter_parents(self.all_comments_qs), - self.all_parents_qs.order_by(*settings.COMMENT_ORDER_BY) - ) - - @patch.object(settings, 'COMMENT_ORDER_BY', ['-reaction__likes']) - def test_custom_values(self): - self.assertQuerysetEqual( - Comment.objects._filter_parents(self.all_comments_qs), - self.all_parents_qs.order_by(*settings.COMMENT_ORDER_BY) - ) - def test_retrieve_all_parent_comments(self): # for all objects of a content type all_comments = Comment.objects.all().count() + self.assertEqual(all_comments, 10) + parent_comments = Comment.objects.all_parents().count() + self.assertEqual(parent_comments, 5) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) @@ -205,6 +192,7 @@ def test_filtering_comment_when_flag_not_enabled(self): self.create_flag_instance(self.user_2, comment) comment.flag.refresh_from_db() self.assertEqual(comment.flag.count, 2) + self.assertEqual(Comment.objects.all_exclude_flagged().count(), self.increment) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) @@ -223,6 +211,7 @@ def test_all_comments_by_object(self): # comments with flagged count = Comment.objects.all_comments_by_object(self.post_1, include_flagged=True).count() + self.assertEqual(count, init_count) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) @@ -236,10 +225,12 @@ def test_filter_parents_by_object(self): self.create_flag_instance(self.user_2, comment) # comments without flagged count = Comment.objects.filter_parents_by_object(self.post_2).count() + self.assertEqual(count, init_count - 1) # comments with flagged count = Comment.objects.filter_parents_by_object(self.post_2, include_flagged=True).count() + self.assertEqual(count, init_count) @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) @@ -255,3 +246,51 @@ def test_get_parent_comment(self): parent_comment = Comment.objects.get_parent_comment(1) self.assertIsNotNone(parent_comment) self.assertEqual(parent_comment, self.parent_comment_1) + + +class OrderForParentCommentsTest(BaseCommentManagerTest): + def setUp(self): + super().setUp() + self.all_parents_qs = Comment.objects.all_exclude_flagged().filter(parent=None) + self.all_comments_qs = Comment.objects.all_exclude_flagged() + + def test_default_value(self): + self.assertQuerysetEqual( + Comment.objects._filter_parents(self.all_comments_qs), + self.all_parents_qs.order_by(*settings.COMMENT_ORDER_BY) + ) + + @patch.object(settings, 'COMMENT_ORDER_BY', ['-reaction__likes']) + def test_custom_values(self): + self.assertQuerysetEqual( + Comment.objects._filter_parents(self.all_comments_qs), + self.all_parents_qs.order_by(*settings.COMMENT_ORDER_BY) + ) + + +class GetUrlTest(BaseCommentManagerTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.request = RequestFactory().get('/') + cls.request.user = cls.user_1 + # no pagination(parent comment 3, 2, 1 belong to the same content_object_1) + + @patch.object(settings, 'COMMENT_PER_PAGE', 0) + def test_with_pagination_disabled(self): + comment = self.parent_comment_3 + comment_url = comment.content_object.get_absolute_url() + '#' + comment.urlhash + + self.assertEqual(comment_url, comment.get_url(self.request)) + + @patch.object(settings, 'COMMENT_PER_PAGE', 3) + def test_comment_on_first_page(self): + comment = self.parent_comment_3 + comment_url = comment.content_object.get_absolute_url() + '#' + comment.urlhash + self.assertEqual(comment_url, comment.get_url(self.request)) + + @patch.object(settings, 'COMMENT_PER_PAGE', 3) + def test_comment_not_on_first_page(self): + comment = self.parent_comment_1 + comment_url = comment.content_object.get_absolute_url() + '?page=2' + '#' + comment.urlhash + self.assertEqual(comment_url, comment.get_url(self.request)) diff --git a/comment/tests/test_models/test_flags.py b/comment/tests/test_models/test_flags.py index e16b774..2409b4a 100644 --- a/comment/tests/test_models/test_flags.py +++ b/comment/tests/test_models/test_flags.py @@ -3,7 +3,7 @@ from django.core.exceptions import ValidationError from comment.conf import settings -from comment.models import FlagInstance +from comment.models import FlagInstance, Flag from comment.tests.base import BaseCommentFlagTest @@ -12,6 +12,7 @@ def test_create_flag(self): data = self.flag_data comment = self.comment instance = self.create_flag_instance(self.user, comment, **data) + self.assertIsNotNone(instance) comment.refresh_from_db() self.assertEqual(comment.flag.count, 1) @@ -21,21 +22,26 @@ class FlagInstanceManagerTest(BaseCommentFlagTest): def test_clean_reason_for_invalid_value(self): data = self.flag_data.copy() data.update({'reason': -1}) + self.assertRaises(ValidationError, self.set_flag, self.user, self.comment, **data) + def test_clean_reason_for_wrong_type(self): + data = self.flag_data.copy() data.update({'reason': 'abc'}) + self.assertRaises(ValidationError, self.set_flag, self.user, self.comment, **data) - def test_clean_for_invalid_values(self): + def test_clean_for_last_reason_without_info(self): data = self.flag_data.copy() - user = self.user - comment = self.comment - # info can't be blank with the last reason(something else) data.update({'reason': FlagInstance.objects.reason_values[-1]}) - self.assertRaises(ValidationError, self.set_flag, user, comment, **data) + self.assertRaises(ValidationError, self.set_flag, self.user, self.comment, **data) + + def test_clean_without_reason(self): + data = self.flag_data.copy() data.pop('reason') - self.assertRaises(ValidationError, self.set_flag, user, comment, **data) + + self.assertRaises(ValidationError, self.set_flag, self.user, self.comment, **data) def test_clean_ignores_info_for_all_reasons_except_last(self): data = self.flag_data.copy() @@ -63,104 +69,146 @@ def test_set_flag_for_delete(self): def test_create_flag_twice(self): self.assertTrue(self.set_flag(self.user, self.comment, **self.flag_data)) + self.assertRaises(ValidationError, self.set_flag, self.user, self.comment, **self.flag_data) - def test_un_flag_non_exist_flag(self): - # user try to un-flag comment that wasn't flagged yet + def test_un_flag_non_existent_flag(self): + # user tries to un-flag comment that wasn't flagged yet self.assertRaises(ValidationError, self.set_flag, self.user, self.comment) class FlagModelTest(BaseCommentFlagTest): def test_flag_count(self): comment = self.comment + self.assertEqual(comment.flag.count, 0) + comment.flag.increase_count() comment.refresh_from_db() + self.assertEqual(comment.flag.count, 1) + comment.flag.decrease_count() comment.flag.refresh_from_db() + self.assertEqual(comment.flag.count, 0) def test_comment_author(self): comment = self.comment + self.assertEqual(comment.user, comment.flag.comment_author) - def test_is_flagged_enabled(self): - flag = self.create_comment(self.content_object_1).flag - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1): - self.assertIs(True, flag.is_flag_enabled) - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0): - self.assertIs(False, flag.is_flag_enabled) +class ToggleFlaggedStateTest(BaseCommentFlagTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.comment = cls.create_comment(cls.content_object_1) + cls.flag = cls.comment.flag + cls.create_flag_instance(cls.user_1, cls.comment) + cls.create_flag_instance(cls.user_2, cls.comment) + cls.flag.refresh_from_db() - @patch('comment.models.flags.Flag.get_clean_state') - def test_get_verbose_state(self, mocked_get_clean_state): - flag = self.create_comment(self.content_object_1).flag - mocked_get_clean_state.return_value = flag.FLAGGED - self.assertEqual(flag.get_verbose_state(flag.FLAGGED), flag.STATES_CHOICES[flag.FLAGGED-1][1]) - mocked_get_clean_state.return_value = 100 - self.assertIsNone(flag.get_verbose_state(100)) + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0) + def test_flag_disabled(self): + self.flag.toggle_flagged_state() + + self.assertEqual(self.flag.state, self.flag.UNFLAGGED) + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) + def test_when_flagging_is_enabled(self): + self.flag.toggle_flagged_state() - def test_get_clean_state(self): - flag = self.create_comment(self.content_object_1).flag - state = flag.get_clean_state(flag.FLAGGED) - self.assertEqual(state, 2) + self.assertEqual(self.flag.state, self.flag.FLAGGED) - # int not in existing states - self.assertRaises(ValidationError, flag.get_clean_state, 100) + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 10) + def test_with_large_allowed_flag_count(self): + self.assertEqual(self.flag.count, 2) + self.flag.toggle_flagged_state() - # not int - self.assertRaises(ValidationError, flag.get_clean_state, 'Not int') + self.assertEqual(self.flag.state, self.flag.UNFLAGGED) - # None - self.assertRaises(ValidationError, flag.get_clean_state, None) - def test_toggle_state(self): - flag = self.create_comment(self.content_object_1).flag - self.assertIsNone(flag.moderator) - self.assertEqual(flag.state, flag.UNFLAGGED) +class ToggleStateTest(BaseCommentFlagTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.flag = cls.create_comment(cls.content_object_1).flag + def test_unflagged_state(self): # toggle states occurs between rejected and resolved only - self.assertRaises(ValidationError, flag.toggle_state, flag.FLAGGED, self.moderator) + self.assertRaises(ValidationError, self.flag.toggle_state, self.flag.FLAGGED, self.moderator) - flag.toggle_state(flag.REJECTED, self.moderator) - self.assertEqual(flag.state, flag.REJECTED) - self.assertEqual(flag.moderator, self.moderator) + def test_rejected_state(self): + self.flag.toggle_state(self.flag.REJECTED, self.moderator) + self.assertEqual(self.flag.state, self.flag.REJECTED) + self.assertEqual(self.flag.moderator, self.moderator) + + def test_passing_same_state_twice(self): # passing RESOLVED state value for the first time - flag.toggle_state(flag.RESOLVED, self.moderator) - self.assertEqual(flag.state, flag.RESOLVED) + self.flag.toggle_state(self.flag.RESOLVED, self.moderator) + self.assertEqual(self.flag.state, self.flag.RESOLVED) # passing RESOLVED state value for the second time - flag.toggle_state(flag.RESOLVED, self.moderator) + self.flag.toggle_state(self.flag.RESOLVED, self.moderator) # state reset to FLAGGED - self.assertEqual(flag.state, flag.FLAGGED) - - def test_toggle_flagged_state(self): - comment = self.create_comment(self.content_object_1) - flag = comment.flag - flag.toggle_flagged_state() - self.assertEqual(flag.state, flag.UNFLAGGED) - - # TODO split this test to be independent from the actual settings - # current settings value COMMENT_FLAGS_ALLOWED = 2 - self.create_flag_instance(self.user_1, comment) - self.create_flag_instance(self.user_2, comment) - flag.refresh_from_db() - self.assertEqual(flag.count, 2) - - # flagging is disabled => state won't change - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0): - flag.toggle_flagged_state() - self.assertEqual(flag.state, flag.UNFLAGGED) - - # flagging is enabled => state changes - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1): - flag.toggle_flagged_state() - self.assertEqual(flag.state, flag.FLAGGED) - - # increase allowed flags count => change the state to UNFLAGGED - with patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 10): - self.assertEqual(flag.count, 2) - flag.toggle_flagged_state() - self.assertEqual(flag.state, flag.UNFLAGGED) + self.assertEqual(self.flag.state, self.flag.FLAGGED) + + +class GetVerboseStateTest(BaseCommentFlagTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.flag = cls.create_comment(cls.content_object_1).flag + + @patch('comment.models.flags.Flag.get_clean_state') + def test_valid_state(self, mocked_get_clean_state): + mocked_get_clean_state.return_value = self.flag.FLAGGED + + self.assertEqual( + self.flag.get_verbose_state(self.flag.FLAGGED), + self.flag.STATES_CHOICES[self.flag.FLAGGED-1][1], + ) + + @patch('comment.models.flags.Flag.get_clean_state') + def test_invalid_state(self, mocked_get_clean_state): + mocked_get_clean_state.return_value = 100 + + self.assertIsNone(self.flag.get_verbose_state(100)) + + +class GetCleanStateTest(BaseCommentFlagTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.flag = cls.create_comment(cls.content_object_1).flag + + def test_valid_state(self): + state = self.flag.get_clean_state(self.flag.FLAGGED) + + self.assertEqual(state, Flag.FLAGGED) + + def test_invalid_int(self): + self.assertRaises(ValidationError, self.flag.get_clean_state, 100) + + def test_non_integeral_value(self): + self.assertRaises(ValidationError, self.flag.get_clean_state, 'Not int') + + def test_passing_none(self): + self.assertRaises(ValidationError, self.flag.get_clean_state, None) + + +class IsFlagEnabledTest(BaseCommentFlagTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.flag = cls.create_comment(cls.content_object_1).flag + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 1) + def test_when_enabled(self): + self.assertIs(True, self.flag.is_flag_enabled) + + @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', 0) + def test_when_disabled(self): + self.assertIs(False, self.flag.is_flag_enabled) diff --git a/comment/tests/test_models/test_followers.py b/comment/tests/test_models/test_followers.py index 0a11fad..495bcf0 100644 --- a/comment/tests/test_models/test_followers.py +++ b/comment/tests/test_models/test_followers.py @@ -56,6 +56,7 @@ def test_follow_return_none_if_email_is_already_follow(self): def test_follow_create_follower_instance(self): initial_count = self.manager.count() follower = self.manager.follow(self.unfollower_email, 'username', self.comment_test_follow) + self.assertIsInstance(follower, self.manager.model) self.assertEqual(self.manager.count(), initial_count + 1) @@ -63,11 +64,13 @@ def test_unfollow_delete_follower_instance(self): initial_count = self.manager.count() self.assertTrue(self.manager.is_following(self.follower_email, self.comment_test_follow)) self.manager.unfollow(self.follower_email, self.comment_test_follow) + self.assertEqual(self.manager.count(), initial_count - 1) def test_toggle_follow_return_false_on_missing_email(self): email = None result = self.manager.toggle_follow(email=email, username='test', model_object=self.comment_test_follow) + self.assertFalse(result) def test_toggle_follow_for_follower(self): @@ -79,6 +82,7 @@ def test_toggle_follow_for_follower(self): model_object=self.comment_test_follow ) self.assertFalse(result) + self.assertFalse(self.manager.is_following(self.follower_email, self.comment_test_follow)) def test_toggle_follow_for_unfollower(self): @@ -90,6 +94,7 @@ def test_toggle_follow_for_unfollower(self): model_object=self.comment_test_follow ) self.assertTrue(result) + self.assertTrue(self.manager.is_following(self.unfollower_email, self.comment_test_follow)) def test_follow_parent_thread_for_comment_no_email(self): @@ -135,8 +140,9 @@ def test_follow_parent_thread_for_comment_parent_comment(self): def test_get_all_followers_for_model_object(self): followers = self.manager.filter_for_model_object(self.comment_test_follow) - content_type = ContentType.objects.get_for_model(self.comment_test_follow) self.assertNotEqual(followers.count(), 0) + content_type = ContentType.objects.get_for_model(self.comment_test_follow) + self.assertEqual( list(followers), list(self.manager.filter(content_type=content_type, object_id=self.comment_test_follow.id)) @@ -144,4 +150,5 @@ def test_get_all_followers_for_model_object(self): def test_get_get_emails_for_model_object(self): emails = self.manager.get_emails_for_model_object(self.comment_test_follow) + self.assertIn(self.comment_test_follow.email, emails) diff --git a/comment/tests/test_models/test_reactions.py b/comment/tests/test_models/test_reactions.py index 00d05c8..b16f2e4 100644 --- a/comment/tests/test_models/test_reactions.py +++ b/comment/tests/test_models/test_reactions.py @@ -21,6 +21,7 @@ def test_user_can_create_reaction(self): def test_unique_togetherness_of_user_and_reaction_type(self): """Test Integrity error is raised when one user is set to have more than 1 reaction type for the same comment""" self.create_reaction_instance(self.user, self.comment, self.LIKE) + self.assertRaises(IntegrityError, self.create_reaction_instance, self.user, self.comment, self.DISLIKE) def test_comment_property_likes_increase_and_decrease(self): @@ -31,10 +32,12 @@ def test_comment_property_likes_increase_and_decrease(self): user = self.user_2 self.create_reaction_instance(user, comment, self.LIKE) comment.refresh_from_db() + self.assertEqual(comment.likes, 2) self.set_reaction(user, comment, self.LIKE) comment.refresh_from_db() + self.assertEqual(comment.likes, 1) def test_comment_property_dislikes_increase_and_decrease(self): @@ -45,11 +48,13 @@ def test_comment_property_dislikes_increase_and_decrease(self): user = self.user_2 self.create_reaction_instance(user, comment, self.DISLIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 2) # can't use create_reaction: one user can't create multiple reaction instances for a comment. self.set_reaction(user, comment, self.DISLIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 1) def test_set_reaction(self): @@ -58,21 +63,25 @@ def test_set_reaction(self): user = self.user_2 self.set_reaction(user, comment, self.DISLIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 1) self.assertEqual(comment.likes, 0) self.set_reaction(user, comment, self.DISLIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 0) self.assertEqual(comment.likes, 0) self.set_reaction(user, comment, self.LIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 0) self.assertEqual(comment.likes, 1) self.set_reaction(user, comment, self.DISLIKE) comment.refresh_from_db() + self.assertEqual(comment.dislikes, 1) self.assertEqual(comment.likes, 0) @@ -117,6 +126,7 @@ def test_clean_reaction_type(self): like = ReactionInstance.ReactionType.LIKE # valid reaction type reaction_type = ReactionInstance.objects.clean_reaction_type(like.name) + self.assertEqual(reaction_type, like.value) # invalid reaction type diff --git a/comment/tests/test_service.py b/comment/tests/test_service.py index 75cbc9a..4201e38 100644 --- a/comment/tests/test_service.py +++ b/comment/tests/test_service.py @@ -19,7 +19,7 @@ def setUp(self): super().setUp() self.email_service = DABEmailService(self.comment_obj, self.request) self.confirmation_url = reverse('comment:confirm-comment', args=[self.key]) - self.confirmation_url_drf = f'/api/comments/confirm/{self.key}/' + self.confirmation_url_drf = reverse('comment-api:confirm-comment', args=[self.key]) self.contact_email = settings.COMMENT_CONTACT_EMAIL self.receivers = [] self.sender = settings.COMMENT_FROM_EMAIL @@ -33,7 +33,7 @@ def setUpTestData(cls): def email_contents_test(self, contents, *args): for arg in args: - self.assertTrue(arg in contents) + self.assertIs(arg in contents, True, msg=f'{arg} not present in email contents') self.assertTrue(self.site.name in contents) self.assertTrue(self.content_object_url in contents) @@ -50,6 +50,7 @@ def test_can_create_service(self): def test_get_msg_context(self): context = self.email_service.get_msg_context(test='test') + self.assertEqual(context['comment'], self.comment_obj) self.assertEqual(context['contact'], settings.COMMENT_CONTACT_EMAIL) self.assertEqual(context['test'], 'test') @@ -59,6 +60,7 @@ def test_get_message_for_txt(self): subject = 'test subject' body = 'test body' msg = self.email_service.get_message(subject, body, self.receivers) + self.assertIsInstance(msg, EmailMultiAlternatives) self.assertEqual(msg.to, self.receivers) self.assertEqual(msg.alternatives, []) @@ -67,6 +69,7 @@ def test_get_message_for_html(self): subject = 'test subject' body = 'test body' html = 'html_test' + msg = self.email_service.get_message(subject, body, self.receivers, html_msg=html) self.assertIsInstance(msg, EmailMultiAlternatives) self.assertEqual(msg.to, self.receivers) @@ -79,6 +82,7 @@ def test_get_message_templates_text_only(self): text_template = 'comment/anonymous/confirmation_request.txt' html_template = 'comment/anonymous/confirmation_request.html' text_msg, html_msg = email_service.get_message_templates(text_template, html_template, context) + self.assertFalse(email_service.is_html) self.assertIsNotNone(text_msg) self.assertIsNone(html_msg) @@ -88,6 +92,7 @@ def test_get_message_templates_with_html(self): text_template = 'comment/anonymous/confirmation_request.txt' html_template = 'comment/anonymous/confirmation_request.html' text_msg, html_msg = self.email_service.get_message_templates(text_template, html_template, context) + self.assertTrue(self.email_service.is_html) self.assertIsNotNone(text_msg) self.assertIsNotNone(html_msg) @@ -98,18 +103,24 @@ def test_send_messages(self): self.email_service.get_message('test subject', 'test body', ['test@test'], html_msg='test msg') for _ in range(100) ] + self.assertEqual(len(mail.outbox), 0) + self.email_service.send_messages(messages) + self.assertNotEqual(len(mail.outbox), 100) self.assertTrue(self.email_service._email_thread.is_alive()) self.email_service._email_thread.join() + self.assertEqual(len(mail.outbox), 100) def test_send_confirmation_request_django(self): self.email_service.send_confirmation_request() self.email_service._email_thread.join() + self.assertEqual(len(mail.outbox), 1) sent_email = mail.outbox[0] + self.assertIsInstance(sent_email, EmailMultiAlternatives) self.assertEqual(sent_email.subject, EmailInfo.CONFIRMATION_SUBJECT) self.email_contents_test( @@ -121,8 +132,10 @@ def test_send_confirmation_request_django(self): def test_send_confirmation_request_api(self): self.email_service.send_confirmation_request(api=True) self.email_service._email_thread.join() + self.assertEqual(len(mail.outbox), 1) sent_email = mail.outbox[0] + self.assertIsInstance(sent_email, EmailMultiAlternatives) self.email_contents_test( sent_email.body, self.confirmation_url_drf, self.comment_obj.content, self.contact_email @@ -135,6 +148,7 @@ def test_get_thread_for_parent_comment(self): """The content type (Post, Picture...) is the parent thread of a parent comment""" self.assertTrue(self.email_service.comment.is_parent) thread = self.email_service.get_thread() + self.assertIs(thread, self.email_service.comment.content_object) self.assertIsInstance(thread, self.email_service.comment.content_object.__class__) @@ -144,18 +158,21 @@ def test_get_thread_for_child_comment(self): email_service = DABEmailService(self.child_comment, self.request) self.assertFalse(email_service.comment.is_parent) thread = email_service.get_thread() + self.assertIsNot(thread, email_service.comment.content_object) self.assertIs(thread, email_service.comment.parent) def test_get_thread_name_for_parent_comment(self): self.assertTrue(self.email_service.comment.is_parent) thread_name = self.email_service.get_thread_name() + self.assertEqual(thread_name, str(self.email_service.comment.content_object)) def test_get_thread_name_for_child_comment(self): email_service = DABEmailService(self.child_comment, self.request) self.assertFalse(email_service.comment.is_parent) thread_name = email_service.get_thread_name() + self.assertEqual(thread_name, str(email_service.comment.parent).split(':')[0]) def test_send_notification_to_followers_return_none(self): @@ -164,6 +181,7 @@ def test_send_notification_to_followers_return_none(self): self.comment_obj.content_object).exclude(email=self.comment_obj.email) self.assertEqual(followers.count(), 0) result = self.email_service.send_notification_to_followers() + self.assertIsNone(result) self.assertEqual(len(mail.outbox), 0) @@ -178,6 +196,7 @@ def test_send_notification_to_followers(self): self.assertEqual(len(mail.outbox), 1) sent_email = mail.outbox[0] + self.assertIsInstance(sent_email, EmailMultiAlternatives) username = self.comment_obj.get_username() thread_name = str(self.comment_obj.content_object) @@ -187,4 +206,5 @@ def test_send_notification_to_followers(self): EmailInfo.NOTIFICATION_SUBJECT.format(username=username, thread_name=thread_name) ) self.receivers = [followers.first().email] + self.email_metadata_test(sent_email) diff --git a/comment/tests/test_signals.py b/comment/tests/test_signals.py index 2e5a1cf..85e9d2b 100644 --- a/comment/tests/test_signals.py +++ b/comment/tests/test_signals.py @@ -63,6 +63,7 @@ def test_increase_reaction_count(self): reaction_instance = ReactionInstance.objects.create( reaction=comment.reaction, user=self.user_1, reaction_type=self.LIKE.value) comment.reaction.refresh_from_db() + self.assertEqual(comment.reaction.likes, 1) self.assertEqual(comment.reaction.dislikes, 0) @@ -70,6 +71,7 @@ def test_increase_reaction_count(self): reaction_instance.reaction_type = self.DISLIKE.value reaction_instance.save() comment.reaction.refresh_from_db() + self.assertEqual(comment.reaction.likes, 1) self.assertEqual(comment.reaction.dislikes, 0) @@ -78,13 +80,16 @@ def test_increase_flag_count(self): # instance created self.set_flag(self.user, self.comment, **self.flag_data) self.comment.flag.refresh_from_db() + self.assertEqual(self.comment.flag.count, 1) + # instance edited won't increase the flag count flag_instance = FlagInstance.objects.get(user=self.user, flag__comment=self.comment) self.assertIsNotNone(flag_instance) flag_instance.info = 'change value for test' flag_instance.save() self.comment.flag.refresh_from_db() + self.assertEqual(self.comment.flag.count, 1) @@ -94,9 +99,12 @@ def test_reaction_decrease_count(self): comment = self.comment instance = self.create_reaction_instance(self.user, self.comment, self.LIKE.name) comment.refresh_from_db() + self.assertEqual(comment.likes, 1) + instance.delete() comment.refresh_from_db() + self.assertEqual(comment.likes, 0) def test_flag_decrease_count(self): @@ -105,7 +113,10 @@ def test_flag_decrease_count(self): comment = self.comment instance = self.create_flag_instance(self.user, comment, **data) comment.refresh_from_db() + self.assertEqual(comment.flag.count, 1) + instance.delete() comment.refresh_from_db() + self.assertEqual(comment.flag.count, 0) diff --git a/comment/tests/test_template_tags.py b/comment/tests/test_template_tags.py index f91297a..ba9ce5e 100644 --- a/comment/tests/test_template_tags.py +++ b/comment/tests/test_template_tags.py @@ -13,49 +13,57 @@ from comment.tests.base import BaseTemplateTagsTest -class CommentTemplateTagsTest(BaseTemplateTagsTest): - def test_get_model_name(self): +class GetModelNameTest(BaseTemplateTagsTest): + def test_success(self): model_name = get_model_name(self.post_1) self.assertEqual(model_name, 'Post') - def test_get_app_name(self): + +class GetAppNameTest(BaseTemplateTagsTest): + def test_success(self): app_name = get_app_name(self.post_1) self.assertEqual(app_name, 'post') - def test_comments_count(self): + +class GetCommentCountTest(BaseTemplateTagsTest): + def test_success(self): counts = get_comments_count(self.post_1, self.user_1) self.assertEqual(counts, self.increment) - @patch.object(settings, 'COMMENT_USE_GRAVATAR', False) - def test_get_profile_url(self): - # profile exist + +@patch.object(settings, 'COMMENT_USE_GRAVATAR', False) +class GetProfileURLTest(BaseTemplateTagsTest): + def test_profile_exists(self): url = get_profile_url(self.parent_comment_1) self.assertEqual(url, '/profile/profile/test-1') - # anonymous comment + def test_anonymous_comment(self): url = get_profile_url(self.anonymous_parent_comment) self.assertEqual(url, '/static/img/default.png') - # missing profile - with patch.object(settings, 'PROFILE_MODEL_NAME', None): - url = get_profile_url(self.parent_comment_1) - self.assertEqual(url, '/static/img/default.png') + @patch.object(settings, 'PROFILE_MODEL_NAME', None) + def test_profile_does_not_exist(self): + url = get_profile_url(self.parent_comment_1) + self.assertEqual(url, '/static/img/default.png') - @patch.object(settings, 'COMMENT_USE_GRAVATAR', False) + +@patch.object(settings, 'COMMENT_USE_GRAVATAR', False) +class GetImgPathTest(BaseTemplateTagsTest): def test_get_img_path(self): url = get_img_path(self.parent_comment_1) self.assertNotEqual(url, '/static/img/default.png') - # use default pic on fail - with patch.object(settings, 'PROFILE_MODEL_NAME', 'app not exist'): + @patch.object(settings, 'PROFILE_MODEL_NAME', 'app not exist') + def test_profile_is_not_found(self): + url = get_img_path(self.parent_comment_1) + self.assertEqual(url, settings.COMMENT_DEFAULT_PROFILE_PIC_LOC) + + @patch.object(settings, 'PROFILE_APP_NAME', 'user_profile') + def test_profile_with_image(self): + with patch('comment.templatetags.comment_tags.get_profile_instance', return_value=None): url = get_img_path(self.parent_comment_1) self.assertEqual(url, '/static/img/default.png') - with patch.object(settings, 'PROFILE_APP_NAME', 'user_profile'): - with patch('comment.templatetags.comment_tags.get_profile_instance', return_value=None): - url = get_img_path(self.parent_comment_1) - self.assertEqual(url, '/static/img/default.png') - @patch.object(settings, 'PROFILE_APP_NAME', 'user_profile') @patch.object(settings, 'COMMENT_USE_GRAVATAR', False) def test_profile_has_no_image_field(self): @@ -63,30 +71,32 @@ def test_profile_has_no_image_field(self): url = get_img_path(self.parent_comment_1) self.assertEqual(url, '/static/img/default.png') - def test_render_comments(self): - request = self.factory.get('/') - request.user = self.user_1 - comments_per_page = 'COMMENT_PER_PAGE' - patch.object(settings, comments_per_page, 0).start() + +class RenderCommentsTest(BaseTemplateTagsTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.request = cls.factory.get('/') + cls.request.user = cls.user_1 + + @patch.object(settings, 'COMMENT_PER_PAGE', 0) + def test_without_pagination(self): count = self.post_1.comments.filter_parents_by_object(self.post_1).count() - data = render_comments(self.post_1, request) + data = render_comments(self.post_1, self.request) - # no pagination self.assertEqual(data['comments'].count(), count) # parent comment only self.assertEqual(data['login_url'], settings.LOGIN_URL) # check if `request` object is passed in context template - self.assertEqual(data['request'], request) + self.assertEqual(data['request'], self.request) @patch.object(settings, 'LOGIN_URL', None) - def test_render_comments_without_login_url(self): - request = self.factory.get('/') - request.user = self.user_1 + def test_without_login_url(self): with self.assertRaises(ImproperlyConfigured) as error: - render_comments(self.post_1, request) + render_comments(self.post_1, self.request) self.assertIsInstance(error.exception, ImproperlyConfigured) @patch.object(settings, 'COMMENT_PER_PAGE', 2) - def test_render_comments_with_pagination(self): + def test_with_pagination(self): request = self.factory.get('/?page=2') request.user = self.user_1 data = render_comments(self.post_1, request) @@ -96,23 +106,30 @@ def test_render_comments_with_pagination(self): self.assertEqual(data['comments'].number, 2) # 3 comment fit in 2 pages self.assertEqual(data['login_url'], settings.LOGIN_URL) - # check not integer page + def test_non_integral_page_number(self): request = self.factory.get('/?page=string') request.user = self.user_1 data = render_comments(self.post_1, request) self.assertIs(data['comments'].has_previous(), False) - # check empty page + @patch.object(settings, 'COMMENT_PER_PAGE', 2) + def test_empty_page(self): request = self.factory.get('/?page=10') request.user = self.user_1 data = render_comments(self.post_1, request) self.assertIs(data['comments'].has_previous(), True) - def test_static_functions(self): + +class TestStaticFunctions(BaseTemplateTagsTest): + def test_include_static(self): self.assertEqual(include_static(), '') + + def test_include_bootstrap(self): self.assertIsNone(include_bootstrap()) - def test_render_field(self): + +class RenderFieldTest(BaseTemplateTagsTest): + def test_success(self): request = self.factory.get('/') request.user = self.user_1 form = CommentForm(request=request) @@ -121,76 +138,86 @@ def test_render_field(self): field = render_field(field, placeholder='placeholder') self.assertEqual(field.field.widget.attrs.get('placeholder'), 'placeholder') + +class RenderContentTest(BaseTemplateTagsTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.comment = cls.parent_comment_1 + cls.content = "Any long text just for testing render content function" + cls.comment.content = cls.content + cls.comment.save() + cls.comment.refresh_from_db() + + def test_urlhash(self): + result = render_content(self.comment) + self.assertEqual(result['urlhash'], self.comment.urlhash) + @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 10) - def test_render_content(self): - comment = self.parent_comment_1 - content = "Any long text just for testing render content function" - comment.content = content - comment.save() - content_words = comment.content.split() - self.assertEqual(len(content_words), len(content.split())) + def test_content_wrapping(self): + content_words = self.comment.content.split() + self.assertEqual(len(content_words), len(self.content.split())) - result = render_content(comment) - # test urlhash - self.assertEqual(result['urlhash'], comment.urlhash) - # truncate number is bigger than content words - self.assertEqual(result['text_1'], comment.content) + result = render_content(self.comment) + # truncate number is bigger than self.contentwords + self.assertEqual(result['text_1'], self.comment.content) self.assertIsNone(result['text_2']) - def test_single_line_breaks_in_render_content(self): + def test_single_line_breaks(self): comment = self.parent_comment_1 comment.content = "Any long text\njust for testing render\ncontent function" + comment.save() + comment.refresh_from_db() result = render_content(comment) self.assertIn('
', result['text_1']) self.assertNotIn('

', result['text_1']) - def test_multiple_line_breaks_in_render_content(self): + def test_multiple_line_breaks(self): comment = self.parent_comment_1 comment.content = "Any long text\n\njust for testing render\n\n\ncontent function" + comment.save() + comment.refresh_from_db() result = render_content(comment) self.assertIn('

', result['text_1']) self.assertNotIn('


', result['text_1']) - def test_render_content_with_passing_value(self): - comment = self.parent_comment_1 - content = "Any long text just for testing render content function" - comment.content = content - comment.save() - content_words = comment.content.split() - self.assertEqual(len(content_words), len(content.split())) + def test_wrapping_after_certain_length(self): + self.comment.refresh_from_db() + content_words = self.comment.content.split() + self.assertEqual(len(content_words), len(self.content.split())) - result = render_content(comment, 5) - # test urlhash - self.assertEqual(result['urlhash'], comment.urlhash) - # truncate number is smaller than content words - self.assertEqual(result['text_1'], ' '.join(content_words[:5])) - self.assertEqual(result['text_2'], ' '.join(content_words[5:])) + truncate_words_after = 5 + result = render_content(self.comment, truncate_words_after) - @patch.object(settings, 'COMMENT_USE_EMAIL_FIRST_PART_AS_USERNAME', True) - def test_get_username_for_comment_use_email_first_part_enabled(self): - comment = self.create_comment(self.content_object_1, user=self.user_1) + # truncate number is smaller than words in content + self.assertEqual(result['text_1'], ' '.join(content_words[:truncate_words_after])) + self.assertEqual(result['text_2'], ' '.join(content_words[truncate_words_after:])) - self.assertEqual(get_username_for_comment(comment), comment.user.username) - # test for anonymous - anonymous_comment = self.create_anonymous_comment() +class GetUsernameForCommentTest(BaseTemplateTagsTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.comment = cls.create_comment(cls.content_object_1, user=cls.user_1) + cls.anonymous_comment = cls.create_anonymous_comment() - self.assertEqual(get_username_for_comment(anonymous_comment), anonymous_comment.email.split('@')[0]) + @patch.object(settings, 'COMMENT_USE_EMAIL_FIRST_PART_AS_USERNAME', True) + def test_use_email_first_part_enabled(self): + self.assertEqual(get_username_for_comment(self.comment), self.comment.user.username) - @patch.object(settings, 'COMMENT_USE_EMAIL_FIRST_PART_AS_USERNAME', False) - def test_get_username_for_comment_use_email_first_part_disabled(self): - comment = self.create_comment(self.content_object_1, user=self.user_1) + # test for anonymous + self.assertEqual(get_username_for_comment(self.anonymous_comment), self.anonymous_comment.email.split('@')[0]) - self.assertEqual(get_username_for_comment(comment), comment.user.username) + @patch.object(settings, 'COMMENT_USE_EMAIL_FIRST_PART_AS_USERNAME', False) + def test_use_email_first_part_disabled(self): + self.assertEqual(get_username_for_comment(self.comment), self.comment.user.username) # test for anonymous - anonymous_comment = self.create_anonymous_comment() - - self.assertEqual(get_username_for_comment(anonymous_comment), settings.COMMENT_ANONYMOUS_USERNAME) + self.assertEqual(get_username_for_comment(self.anonymous_comment), settings.COMMENT_ANONYMOUS_USERNAME) class ReactionTemplateTagsTest(BaseTemplateTagsTest): diff --git a/comment/tests/test_utils.py b/comment/tests/test_utils.py index 0bdc397..0f3df0b 100644 --- a/comment/tests/test_utils.py +++ b/comment/tests/test_utils.py @@ -1,4 +1,3 @@ -from unittest import TestCase from unittest.mock import patch from django.core.exceptions import ImproperlyConfigured @@ -15,94 +14,109 @@ from comment.messages import ErrorMessage -class CommentUtilsTest(BaseCommentUtilsTest): - def test_get_model_object(self): +class GetModelObjectTest(BaseCommentUtilsTest): + def test_success(self): data = { 'app_name': 'post', 'model_name': 'Post', 'model_id': self.post_1.id } model_object = get_model_obj(**data) - self.assertIsNotNone(model_object) self.assertIsInstance(model_object, self.post_1.__class__) - def test_get_gravatar_img(self): - with patch.object(settings, 'COMMENT_USE_GRAVATAR', True): - # email is not provided - default_profile_pic_loc = settings.COMMENT_DEFAULT_PROFILE_PIC_LOC - self.assertEqual(get_gravatar_img(''), default_profile_pic_loc) - # email is provided - self.assertTrue(get_gravatar_img('test').startswith('https://www.gravatar.com/avatar/')) +class GetGratavarImgTest(BaseCommentUtilsTest): + @patch.object(settings, 'COMMENT_USE_GRAVATAR', True) + def test_without_email(self): + self.assertEqual(get_gravatar_img(''), settings.COMMENT_DEFAULT_PROFILE_PIC_LOC) + + @patch.object(settings, 'COMMENT_USE_GRAVATAR', True) + def test_with_email(self): + self.assertTrue(get_gravatar_img('test').startswith('https://www.gravatar.com/avatar/')) - # gravatar is disabled - with patch.object(settings, 'COMMENT_USE_GRAVATAR', False): - self.assertEqual(get_gravatar_img(''), default_profile_pic_loc) + @patch.object(settings, 'COMMENT_USE_GRAVATAR', False) + def test_disabling(self): + self.assertEqual(get_gravatar_img(''), settings.COMMENT_DEFAULT_PROFILE_PIC_LOC) - def test_get_profile_instance(self): - # wrong content type - with patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong'): - self.assertIsNone(get_profile_instance(self.user_1)) - # correct data - with patch.object(settings, 'PROFILE_MODEL_NAME', 'userprofile'): - self.assertIsNotNone(get_profile_instance(self.user_1)) +class GetProfileInstanceTest(BaseCommentUtilsTest): + @patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong') + def test_wrong_content_type(self): + self.assertIsNone(get_profile_instance(self.user_1)) - # profile model has no user related model - with patch.object(settings, 'PROFILE_MODEL_NAME', None): - self.assertIsNone(get_profile_instance(self.user_1)) + @patch.object(settings, 'PROFILE_MODEL_NAME', 'userprofile') + def test_correct_content_type(self): + self.assertIsNotNone(get_profile_instance(self.user_1)) - @patch.object(settings, 'COMMENT_USE_GRAVATAR', False) - def test_has_valid_profile(self): - with patch.object(settings, 'PROFILE_APP_NAME', 'user_profile'): - with patch.object(settings, 'PROFILE_MODEL_NAME', 'userprofile'): - self.assertIs(has_valid_profile(), True) + @patch.object(settings, 'PROFILE_MODEL_NAME', None) + def test_profile_model_is_not_associated_with_user(self): + self.assertIsNone(get_profile_instance(self.user_1)) + + +@patch.object(settings, 'COMMENT_USE_GRAVATAR', False) +@patch.object(settings, 'PROFILE_APP_NAME', 'user_profile') +class HasValidProfileTest(BaseCommentUtilsTest): + def test_success(self): + self.assertIs(has_valid_profile(), True) + + def test_model_provided_without_image(self): + with patch('comment.utils.hasattr', return_value=False): + self.assertIs(has_valid_profile(), False) - # settings attr provided, profile model has no image - with patch('comment.utils.hasattr', return_value=False): - self.assertIs(has_valid_profile(), False) + @patch.object(settings, 'PROFILE_MODEL_NAME', '') + def test_missing_setting_attribute(self): + self.assertIs(has_valid_profile(), False) - # one of settings attribute is missing - with patch.object(settings, 'PROFILE_MODEL_NAME', ''): - self.assertIs(has_valid_profile(), False) + @patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong_value') + def test_wrong_setting_attribute(self): + self.assertIs(has_valid_profile(), False) - # settings attr provided with wrong value - with patch.object(settings, 'PROFILE_MODEL_NAME', 'wrong_value'): - self.assertIs(has_valid_profile(), False) + @patch.object(settings, 'COMMENT_USE_GRAVATAR', True) + def test_gravatar_enabled(self): + self.assertIs(has_valid_profile(), True) - with patch.object(settings, 'COMMENT_USE_GRAVATAR', True): - self.assertIs(has_valid_profile(), True) +class IsCommentModeratorTest(BaseCommentUtilsTest): @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', False) - def test_is_comment_moderator_no_moderation(self): - self.assertFalse(is_comment_moderator(self.moderator)) + def test_flagging_disabled(self): + self.assertIs(is_comment_moderator(self.moderator), False) + +class IsCommentAdminTest(BaseCommentUtilsTest): @patch.object(settings, 'COMMENT_FLAGS_ALLOWED', False) - def test_is_comment_admin_no_moderation(self): - self.assertFalse(is_comment_admin(self.admin)) - - def test_user_for_request(self): - request = self.factory.get('/') - request.user = AnonymousUser() - # test unauthenticated user - self.assertIsNone(get_user_for_request(request)) - # test authenticated user - request.user = self.user_1 - self.assertEqual(get_user_for_request(request), self.user_1) + def test_flagging_disabled(self): + self.assertIs(is_comment_admin(self.admin), False) + + +class GetUserForRequestTest(BaseCommentUtilsTest): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.request = cls.factory.get('/') + + def test_unauthenticated_user(self): + self.request.user = AnonymousUser() + self.assertIsNone(get_user_for_request(self.request)) + def test_authenticated_user(self): + self.request.user = self.user_1 + self.assertEqual(get_user_for_request(self.request), self.user_1) + + +class GetWrappedWordsNumberTest(BaseCommentUtilsTest): @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', None) - def test_get_wrapped_words_number_return_0_for_None(self): + def test_using_None(self): self.assertEqual(get_wrapped_words_number(), 0) @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 'test') - def test_get_wrapped_words_number_fails_on_non_int_value(self): + def test_using_non_integeral_value(self): with self.assertRaises(ImproperlyConfigured) as e: get_wrapped_words_number() self.assertEqual(str(e.exception), ErrorMessage.WRAP_CONTENT_WORDS_NOT_INT) self.assertTextTranslated(ErrorMessage.WRAP_CONTENT_WORDS_NOT_INT) @patch.object(settings, 'COMMENT_WRAP_CONTENT_WORDS', 20) - def test_get_wrapped_words_number_return_specified_setting_value(self): + def test_using_integer_value(self): self.assertEqual(get_wrapped_words_number(), 20) @@ -188,9 +202,7 @@ def test_success(self): self.assertIsInstance(response.obj, Comment) -class UtilsTest(TestCase): - """Test general purpose utilities that aren't necessarily related to a comment""" - +class TestIdGenerator(BaseCommentUtilsTest): def setUp(self): self.len_id = 6 diff --git a/comment/tests/test_validators.py b/comment/tests/test_validators.py index 5f16a05..d20d5d1 100644 --- a/comment/tests/test_validators.py +++ b/comment/tests/test_validators.py @@ -26,14 +26,16 @@ def get(self, request, *args, **kwargs): class CustomValidationTest(TestCase): - def test_can_create_custom_validation(self): - # no params + + def test_without_param(self): validator = CommentBadRequest() + self.assertEqual(validator.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(validator.detail, ExceptionError.BAD_REQUEST) - # with params + def test_with_params(self): validator = CommentBadRequest(detail='Not Found', status_code=404) + self.assertEqual(validator.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(validator.detail, "Not Found") @@ -50,6 +52,7 @@ def test_missing_app_name(self): url_data.pop('app_name') request = self.factory.get(self.get_url(**url_data)) response = self.view.dispatch(request) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(self.view.error, ContentTypeError.APP_NAME_MISSING) @@ -138,6 +141,7 @@ def test_api_case_success(self): view = MockedContentTypeValidatorAPIView() request = self.factory.get(self.get_url(**self.data)) response = view.dispatch(request) + self.assertEqual(response.status_code, 200) def test_api_case_missing_app_name(self): @@ -146,6 +150,7 @@ def test_api_case_missing_app_name(self): url_data.pop('app_name') request = self.factory.get(self.get_url(**url_data)) response = view.dispatch(request) + self.assertEqual(response.status_code, 400) self.assertEqual(response.data['detail'], view.error) @@ -153,11 +158,13 @@ def test_api_case_missing_app_name(self): class ValidateOrderTest(TestCase): def test_success(self): order = ['-reaction__likes'] + with patch.object(settings, 'COMMENT_ORDER_BY', order): self.assertEqual(_validate_order(), order) def test_incorrect_value_raises_exception(self): order = ['err'] + with patch.object(settings, 'COMMENT_ORDER_BY', order): with self.assertRaises(ImproperlyConfigured) as error: _validate_order() @@ -169,6 +176,7 @@ def test_incorrect_value_raises_exception(self): def test_duplicate_value_raises_exception(self): order = ['posted', '-posted'] + with patch.object(settings, 'COMMENT_ORDER_BY', order): with self.assertRaises(ImproperlyConfigured) as error: _validate_order() diff --git a/comment/tests/test_views/test_comments.py b/comment/tests/test_views/test_comments.py index a9e3d5d..b444c55 100644 --- a/comment/tests/test_views/test_comments.py +++ b/comment/tests/test_views/test_comments.py @@ -50,11 +50,13 @@ def test_create_parent_comment(self): url = self.get_create_url() response = self.client.post(url, data=self.data) + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'comment/comments/base.html') self.assertHtmlTranslated(response.content, url) parent_comment = Comment.objects.get(object_id=self.post_1.id, parent=None) + self.assertEqual(response.context.get('comment').id, parent_comment.id) self.assertTrue(response.context.get('comment').is_parent) @@ -91,12 +93,14 @@ def test_send_notification_to_thread_followers_on_create_comment(self): self.assertEqual(len(mail.outbox), 0) url = self.get_create_url() response = self.client.post(url, data=self.data) + self.assertEqual(response.status_code, 200) response.context['view'].email_service._email_thread.join() self.assertEqual(len(mail.outbox), 1) def test_create_comment_non_ajax_request(self): response = self.client_non_ajax.post(self.get_create_url(), data=self.data) + self.assertEqual(response.status_code, 400) @patch.object(settings, 'COMMENT_ALLOW_ANONYMOUS', True) @@ -108,11 +112,13 @@ def test_create_anonymous_comment(self): self.assertEqual(len(mail.outbox), 0) response = self.client.post(url, data=data) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTemplateUsed(response, 'comment/comments/base.html') self.assertEqual(response.json()['msg'], EmailInfo.CONFIRMATION_SENT) # confirmation email is sent response.context['view'].email_service._email_thread.join() + self.assertEqual(len(mail.outbox), 1) # no change in comment count @@ -126,6 +132,7 @@ def test_create_anonymous_comment_with_invalid_email(self): url = self.get_create_url() response = self.client.post(url, data=data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.json()['error'], EmailError.EMAIL_INVALID) @@ -150,6 +157,7 @@ def test_edit_comment(self): get_url = self.get_url('comment:edit', comment.id, data) self.assertEqual(comment.content, 'comment 2') response = self.client.get(get_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) self.assertTemplateUsed('comment/comments/update_comment.html') self.assertHtmlTranslated(response.content, get_url) @@ -157,6 +165,7 @@ def test_edit_comment(self): post_url = self.get_url('comment:edit', comment.id) response = self.client.post(post_url, data=data, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 200) self.assertTemplateUsed('comment/comments/comment_content.html') self.assertHtmlTranslated(response.content, post_url) @@ -181,10 +190,12 @@ def test_cannot_edit_comment_by_different_user(self): } self.assertEqual(comment.user.username, self.user_1.username) response = self.client.get(self.get_url('comment:edit', comment.id), data=data) + self.assertEqual(response.status_code, 403) self.assertEqual(response.reason_phrase, 'Forbidden') response = self.client.post(self.get_url('comment:edit', comment.id), data=data) + self.assertEqual(response.status_code, 403) self.assertEqual(response.reason_phrase, 'Forbidden') @@ -202,6 +213,7 @@ def test_delete_comment(self): self.assertEqual(init_count, 1) get_url = self.get_url('comment:delete', comment.id, self.data) response = self.client.get(get_url, data=self.data) + self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'comment/comments/comment_modal.html') self.assertContains(response, 'data') @@ -227,6 +239,7 @@ def test_delete_comment_by_moderator(self): self.assertEqual(init_count, 1) # moderator cannot delete un-flagged comment response = self.client.post(self.get_url('comment:delete', comment.id), data=self.data) + self.assertEqual(response.status_code, 403) # moderator can delete flagged comment @@ -345,6 +358,7 @@ def test_success_with_notification(self): view = ConfirmComment() response = view.get(request, key=self.key) comment = Comment.objects.get(email=self.comment_obj.email, posted=self.time_posted) + self.assertEqual(Comment.objects.all().count(), self.init_count + 1) self.assertEqual(response.status_code, status.HTTP_302_FOUND) self.assertEqual(response.url, comment.get_url(self.request)) diff --git a/comment/tests/test_views/test_flags.py b/comment/tests/test_views/test_flags.py index de25334..78c1d22 100644 --- a/comment/tests/test_views/test_flags.py +++ b/comment/tests/test_views/test_flags.py @@ -31,6 +31,7 @@ def test_set_flag(self): 'error': None, 'msg': FlagInfo.FLAGGED_SUCCESS } + self.assertEqual(response.status_code, 200) server_response = response.json() self.assertDictEqual(server_response, response_data) @@ -42,6 +43,7 @@ def test_set_flag_when_flagging_not_enabled(self): _url = self.get_url('comment:flag', self.comment.id) self.flag_data['reason'] = 1 response = self.client.post(_url, data=self.flag_data) + self.assertEqual(response.status_code, 403) def test_set_flag_for_flagging_old_comments(self): @@ -60,6 +62,7 @@ def test_set_flag_for_flagging_old_comments(self): 'error': None, 'msg': FlagInfo.FLAGGED_SUCCESS } + self.assertEqual(response.status_code, 200) server_response = response.json() self.assertDictEqual(server_response, response_data) @@ -80,6 +83,7 @@ def test_set_flag_for_unflagging(self): } self.assertEqual(response.status_code, 200) server_response = response.json() + self.assertDictEqual(server_response, response_data) self.assertTextTranslated(server_response['msg'], _url) @@ -88,6 +92,7 @@ def test_set_flag_for_unauthenticated_user(self): url = self.get_url('comment:flag', self.comment.id).replace('?', '') self.client.logout() response = self.client.post(url, data=self.flag_data) + self.assertEqual(response.status_code, status.HTTP_302_FOUND) self.assertEqual(response.url, '{}?next={}'.format(settings.LOGIN_URL, url)) @@ -95,18 +100,21 @@ def test_get_request(self): """Test whether GET requests are allowed or not""" url = self.get_url('comment:flag', self.comment.id) response = self.client.get(url, data=self.flag_data) + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) def test_non_ajax_requests(self): """Test response if non AJAX requests are sent""" url = self.get_url('comment:flag', self.comment.id) response = self.client_non_ajax.post(url, data=self.flag_data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_incorrect_comment_id(self): """Test response when an incorrect comment id is passed""" url = self.get_url('comment:flag', 102_876) response = self.client.post(url, data=self.flag_data) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_incorrect_reason(self): @@ -116,6 +124,7 @@ def test_incorrect_reason(self): reason = -1 data.update({'reason': reason}) response = self.client.post(url, data=data) + self.assertEqual(response.status_code, 400) @@ -135,6 +144,7 @@ def test_change_flag_state_for_unflagged_comment(self): self.client.force_login(self.moderator) self.assertEqual(int(self.client.session['_auth_user_id']), self.moderator.id) response = self.client.post(self.get_url('comment:flag-change-state', comment.id), data=self.data) + self.assertEqual(response.status_code, 400) def test_change_flag_state_by_not_permitted_user(self): @@ -144,6 +154,7 @@ def test_change_flag_state_by_not_permitted_user(self): response = self.client.post( self.get_url('comment:flag-change-state', self.comment_for_change_state.id), data=self.data ) + self.assertEqual(response.status_code, 403) def test_change_flag_state_with_wrong_state_value(self): @@ -157,6 +168,7 @@ def test_change_flag_state_with_wrong_state_value(self): response = self.client.post( self.get_url('comment:flag-change-state', self.comment_for_change_state.id), data=self.data ) + self.assertEqual(response.status_code, 400) self.assertEqual(response.json()['error'], FlagError.STATE_CHANGE_ERROR) self.assertEqual(self.comment_for_change_state.flag.state, self.comment_for_change_state.flag.FLAGGED) @@ -172,6 +184,7 @@ def test_change_flag_state_success(self): response = self.client.post( self.get_url('comment:flag-change-state', self.comment_for_change_state.id), data=self.data ) + self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['data']['state'], self.comment_for_change_state.flag.REJECTED) self.comment_for_change_state.flag.refresh_from_db() diff --git a/comment/tests/test_views/test_reactions.py b/comment/tests/test_views/test_reactions.py index fa502e4..28cfba9 100644 --- a/comment/tests/test_views/test_reactions.py +++ b/comment/tests/test_views/test_reactions.py @@ -32,6 +32,7 @@ def test_set_reaction_for_authenticated_users(self): 'anonymous': False, 'error': None, } + self.assertEqual(response.status_code, status.HTTP_200_OK) server_response = response.json() self.assertDictEqual(server_response, data) @@ -53,6 +54,7 @@ def test_set_reaction_for_old_comments(self): 'anonymous': False, 'error': None, } + self.assertEqual(response.status_code, status.HTTP_200_OK) server_response = response.json() self.assertDictEqual(server_response, data) @@ -63,6 +65,7 @@ def test_set_reaction_for_unauthenticated_users(self): _url = self.get_reaction_url(self.comment.id, 'dislike') self.client.logout() response = self.client.post(_url) + self.assertEqual(response.status_code, status.HTTP_302_FOUND) self.assertEqual(response.url, '{}?next={}'.format(settings.LOGIN_URL, _url)) @@ -70,27 +73,32 @@ def test_get_request(self): """Test whether GET requests are allowed or not""" _url = self.get_reaction_url(self.comment.id, 'like') response = self.client.get(_url) + self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) def test_non_ajax_requests(self): """Test response if non AJAX requests are sent""" _url = self.get_reaction_url(self.comment.id, 'like') response = self.client_non_ajax.post(_url) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_incorrect_comment_id(self): """Test response when an incorrect comment id is passed""" _url = self.get_reaction_url(102_876, 'like') response = self.client.post(_url) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) def test_incorrect_reaction(self): """Test response when incorrect reaction is passed""" _url = self.get_reaction_url(self.comment.id, 'likes') response = self.client.post(_url) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # test incorrect type _url = self.get_reaction_url(self.comment.id, 1) response = self.client.post(_url) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/comment/tests/test_views/test_subscription.py b/comment/tests/test_views/test_subscription.py index d8df8cb..777f410 100644 --- a/comment/tests/test_views/test_subscription.py +++ b/comment/tests/test_views/test_subscription.py @@ -11,7 +11,7 @@ def setUp(self): super().setUp() self.view = BaseToggleFollowView() self.toggle_follow_url = self.get_url( - reverse('toggle-subscription'), app_name='comment', model_name='comment', model_id=self.comment.id + reverse('comment:toggle-subscription'), app_name='comment', model_name='comment', model_id=self.comment.id ) def test_assertion_error_on_missing_request_class(self): @@ -19,11 +19,13 @@ def test_assertion_error_on_missing_request_class(self): def test_success_on_providing_request_class(self): self.view.response_class = 'test' + self.assertEqual(self.view.get_response_class(), self.view.response_class) def test_email_required_to_follow_object(self): self.client.force_login(self.user_without_email) response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(response.status_code, 400) self.assertEqual( response.json()['error']['email_required'], FollowError.EMAIL_REQUIRED.format(model_object=self.comment) @@ -32,6 +34,7 @@ def test_email_required_to_follow_object(self): def test_invalid_email(self): data = {'email': 'invalid_email'} response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest', data=data) + self.assertEqual(response.status_code, 400) self.assertEqual(response.json()['error']['invalid_email'], EmailError.EMAIL_INVALID) @@ -41,6 +44,7 @@ def test_toggle_follow_for_valid_email(self): data = {'email': 't@t.com'} self.assertFalse(Follower.objects.is_following(data['email'], self.comment)) response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest', data=data) + self.assertEqual(response.status_code, 200) self.assertTrue(response.json()['data']['following']) self.assertEqual(response.json()['data']['model_id'], self.comment.id) @@ -53,6 +57,7 @@ def test_provide_email_for_user_has_already_email(self): data = {'email': 't@t.com'} self.assertFalse(Follower.objects.is_following(data['email'], self.comment)) response = self.client.post(self.toggle_follow_url, HTTP_X_REQUESTED_WITH='XMLHttpRequest', data=data) + self.assertEqual(response.status_code, 200) self.assertTrue(response.json()['data']['following']) self.assertEqual(response.json()['data']['model_id'], self.comment.id)