from random import randint import json from django.test import TestCase, Client from django.core import serializers from django.contrib.auth.models import User, Permission from rest_framework.test import APIClient from rp.models import Article from rp.factories import ArticleFactory from rp.apps import RpConfig from rp.views.articles import ArticleList class TestArticle(TestCase): def setUp(self): self.article = ArticleFactory(archive=False, quote=False, speak=False) self.newarticle = ArticleFactory(status='NEW', archive=False, quote=False, speak=False) def test_init(self): assert RpConfig.name == "rp" def test_article(self): assert type(self.article) == Article assert str(self.article) == self.article.title def test_recover(self): article = ArticleFactory(status='NEW') article.recover() assert article.status == 'DRAFT' article = ArticleFactory(status='REJECTED') article.recover() assert article.status == 'DRAFT' def test_add_new_url(self): article = Article.add_new_url(url='https://www.example.org/article') assert article.status == 'NEW' assert article.score == 1 article2 = Article.add_new_url(url='https://www.example.org/article', tags=["Tag 1", "Tag 2"]) assert article2.status == 'NEW' assert article2.score == 2 assert set(article2.tags.names()) == {"Tag 1", "Tag 2"} article3 = Article.add_new_url(url='https://www.example.org/article', tags=["Merged Tag"]) def test_flags(self): assert not self.article.archive assert not self.article.quote assert not self.article.speak def test_toggle_flags(self): self.newarticle.toggle_archive() assert self.newarticle.archive self.newarticle.toggle_archive() assert not self.newarticle.archive self.newarticle.toggle_quote() assert self.newarticle.quote self.newarticle.toggle_quote() assert not self.newarticle.quote self.newarticle.toggle_speak() assert self.newarticle.speak self.newarticle.toggle_speak() assert not self.newarticle.speak def test_set_flags(self): # Method signature is set_flags(boolean: archive = False, # boolean: speak = False, # boolean: quote = False) # All falsg set to their default values self.newarticle.set_flags() assert not self.newarticle.archive assert not self.newarticle.speak assert not self.newarticle.quote self.newarticle.set_flags(speak=True) assert not self.newarticle.archive assert self.newarticle.speak assert not self.newarticle.quote self.newarticle.set_flags(quote=True) assert not self.newarticle.archive assert not self.newarticle.speak assert self.newarticle.quote self.newarticle.set_flags(quote=True, speak=True) assert not self.newarticle.archive assert self.newarticle.speak assert self.newarticle.quote def test_update(self): old_title = self.article.title self.article.title = old_title[::-1] self.article.save() self.article.refresh_from_db() assert self.article.title != old_title def test_unpublish(self): a = ArticleFactory(status='PUBLISHED') a.unpublish() assert a.status == 'DRAFT' class TestArticleViews(TestCase): def setUp(self): self.client = Client() self.articles = [ArticleFactory() for i in range(0, 2 * ArticleList.paginate_by)] self.user = User.objects.create(username="test", email="test@example.org", password="test") for a in self.articles: a.save() def test_list_fr(self): # ArticleFactory use english by default, so we should have # no objects r = self.client.get('/rp/') assert len(r.context['object_list']) == 0 def test_list_en(self): r = self.client.get('/rp/international') if r.context['is_paginated']: assert len(r.context['object_list']) == ArticleList.paginate_by else: assert len(r.context['object_list']) == 0 def test_filter_tag(self): tag = 'Tag 1' r = self.client.get('/rp/by-tag/{}'.format(tag)) if r.context['is_paginated']: assert len(r.context['object_list']) == ArticleList.paginate_by else: assert len(r.context['object_list']) == 0 r = self.client.get('/rp/by-tag/zogzog') assert len(r.context['object_list']) == 0 def test_search_view(self): article = ArticleFactory(title=u'Zog Zog chez les schtroumphs', lang='FR', archive=False, status='PUBLISHED') article.save() r = self.client.get('/rp/', {'q': 'Zog Zog'}) assert len(r.context['article_list']) == 1 r = self.client.get('/rp/', {'q': 'Gargamel was here'}) assert len(r.context['article_list']) == 0 def test_search_view_archived(self): archive = ArticleFactory(archive=True, lang='FR', status='PUBLISHED') r = self.client.get('/rp/', {'q': '', 'archive': 'true'}) assert len(r.context['article_list']) == 1 assert r.context['article_list'][0] == archive r = self.client.get('/rp/', {'archive': 'false'}) assert len(r.context['article_list']) == 0 def test_search_view_speaks(self): speak = ArticleFactory(speak=True, archive=False, lang='FR', status='PUBLISHED') r = self.client.get('/rp/', {'q': '', 'speak': 'true'}) assert len(r.context['article_list']) == 1 assert r.context['article_list'][0] == speak r = self.client.get('/rp/', {'speak': 'false'}) assert len(r.context['article_list']) == 0 def test_search_view_quoted(self): quote = ArticleFactory(quote=True, archive=False, lang='FR', status='PUBLISHED') r = self.client.get('/rp/', {'q': '', 'quote': 'true'}) assert len(r.context['article_list']) == 1 assert r.context['article_list'][0] == quote r = self.client.get('/rp/', {'quote': 'false'}) assert len(r.context['article_list']) == 0 def test_detail_view(self): # Let's find a published article self.client.force_login(user=self.user) a = self.articles[0] r = self.client.get('/rp/article/view/{}'.format(a.pk)) assert r.context['object'] == a def test_article_edit_unauth(self): a = self.articles[0] r = self.client.post('/rp/article/edit/{}'.format(a.pk)) assert r.status_code == 403 def test_article_edit(self): self.user.user_permissions.add(Permission.objects.get( codename='can_edit')) self.client.force_login(user=self.user) pk = self.articles[0].pk a = {'title': 'Zog Zog', 'status': 'NEW', 'lang': 'FR', 'url': 'https://www.example.org/', 'tags': ["Merged Tag"]} r = self.client.post('/rp/article/edit/{}/'.format(pk), a) a = Article.objects.get(pk=pk) assert r.status_code == 302 # We're redirecting to the view or preview of the article assert a.title == 'Zog Zog' assert set(a.tags.names()) == set(self.articles[0].tags.names()) | {"merged tag"} class TestArticleApi(TestCase): def setUp(self): self.client = APIClient() self.articles = [ArticleFactory(tags=["Tag {}".format(n) for n in range(randint(1, 10))]) for i in range(0, 2 * ArticleList.paginate_by)] self.user = User.objects.create(username="test", email="test@example.org", password="test") self.jedi = User.objects.create(username="obiwan", email="o.kennoby@example.org", password="Thisaintthedroidyourelookin") for a in self.articles: a.save() def test_api_get(self): r = self.client.get('/api/articles/1/', {}) assert r.status_code == 200 assert r.data['id'] == 1 def test_api_list(self): r = self.client.get('/api/articles/', {}) assert r.status_code == 200 assert r.data['count'] == 2 * ArticleList.paginate_by def test_api_edit(self): self.user.user_permissions.add(Permission.objects.get( codename='can_edit')) self.client.force_login(user=self.user) pk = self.articles[0].pk article = {'title': 'Zog Zog', 'url': 'https://article.org/Zog+Zog'} r = self.client.put('/api/articles/{}/'.format(pk), article, format='json') assert r.status_code == 200 assert Article.objects.get(pk=pk).title == 'Zog Zog' def test_api_edit_tags(self): # Checking that we indeed change the tags self.user.user_permissions.add(Permission.objects.get( codename='can_edit')) self.client.force_login(user=self.user) pk = self.articles[0].pk article = {'title': 'Zog Zog', 'url': 'https://article.org/Zog+Zog', 'tags': '["New Tag 1", "New Tag 2"]'} r = self.client.put('/api/articles/{}/'.format(pk), article, format='json') assert r.status_code == 200 a = Article.objects.get(pk=pk) assert list(a.tags.values('name',).order_by('name')) == [{'name': 'New Tag 1'}, {'name': 'New Tag 2'}] def test_api_filter_tag(self): tag = 'Tag 1' tagged = Article.objects.filter(tags__name__in=[tag]).count() r = self.client.get('/api/articles-by-tag/{}/'.format(tag)) assert r.status_code == 200 assert r.data['count'] == tagged # Case sensitivity checking - tags are sensitive to case r = self.client.get('/api/articles-by-tag/{}/'.format(tag.upper())) assert r.status_code == 200 assert r.data['count'] == 0 # No article should have the ZogZog tag r = self.client.get('/api/articles-by-tag/zogzog/') assert r.status_code == 200 assert r.data['count'] == 0 def test_api_filter_search(self): text = self.articles[0].title r = self.client.get('/api/articles/', {'q': text}) assert r.status_code == 200 assert r.data['count'] == 1 assert r.data['results'][0]['id'] == self.articles[0].id def test_api_filter_flag_search(self): r = self.client.get('/api/articles/', {'quote': 'both'}) assert r.status_code == 200 assert r.data['count'] == len(self.articles) def test_api_tag_push_unauth(self): a = ArticleFactory() r = self.client.post('/api/articles/', {'url': a.url, 'title': a.title, 'tags': '["Tag 1", "Tag 2"]'}, format='json') assert r.status_code == 401 def test_api_tag_push_auth(self): self.client.force_login(user=self.user) a = ArticleFactory(status='NEW') r = self.client.post('/api/articles/', {'url': a.url, 'title': a.title, 'tags': a.tags.all()}, format='json') assert r.status_code == 201 assert list(a.tags.all()) == r.data['tags'] # Need to test if we keep the tags r = self.client.post('/api/articles/', {'url': a.url, 'title': a.title}, format='json') assert list(a.tags.all()) == r.data['tags'] def test_api_recover(self): # Can we recover if we're no Jedis self.client.force_login(user=self.user) a = ArticleFactory(status='NEW') r = self.client.post('/api/articles/{}/recover/'.format(a.id)) assert r.status_code == 403 # Can we recover a NEW article and force it to DRAFT? self.user.user_permissions.add(Permission.objects.get( codename='can_change_status')) self.client.force_login(user=self.user) a = ArticleFactory(status='NEW') r = self.client.post('/api/articles/{}/recover/'.format(a.id)) assert r.status_code == 200 assert r.data['status'] == 'DRAFT' # Can we recovr a REJECTED article and force it to DRAFT? a = ArticleFactory(status='REJECTED') r = self.client.post('/api/articles/{}/recover/'.format(a.id)) assert r.status_code == 200 assert r.data['status'] == 'DRAFT' # We cannot recover a published article a = ArticleFactory(status='PUBLISHED') r = self.client.post('/api/articles/{}/recover/'.format(a.id)) assert r.status_code == 400 def test_api_set_priority(self): self.user.user_permissions.add(Permission.objects.get( codename='can_change_priority')) self.client.force_login(user=self.user) a = ArticleFactory(status='DRAFT') assert a.priority is False r = self.client.post('/api/articles/{}/set-priority/'.format(a.id)) assert r.status_code == 200 assert r.data['priority'] def test_api_unset_priority(self): self.user.user_permissions.add(Permission.objects.get( codename='can_change_priority')) self.client.force_login(user=self.user) a = ArticleFactory(status='DRAFT', priority=True) assert a.priority r = self.client.post('/api/articles/{}/unset-priority/'.format(a.id)) assert r.status_code == 200 assert r.data['priority'] is False def test_api_unpublish_unauth(self): a = ArticleFactory(status='PUBLISHED') r = self.client.post('/api/articles/{}/unpublish/'.format(a.id)) assert r.status_code == 401 def test_api_unpublish(self): self.jedi.user_permissions.add(Permission.objects.get( codename='can_change_status')) self.client.force_login(self.jedi) a = ArticleFactory(status='PUBLISHED') r = self.client.post('/api/articles/{}/unpublish/'.format(a.id)) assert r.status_code == 200 assert r.data['status'] == 'DRAFT'