Coverage for src/mesh/tests/models/test_review_models.py: 100%
115 statements
« prev ^ index » next coverage.py v7.9.0, created at 2026-02-04 09:42 +0000
« prev ^ index » next coverage.py v7.9.0, created at 2026-02-04 09:42 +0000
1from datetime import date, timedelta
2from unittest.mock import patch
4from django.db import transaction
5from django.db.utils import IntegrityError
7from mesh.model.exceptions import ReviewStateError
9from ...models.factories import ReviewFactory, UserFactory
10from ...models.review_models import Review, ReviewState
11from ...models.submission_models import Submission, SubmissionLog
12from ...models.user_models import User
13from ..base_test_case import BaseTestCase
16class ReviewTestCase(BaseTestCase):
17 used_models = [Submission]
18 class_used_models = [User]
20 @classmethod
21 def setUpClass(cls) -> None:
22 super().setUpClass()
23 cls.user_reviewer = UserFactory.create()
25 def test_unique_reviewer_per_round(self):
26 review = ReviewFactory.create()
27 self.assertEqual(review.state, ReviewState.AWAITING_ACCEPTANCE.value)
29 # We need to encapsulate the database exception in a transaction, otherwise
30 # successive DB operations are not permitted.
31 with transaction.atomic():
32 self.assertRaises(
33 IntegrityError,
34 ReviewFactory.create,
35 reviewer=review.reviewer,
36 version=review.version,
37 )
39 def test_is_response_overdue(self):
40 review = ReviewFactory.create()
41 review.date_response_due = date.today()
42 self.assertFalse(review.is_response_overdue)
44 review.date_response_due -= timedelta(days=1)
45 self.assertTrue(review.is_response_overdue)
47 review.accepted = True
48 self.assertFalse(review.is_response_overdue)
50 def test_is_report_overdue(self):
51 review = ReviewFactory.create()
52 review.date_review_due = date.today()
53 review.accepted = False
54 review.submitted = False
56 with patch.object(Review, "is_response_overdue", False):
57 self.assertFalse(review.is_report_overdue)
59 review.date_review_due -= timedelta(days=1)
60 self.assertFalse(review.is_report_overdue)
62 review.accepted = True
63 self.assertTrue(review.is_report_overdue)
65 review.submitted = True
66 self.assertFalse(review.is_report_overdue)
68 with patch.object(Review, "is_response_overdue", True):
69 self.assertTrue(review.is_report_overdue)
71 def test_is_completed(self):
72 review = ReviewFactory.create()
73 review.accepted = None
74 review.submitted = False
75 self.assertFalse(review.is_completed)
77 review.accepted = True
78 self.assertFalse(review.is_completed)
80 review.submitted = True
81 self.assertTrue(review.is_completed)
83 review.submitted = False
84 review.accepted = False
85 self.assertTrue(review.is_completed)
87 def test_is_editable(self):
88 review = ReviewFactory.create()
89 review.submitted = True
90 review.version.review_open = False
92 self.assertFalse(review.is_editable)
94 review.submitted = False
95 self.assertFalse(review.is_editable)
97 review.version.review_open = True
98 self.assertTrue(review.is_editable)
100 def test_accept(self):
101 review = ReviewFactory.create()
102 accept_value = True
103 accept_comment = "<p>My comment</p>"
104 request = self.dummy_request()
105 request.user = review.reviewer
107 self.assertIsNone(review.accepted)
108 self.assertEqual(
109 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 0
110 )
112 with patch.object(Review, "is_editable", False):
113 self.assertRaises(
114 ReviewStateError,
115 review.accept,
116 accept_value,
117 accept_comment,
118 review.reviewer,
119 )
120 self.assertEqual(
121 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 0
122 )
123 review = Review.objects.get(pk=review.pk)
124 self.assertEqual(review.state, ReviewState.AWAITING_ACCEPTANCE.value)
125 self.assertIsNone(review.accepted)
127 with patch.object(Review, "is_editable", True):
128 review.accept(accept_value, accept_comment, review.reviewer)
129 self.assertEqual(
130 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 1
131 )
132 review = Review.objects.get(pk=review.pk)
133 self.assertEqual(review.state, ReviewState.PENDING.value)
134 self.assertTrue(review.accepted)
135 self.assertEqual(review.accept_comment, accept_comment)
137 review = ReviewFactory.create()
138 accept_value = False
139 accept_comment = "<p>My comment</p>"
140 request = self.dummy_request()
141 request.user = review.reviewer
143 with patch.object(Review, "is_editable", True):
144 review.accept(accept_value, accept_comment, review.reviewer)
145 self.assertEqual(
146 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 1
147 )
148 review = Review.objects.get(pk=review.pk)
149 self.assertEqual(review.state, ReviewState.DECLINED.value)
150 self.assertFalse(review.accepted)
152 def test_submit(self):
153 review = ReviewFactory.create(accepted=True, state=ReviewState.PENDING.value)
154 request = self.dummy_request()
155 request.user = review.reviewer
157 self.assertFalse(review.submitted)
158 self.assertEqual(review.state, ReviewState.PENDING.value)
159 self.assertEqual(
160 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 0
161 )
163 with patch.object(Review, "is_submittable", False):
164 self.assertRaises(ReviewStateError, review.submit, review.reviewer)
165 self.assertFalse(review.submitted)
166 self.assertEqual(review.state, ReviewState.PENDING.value)
167 self.assertEqual(
168 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 0
169 )
171 with patch.object(Review, "is_submittable", True):
172 review.submit(review.reviewer)
173 self.assertTrue(review.submitted)
174 self.assertEqual(review.state, ReviewState.SUBMITTED.value)
175 self.assertEqual(
176 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 1
177 )