changeset 1221:d6b3f7e77f6c modernize tip

Add unit tests for comments views.
author Brian Neal <bgneal@gmail.com>
date Sat, 01 Mar 2025 15:52:11 -0600
parents d63f9ece1129
children
files comments/tests/__init__.py comments/tests/test_views.py comments/views.py
diffstat 2 files changed, 241 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/comments/tests/test_views.py	Sat Mar 01 15:52:11 2025 -0600
@@ -0,0 +1,236 @@
+"""
+Unit tests for the comments app views.
+
+"""
+from datetime import datetime, timedelta
+
+from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
+from django.core.urlresolvers import reverse
+from django.test import TestCase
+from mock import ANY, call, patch
+
+from comments.models import Comment, CommentFlag
+from potd.models import Current, Photo
+
+
+class PostCommentTestCase(TestCase):
+    def setUp(self):
+        self.user = User.objects.create_user('pjmoto', '', 'pw')
+        self.user.save()
+        self.client.login(username='pjmoto', password='pw')
+        self.post_url = reverse('comments-post')
+        potd1 = Photo(pk=4096, user=self.user, date_added=datetime.today())
+        potd1.save()
+        potd2 = Photo(pk=8192, user=self.user, date_added=datetime.today())
+        potd2.save()
+        current = Current(potd=potd2)
+        current.save()
+
+    def test_no_ctype_or_object(self):
+        response = self.client.post(self.post_url, data={})
+        self.assertEqual(response.status_code, 400)
+
+    def test_no_ctype(self):
+        response = self.client.post(self.post_url, data={
+            'object_pk': '4096',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    def test_no_object(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'bulletins.Bulletin',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    def test_invalid_model(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'wut.Model',
+            'object_pk': '4096',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    def test_bad_content_type(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'wut',
+            'object_pk': '4096',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    def test_object_does_not_exist(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'potd.Photo',
+            'object_pk': '1024',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    def test_cannot_comment_on_object(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'potd.Photo',
+            'object_pk': '4096',
+        })
+        self.assertEqual(response.status_code, 403)
+
+    def test_form_is_not_valid(self):
+        response = self.client.post(self.post_url, data={
+            'content_type': 'potd.Photo',
+            'object_pk': '8192',
+            'comment': '',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    @patch('comments.views.antispam.utils.spam_check')
+    def test_comment_fails_spam_check(self, spam_check_mock):
+        spam_check_mock.return_value = True
+        response = self.client.post(self.post_url, data={
+            'content_type': 'potd.Photo',
+            'object_pk': '8192',
+            'comment': 'spam!',
+        })
+        self.assertEqual(response.status_code, 403)
+        self.assertEqual(spam_check_mock.mock_calls, [
+            call(ANY, 'spam!'),
+        ])
+
+    @patch('comments.views.antispam.utils.spam_check')
+    def test_happy_path(self, spam_check_mock):
+        spam_check_mock.return_value = False
+        response = self.client.post(self.post_url, data={
+            'content_type': 'potd.Photo',
+            'object_pk': '8192',
+            'comment': '**Nice**',
+        })
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(spam_check_mock.mock_calls, [
+            call(ANY, '**Nice**'),
+        ])
+        self.assertIn('<strong>Nice</strong>', response.content)
+
+        self.assertEqual(Comment.objects.count(), 1)
+        comments = Comment.objects.for_object(Photo.objects.get(pk=8192))
+        self.assertEqual(comments.count(), 1)
+        comment = comments[0]
+        self.assertEqual(comment.content_type.model, 'photo')
+        self.assertEqual(comment.object_id, 8192)
+        self.assertEqual(comment.user, self.user)
+        self.assertEqual(comment.comment, '**Nice**')
+        self.assertIn('<strong>Nice</strong>', comment.html)
+
+        now = datetime.now()
+        delta = timedelta(seconds=1)
+        self.assertGreater(comment.creation_date, now - delta)
+        self.assertLess(comment.creation_date, now + delta)
+        self.assertTrue(comment.is_public)
+        self.assertFalse(comment.is_removed)
+
+class FlagCommentTestCase(TestCase):
+    def setUp(self):
+        self.user = User.objects.create_user('pjmoto', '', 'pw')
+        self.user.save()
+        self.client.login(username='pjmoto', password='pw')
+        self.post_url = reverse('comments-flag')
+
+    def test_not_logged_in(self):
+        self.client.logout()
+        response = self.client.post(self.post_url, data={
+            'id': '8192',
+        })
+        self.assertEqual(response.status_code, 403)
+
+    def test_no_id_supplied(self):
+        response = self.client.post(self.post_url, data={})
+        self.assertEqual(response.status_code, 400)
+
+    def test_invalid_comment(self):
+        response = self.client.post(self.post_url, data={
+            'id': '8192',
+        })
+        self.assertEqual(response.status_code, 400)
+
+    @patch('comments.views.email_admins')
+    def test_happy_path(self, email_mock):
+        content_type = ContentType.objects.get(app_label='potd', model='photo')
+        c = Comment(content_type=content_type, object_id=512, user=self.user,
+                    comment='Nice', ip_address='127.0.0.1')
+        c.save()
+        response = self.client.post(self.post_url, data={
+            'id': str(c.pk)
+        })
+        self.assertEqual(response.status_code, 200)
+
+        self.assertEqual(email_mock.mock_calls, [
+            call('A Comment Has Been Flagged',
+                 'Hello,\n\nA user has flagged a comment for review.\n'),
+        ])
+
+        self.assertEqual(CommentFlag.objects.count(), 1)
+        flag = CommentFlag.objects.all()[0]
+        self.assertEqual(flag.user, self.user)
+        self.assertEqual(flag.comment.pk, c.pk)
+
+        now = datetime.now()
+        delta = timedelta(seconds=1)
+        self.assertGreater(flag.flag_date, now - delta)
+        self.assertLess(flag.flag_date, now + delta)
+
+class MarkdownPreviewTestCase(TestCase):
+    def setUp(self):
+        self.user = User.objects.create_user('pjmoto', '', 'pw')
+        self.user.save()
+        self.client.login(username='pjmoto', password='pw')
+        self.post_url = reverse('comments-markdown_preview')
+
+    def test_not_logged_in(self):
+        self.client.logout()
+        response = self.client.post(self.post_url, data={
+            'data': 'Test',
+        })
+        self.assertEqual(response.status_code, 403)
+
+    def test_no_data_supplied(self):
+        response = self.client.post(self.post_url, data={})
+        self.assertEqual(response.status_code, 400)
+
+    def test_happy_path(self):
+        response = self.client.post(self.post_url, data={
+            'data': 'Test',
+        })
+        self.assertEqual(response.status_code, 200)
+        expected_content = (
+            '<!DOCTYPE html>\n'
+            '<html lang="en">\n'
+            '<head>\n'
+            '<meta charset="utf-8" />\n'
+            '<title>Markdown Preview</title>\n'
+            '<link rel="stylesheet" href="/static/js/markitup/templates/preview.css" />\n'
+            '</head>\n'
+            '<p>Test</p>\n'
+            '</body>\n'
+            '</html>')
+        self.assertEqual(response.content.strip(), expected_content)
+
+class MarkdownPreviewV3TestCase(TestCase):
+    def setUp(self):
+        self.user = User.objects.create_user('pjmoto', '', 'pw')
+        self.user.save()
+        self.client.login(username='pjmoto', password='pw')
+        self.post_url = reverse('comments-markdown_preview_v3')
+
+    def test_not_logged_in(self):
+        self.client.logout()
+        response = self.client.post(self.post_url, data={
+            'data': 'Test',
+        })
+        self.assertEqual(response.status_code, 403)
+
+    def test_no_data_supplied(self):
+        response = self.client.post(self.post_url, data={})
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content, '')
+
+    def test_happy_path(self):
+        response = self.client.post(self.post_url, data={
+            'data': 'Test',
+        })
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content.strip(), '<p>Test</p>')
--- a/comments/views.py	Sun Feb 23 16:34:01 2025 -0600
+++ b/comments/views.py	Sat Mar 01 15:52:11 2025 -0600
@@ -53,10 +53,10 @@
     try:
         model = apps.get_model(*ctype.split('.', 1))
         target = model.objects.get(pk=object_pk)
-    except TypeError:
+    except LookupError:
         return HttpResponseBadRequest(
             "Invalid content_type value: %r" % escape(ctype))
-    except AttributeError:
+    except ValueError:
         return HttpResponseBadRequest(
             "The given content-type %r does not resolve to a valid model." % \
                 escape(ctype))
@@ -64,6 +64,8 @@
         return HttpResponseBadRequest(
             "No object matching content-type %r and object PK %r exists." % \
                 (escape(ctype), escape(object_pk)))
+    except:
+        return HttpResponseBadRequest('Unexpected error')
 
     # Can we comment on the target object?
     if hasattr(target, 'can_comment_on'):
@@ -110,7 +112,7 @@
     be the target of an AJAX post.
     """
     if not request.user.is_authenticated():
-        return HttpResponse('Please login or register to flag a comment.')
+        return HttpResponseForbidden('Please login or register to flag a comment.')
 
     id = request.POST.get('id', None)
     if id is None: