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

1from datetime import date, timedelta 

2from unittest.mock import patch 

3 

4from django.db import transaction 

5from django.db.utils import IntegrityError 

6 

7from mesh.model.exceptions import ReviewStateError 

8 

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 

14 

15 

16class ReviewTestCase(BaseTestCase): 

17 used_models = [Submission] 

18 class_used_models = [User] 

19 

20 @classmethod 

21 def setUpClass(cls) -> None: 

22 super().setUpClass() 

23 cls.user_reviewer = UserFactory.create() 

24 

25 def test_unique_reviewer_per_round(self): 

26 review = ReviewFactory.create() 

27 self.assertEqual(review.state, ReviewState.AWAITING_ACCEPTANCE.value) 

28 

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 ) 

38 

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) 

43 

44 review.date_response_due -= timedelta(days=1) 

45 self.assertTrue(review.is_response_overdue) 

46 

47 review.accepted = True 

48 self.assertFalse(review.is_response_overdue) 

49 

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 

55 

56 with patch.object(Review, "is_response_overdue", False): 

57 self.assertFalse(review.is_report_overdue) 

58 

59 review.date_review_due -= timedelta(days=1) 

60 self.assertFalse(review.is_report_overdue) 

61 

62 review.accepted = True 

63 self.assertTrue(review.is_report_overdue) 

64 

65 review.submitted = True 

66 self.assertFalse(review.is_report_overdue) 

67 

68 with patch.object(Review, "is_response_overdue", True): 

69 self.assertTrue(review.is_report_overdue) 

70 

71 def test_is_completed(self): 

72 review = ReviewFactory.create() 

73 review.accepted = None 

74 review.submitted = False 

75 self.assertFalse(review.is_completed) 

76 

77 review.accepted = True 

78 self.assertFalse(review.is_completed) 

79 

80 review.submitted = True 

81 self.assertTrue(review.is_completed) 

82 

83 review.submitted = False 

84 review.accepted = False 

85 self.assertTrue(review.is_completed) 

86 

87 def test_is_editable(self): 

88 review = ReviewFactory.create() 

89 review.submitted = True 

90 review.version.review_open = False 

91 

92 self.assertFalse(review.is_editable) 

93 

94 review.submitted = False 

95 self.assertFalse(review.is_editable) 

96 

97 review.version.review_open = True 

98 self.assertTrue(review.is_editable) 

99 

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 

106 

107 self.assertIsNone(review.accepted) 

108 self.assertEqual( 

109 len(SubmissionLog.objects.filter(attached_to=review.version.submission)), 0 

110 ) 

111 

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) 

126 

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) 

136 

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 

142 

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) 

151 

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 

156 

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 ) 

162 

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 ) 

170 

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 )