diff --git a/.coveragerc b/.coveragerc index 678e6a4..09b70e0 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,3 @@ [run] include = qa/* -omit = *migrations* +omit = *migrations*, *tests* diff --git a/qa/models.py b/qa/models.py index ecd8edb..11a4919 100644 --- a/qa/models.py +++ b/qa/models.py @@ -14,7 +14,7 @@ class UserQAProfile(models.Model): picture = models.ImageField(upload_to='qa/static/profile_images', blank=True) - def __str__(self): + def __str__(self): # pragma: no cover return self.user.username @@ -54,7 +54,7 @@ def save(self, *args, **kwargs): self.total_points = self.positive_votes - self.negative_votes super(Answer, self).save(*args, **kwargs) - def __str__(self): + def __str__(self): # pragma: no cover return self.answer_text @@ -87,7 +87,7 @@ class BaseComment(models.Model): class Meta: abstract = True - def __str__(self): + def __str__(self): # pragma: no cover return self.comment_text diff --git a/qa/tests/test_mixins.py b/qa/tests/test_mixins.py index ed605e6..f5d9017 100644 --- a/qa/tests/test_mixins.py +++ b/qa/tests/test_mixins.py @@ -99,6 +99,5 @@ def test_author_required_not_allow_not_object_user(self): closed=False, ) with self.assertRaises(PermissionDenied): - response = SomeAuthorRequiredView.as_view()( + SomeAuthorRequiredView.as_view()( request, pk=question.pk) - self.assertEqual(response.status_code, 403) diff --git a/qa/tests/test_views.py b/qa/tests/test_views.py index f85b62d..99414ce 100644 --- a/qa/tests/test_views.py +++ b/qa/tests/test_views.py @@ -65,7 +65,8 @@ def test_create_question_view_two(self): self.assertEqual(response.status_code, 302) new_answer = Answer.objects.first() self.assertEqual(new_answer.question, question) - self.assertEqual(Answer.objects.count(), current_answer_count+1) + self.assertEqual( + Answer.objects.count(), current_answer_count + 1) # CreateQuestionCommentView @@ -87,7 +88,7 @@ def test_create_question_comment_view(self): new_comment = QuestionComment.objects.first() self.assertEqual(new_comment.question, question) self.assertEqual(QuestionComment.objects.count(), - current_comment_question_count+1) + current_comment_question_count + 1) def test_user_cannot_upvote_own_questions(self): """ @@ -97,7 +98,7 @@ def test_user_cannot_upvote_own_questions(self): question = Question.objects.create( title='a title', description='bla', user=self.user) with self.assertRaises(ValidationError): - response = self.client.post(reverse( + self.client.post(reverse( 'qa_question_vote', kwargs={'object_id': question.id}), data={'upvote': 'on'}) @@ -158,9 +159,9 @@ def test_upvote_question_deletes_instance(self): value=True) previous_vote_instances = QuestionVote.objects.count() previous_votes = question.total_points - response = self.client.post(reverse('qa_question_vote', - kwargs={'object_id': question.id}), - data={'upvote': 'on'}) + self.client.post(reverse('qa_question_vote', + kwargs={'object_id': question.id}), + data={'upvote': 'on'}) self.assertEqual(previous_vote_instances - 1, QuestionVote.objects.count()) question.refresh_from_db() @@ -182,10 +183,235 @@ def test_switching_vote_updates_correctly(self): previous_vote_instances = QuestionVote.objects.count() previous_votes = question.total_points previous_question_vote = question_vote.value - response = self.client.post(reverse('qa_question_vote', - kwargs={'object_id': question.id})) + self.client.post(reverse('qa_question_vote', + kwargs={'object_id': question.id})) self.assertEqual(previous_vote_instances, QuestionVote.objects.count()) question.refresh_from_db() question_vote.refresh_from_db() self.assertEqual(previous_votes - 2, question.total_points) self.assertNotEqual(previous_question_vote, question_vote.value) + +# AnswerQuestionView + + def test_can_mark_answer_as_satisfying_answer(self): + """ + The owner of the question should be able to mark an answer + as the satisfying one. + """ + + user = get_user_model().objects.create_user(username='user2', + password='top_secret') + question = Question.objects.create( + title='a title', description='bla', user=self.user) + answer = Answer.objects.create( + answer_text='a title', user=user, question=question) + response = self.client.post(reverse('qa_close_question', + kwargs={'answer_id': answer.id})) + answer.refresh_from_db() + question.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertTrue(question.closed) + self.assertTrue(answer.answer) + + def test_can_provide_next_url_when_marking_satisfying_answer(self): + """ + The if an url is provided at the post request, the view should + redirect there. + """ + + user = get_user_model().objects.create_user(username='user2', + password='top_secret') + question = Question.objects.create( + title='a title', description='bla', user=self.user) + answer = Answer.objects.create( + answer_text='a title', user=user, question=question) + response = self.client.post( + reverse('qa_close_question', + kwargs={'answer_id': answer.id}), + data={'next': reverse('qa_create_question')}) + answer.refresh_from_db() + question.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, reverse('qa_create_question')) + + def test_not_owner_cannot__mark_answer_as_satisfying_answer(self): + """ + Any user that is not the owner of the question should not be able + to mark an user as the satisfying one. + """ + + user = get_user_model().objects.create_user(username='user2', + password='top_secret') + question = Question.objects.create( + title='a title', description='bla', user=user) + answer = Answer.objects.create( + answer_text='a title', user=self.user, question=question) + with self.assertRaises(ValidationError): + self.client.post(reverse('qa_close_question', + kwargs={'answer_id': answer.id})) + answer.refresh_from_db() + self.assertFalse(answer.question.closed) + self.assertFalse(answer.answer) + + +# QuestionIndexView + + def test_question_index_returns_all_questions(self): + """ + QuestionIndexView should return all questions, + questions with no answers and the questions with + points + """ + title = 'This is my question' + self.client.post( + reverse('qa_create_question'), + {'title': title, 'description': 'babla', 'tags': 'test tag'}) + response = self.client.get(reverse('qa_index')) + self.assertEqual(response.status_code, 200) + self.assertEqual( + list(response.context['questions']), + list(Question.objects.all())) + self.assertEqual( + list(response.context['noans']), + list(Question.objects.all())) + self.assertEqual( + list(response.context['reward']), []) + + def test_question_search_returns_related_questions(self): + """ + QuestionsSearchView should return questions + containing the search term + """ + self.client.post( + reverse('qa_create_question'), + {'title': "first title", + 'description': 'first description', + 'tags': 'test tag'}) + self.client.post( + reverse('qa_create_question'), + {'title': "second title", + 'description': 'second description', + 'tags': 'test tag'}) + response = self.client.get(reverse('qa_search')) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['questions']), + len(Question.objects.all())) + self.assertEqual( + len(response.context['noans']), + len(Question.objects.all())) + self.assertEqual( + len(response.context['reward']), 0) + response = self.client.get( + reverse('qa_search'), data={'word': 'first'}) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['questions']), + len(Question.objects.filter(title="first title"))) + response = self.client.get( + reverse('qa_search'), data={'word': 'second'}) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['questions']), + len(Question.objects.filter(title="second title"))) + +# QuestionsByTagView + + def test_question_by_tag_returns_related_tag_questions(self): + """ + QuestionsByTagView should return questions related + with searched tag + """ + self.client.post( + reverse('qa_create_question'), + {'title': "first title", + 'description': 'first description', + 'tags': 'tag'}) + self.client.post( + reverse('qa_create_question'), + {'title': "second title", + 'description': 'second description', + 'tags': 'test'}) + response = self.client.get( + reverse('qa_tag', kwargs={'tag': 'tag'})) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['questions']), + len(Question.objects.filter(title="first title"))) + response = self.client.get( + reverse('qa_tag', kwargs={'tag': 'test'})) + self.assertEqual(response.status_code, 200) + self.assertEqual( + len(response.context['questions']), + len(Question.objects.filter(title="second title"))) + +# UpdateQuestionView + + def test_updates_question_modify_question(self): + """ + UpdateQuestionView updates the required question + """ + self.client.post( + reverse('qa_create_question'), + {'title': "first title", + 'description': 'first description', + 'tags': 'tag'}) + question = Question.objects.latest('pub_date') + question_title = question.title + question_description = question.description + response = self.client.post( + reverse('qa_update_question', + kwargs={'question_id': question.id}), + {'title': "second title", + 'description': 'second description', + 'tags': 'test'}) + question.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertNotEqual(question_title, question.title) + self.assertNotEqual(question_description, question.description) + + +# UpdateAnswerView + + def test_updates_answer_modify_answer(self): + """ + UpdateQuestionView updates the required answer + """ + + user = get_user_model().objects.create_user(username='user2', + password='top_secret') + question = Question.objects.create( + title='a title', description='bla', user=user) + answer = Answer.objects.create( + answer_text='a title', user=self.user, question=question) + answer_text = answer.answer_text + response = self.client.post( + reverse('qa_update_answer', + kwargs={'answer_id': answer.id}), + {'answer_text': 'a description'}) + answer.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertNotEqual(answer_text, answer.answer_text) + +# CreateAnswerCommentView + + def test_create_answer_comment_create_comment_to_given_answer(self): + """ + CreateAnswerCommentView creates comment to given answer + """ + + user = get_user_model().objects.create_user(username='user2', + password='top_secret') + question = Question.objects.create( + title='a title', description='bla', user=user) + answer = Answer.objects.create( + answer_text='a title', user=self.user, question=question) + answer_comments = len(answer.answercomment_set.all()) + response = self.client.post( + reverse('qa_create_answer_comment', + kwargs={'answer_id': answer.id}), + {'comment_text': 'a description'}) + answer.refresh_from_db() + self.assertEqual(response.status_code, 302) + self.assertNotEqual( + answer_comments, answer.answercomment_set.all()) diff --git a/qa/views.py b/qa/views.py index 7ddbdcb..b8e9d72 100644 --- a/qa/views.py +++ b/qa/views.py @@ -116,7 +116,7 @@ class QuestionsSearchView(QuestionIndexView): def get_queryset(self): result = super(QuestionsSearchView, self).get_queryset() - query = self.request.GET.get('word') + query = self.request.GET.get('word', '') if query: query_list = query.split() result = result.filter( @@ -128,16 +128,16 @@ def get_queryset(self): return result - def get_context_data(self, *args, **kwargs): - context = super( - QuestionsSearchView, self).get_context_data(*args, **kwargs) - context['totalcount'] = Question.objects.count - context['anscount'] = Answer.objects.count - context['noans'] = Question.objects.order_by('-pub_date').filter( - answer__isnull=True)[:10] - context['reward'] = Question.objects.order_by('-reward').filter( - reward__gte=1)[:10] - return context + def get_context_data(self, *args, **kwargs): + context = super( + QuestionsSearchView, self).get_context_data(*args, **kwargs) + context['totalcount'] = Question.objects.count + context['anscount'] = Answer.objects.count + context['noans'] = Question.objects.order_by('-pub_date').filter( + answer__isnull=True)[:10] + context['reward'] = Question.objects.order_by('-reward').filter( + reward__gte=1)[:10] + return context class QuestionsByTagView(ListView): @@ -448,4 +448,5 @@ class QuestionVoteView(ParentVoteView): def profile(request, user_id): user_ob = get_user_model().objects.get(id=user_id) user = UserQAProfile.objects.get(user=user_ob) - return render(request, 'qa/profile.html', {'user': user}) + context = {'user': user} + return render(request, 'qa/profile.html', context)