This commit is contained in:
lwark
2025-09-17 07:52:16 -05:00
commit a2ff72dda8
584 changed files with 52247 additions and 0 deletions

0
tests/core/__init__.py Normal file
View File

153
tests/core/test_accounts.py Normal file
View File

@@ -0,0 +1,153 @@
from django.conf import settings as django_settings
from django.contrib import auth
from django.contrib.auth import authenticate
from django.contrib.auth.models import AnonymousUser
from django.shortcuts import resolve_url
from wiki.conf import settings as wiki_settings
from wiki.models import reverse
from ..base import ArticleWebTestUtils
from ..base import DjangoClientTestBase
from ..base import RequireRootArticleMixin
from ..base import SUPERUSER1_PASSWORD
from ..base import SUPERUSER1_USERNAME
from ..base import TestBase
from ..base import wiki_override_settings
from ..testdata.models import CustomUser
SIGNUP_TEST_USERNAME = "wiki"
SIGNUP_TEST_PASSWORD = "wiki1234567"
class AccountUpdateTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_password_change(self):
"""
Test that we can make a successful password change via the update form
"""
# Check out that it works as expected, notice that there is no referrer
# on this GET request.
self.client.get(
resolve_url(
"wiki:profile_update",
)
)
# Now check that we don't succeed with unmatching passwords
example_data = {
"password1": "abcdef",
"password2": "abcdef123",
"email": self.superuser1.email,
}
# save a new revision
response = self.client.post(
resolve_url("wiki:profile_update"), example_data
)
self.assertContains(
response, "Passwords don", status_code=200
) # Django 2/3 output different escaped versions of single quote in don't
# Now check that we don't succeed with unmatching passwords
example_data = {
"password1": "abcdef",
"password2": "abcdef",
"email": self.superuser1.email,
}
# save a new revision
response = self.client.post(
resolve_url("wiki:profile_update"), example_data
)
# Need to force str() because of:
# TypeError: coercing to Unicode: need string or buffer, __proxy__
# found
self.assertRedirects(response, str(django_settings.LOGIN_REDIRECT_URL))
self.assertEqual(
self.superuser1,
authenticate(
username=self.superuser1.username,
password=example_data["password1"],
),
)
class UpdateProfileViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_update_profile(self):
self.client.post(
resolve_url("wiki:profile_update"),
{
"email": "test@test.com",
"password1": "newPass",
"password2": "newPass",
},
follow=True,
)
test_auth = authenticate(username="admin", password="newPass")
self.assertIsNotNone(test_auth)
self.assertEqual(test_auth.email, "test@test.com")
@wiki_override_settings(ACCOUNT_HANDLING=True)
class LogoutViewTests(RequireRootArticleMixin, DjangoClientTestBase):
def test_logout_account_handling(self):
self.client.get(wiki_settings.LOGOUT_URL)
user = auth.get_user(self.client)
self.assertIs(auth.get_user(self.client).is_authenticated, False)
self.assertIsInstance(user, AnonymousUser)
@wiki_override_settings(ACCOUNT_HANDLING=True)
class LoginTestViews(RequireRootArticleMixin, TestBase):
def test_already_signed_in(self):
self.client.force_login(self.superuser1)
response = self.client.get(wiki_settings.LOGIN_URL)
self.assertRedirects(response, reverse("wiki:root"))
def test_log_in(self):
self.client.post(
wiki_settings.LOGIN_URL,
{"username": SUPERUSER1_USERNAME, "password": SUPERUSER1_PASSWORD},
)
self.assertIs(self.superuser1.is_authenticated, True)
self.assertEqual(auth.get_user(self.client), self.superuser1)
class SignupViewTests(RequireRootArticleMixin, TestBase):
@wiki_override_settings(ACCOUNT_HANDLING=True, ACCOUNT_SIGNUP_ALLOWED=True)
def test_signup(self):
response = self.client.post(
wiki_settings.SIGNUP_URL,
data={
"password1": SIGNUP_TEST_PASSWORD,
"password2": SIGNUP_TEST_PASSWORD,
"username": SIGNUP_TEST_USERNAME,
"email": "wiki@wiki.com",
},
)
self.assertIs(
CustomUser.objects.filter(email="wiki@wiki.com").exists(), True
)
self.assertRedirects(response, reverse("wiki:login"))
# Test that signing up the same user again gives a validation error
# Regression test: https://github.com/django-wiki/django-wiki/issues/1152
response = self.client.post(
wiki_settings.SIGNUP_URL,
data={
"password1": SIGNUP_TEST_PASSWORD,
"password2": SIGNUP_TEST_PASSWORD,
"username": SIGNUP_TEST_USERNAME,
"email": "wiki@wiki.com",
},
)
self.assertIs(response.status_code, 200)
self.assertContains(response, "username already exists")

64
tests/core/test_basic.py Normal file
View File

@@ -0,0 +1,64 @@
import tempfile
from datetime import datetime
from django.test import TestCase
from wiki.conf import settings as wiki_settings
from wiki.core.http import send_file
from wiki.forms import Group
from wiki.models import Article
from wiki.models import ArticleRevision
from wiki.models import URLPath
from ..base import wiki_override_settings
from ..testdata.models import CustomGroup
class URLPathTests(TestCase):
def test_manager(self):
root = URLPath.create_root()
child = URLPath.create_urlpath(root, "child")
self.assertIsNone(root.parent)
self.assertEqual(list(root.children.all().active()), [child])
class CustomGroupTests(TestCase):
@wiki_override_settings(WIKI_GROUP_MODEL="auth.Group")
def test_setting(self):
self.assertEqual(wiki_settings.GROUP_MODEL, "auth.Group")
def test_custom(self):
self.assertEqual(Group, CustomGroup)
self.assertEqual(wiki_settings.GROUP_MODEL, "testdata.CustomGroup")
class LineEndingsTests(TestCase):
def test_manager(self):
article = Article()
article.add_revision(
ArticleRevision(title="Root", content="Hello\nworld"), save=True
)
self.assertEqual("Hello\r\nworld", article.current_revision.content)
class HttpTests(TestCase):
def test_send_file(self):
fabricate_request = self.client.get("/").wsgi_request
fobject = tempfile.NamedTemporaryFile("r")
response = send_file(
fabricate_request, fobject.name, filename="test.pdf"
)
assert response.has_header("Content-Disposition")
assert "inline" in response.get("Content-Disposition")
response = send_file(
fabricate_request, fobject.name, filename="test.jpeg"
)
assert response.has_header("Content-Disposition")
response = send_file(
fabricate_request,
fobject.name,
filename="test.jpeg",
last_modified=datetime.now(),
)
assert response.has_header("Content-Disposition")
fobject.close()

115
tests/core/test_checks.py Normal file
View File

@@ -0,0 +1,115 @@
import copy
from django.conf import settings
from django.core.checks import Error
from django.core.checks import registry
from django.test import TestCase
from wiki.checks import FIELDS_IN_CUSTOM_USER_MODEL
from wiki.checks import REQUIRED_CONTEXT_PROCESSORS
from wiki.checks import REQUIRED_INSTALLED_APPS
from wiki.checks import Tags
from ..base import wiki_override_settings
def _remove(settings, arg):
return [setting for setting in settings if not setting.startswith(arg)]
class CheckTests(TestCase):
def test_required_installed_apps(self):
for app in REQUIRED_INSTALLED_APPS:
with self.settings(
INSTALLED_APPS=_remove(settings.INSTALLED_APPS, app[0])
):
errors = registry.run_checks(
tags=[Tags.required_installed_apps]
)
expected_errors = [
Error(
"needs %s in INSTALLED_APPS" % app[1],
id="wiki.%s" % app[2],
)
]
self.assertEqual(errors, expected_errors)
def test_required_context_processors(self):
for context_processor in REQUIRED_CONTEXT_PROCESSORS:
TEMPLATES = copy.deepcopy(settings.TEMPLATES)
TEMPLATES[0]["OPTIONS"]["context_processors"] = [
cp
for cp in TEMPLATES[0]["OPTIONS"]["context_processors"]
if cp != context_processor[0]
]
with self.settings(TEMPLATES=TEMPLATES):
errors = registry.run_checks(tags=[Tags.context_processors])
expected_errors = [
Error(
"needs %s in TEMPLATES[*]['OPTIONS']['context_processors']"
% context_processor[0],
id="wiki.%s" % context_processor[1],
)
]
self.assertEqual(errors, expected_errors)
def test_custom_user_model_mitigation_required(self):
"""
Django check django.forms.ModelForm.Meta on definition, and raises an error if Meta.fields don't exist in Meta.model.
This causes problems in wiki.forms.UserCreationForm and wiki.forms.UserUpdateForm when a custom user model doesn't have fields django-wiki assumes.
There is some code in wiki.forms that detects this situation.
This check asserts that Django are still raising an exception on definition, and asserts the mitigation code in wiki.forms,
and that test_check_for_fields_in_custom_user_model below are required.
"""
from django.core.exceptions import FieldError
from django import forms
from ..testdata.models import VeryCustomUser
with self.assertRaisesRegex(
FieldError,
"Unknown field\\(s\\) \\((email|username|, )+\\) specified for VeryCustomUser",
):
class UserUpdateForm(forms.ModelForm):
class Meta:
model = VeryCustomUser
fields = ["username", "email"]
def test_check_for_fields_in_custom_user_model(self):
from django.contrib.auth import get_user_model
with wiki_override_settings(
WIKI_ACCOUNT_HANDLING=False,
AUTH_USER_MODEL="testdata.VeryCustomUser",
):
errors = registry.run_checks(
tags=[Tags.fields_in_custom_user_model]
)
self.assertEqual(errors, [])
with wiki_override_settings(
WIKI_ACCOUNT_HANDLING=True,
AUTH_USER_MODEL="testdata.VeryCustomUser",
):
errors = registry.run_checks(
tags=[Tags.fields_in_custom_user_model]
)
expected_errors = [
Error(
"%s.%s.%s refers to a field that is not of type %s"
% (
get_user_model().__module__,
get_user_model().__name__,
field_fetcher,
required_field_type,
),
hint="If you have your own login/logout views, turn off settings.WIKI_ACCOUNT_HANDLING",
obj=get_user_model(),
id="wiki.%s" % error_code,
)
for check_function_name, field_fetcher, required_field_type, error_code in FIELDS_IN_CUSTOM_USER_MODEL
]
self.assertEqual(errors, expected_errors)
with wiki_override_settings(WIKI_ACCOUNT_HANDLING=True):
errors = registry.run_checks(
tags=[Tags.fields_in_custom_user_model]
)
self.assertEqual(errors, [])

View File

@@ -0,0 +1,29 @@
import os
import sys
import tempfile
from django.core.management import call_command
from ..base import ArticleTestBase
class TestManagementCommands(ArticleTestBase):
"""
This clever test case can be inherited in other plugins
Some data is created with ArticleTestBase, use that.
"""
def test_dumpdata_loaddata(self):
sysout = sys.stdout
fixtures_file = tempfile.NamedTemporaryFile(
"w", delete=False, suffix=".json"
)
sys.stdout = fixtures_file
call_command("dumpdata", "wiki")
fixtures_file.file.flush()
fixtures_file.file.close()
sys.stdout = open(os.devnull, "w")
call_command("loaddata", fixtures_file.name)
sys.stdout = sysout
os.unlink(fixtures_file.name)

81
tests/core/test_editor.py Normal file
View File

@@ -0,0 +1,81 @@
import wiki.editors
from django.forms import Textarea
from wiki.editors.base import BaseEditor
from ..base import RequireRootArticleMixin
from ..base import WebTestBase
from ..base import wiki_override_settings
class CustomEditor(BaseEditor):
def get_widget(self, revision=None):
return Textarea(attrs={"data-revision": revision.pk})
def get_admin_widget(self, revision=None):
return Textarea(attrs={"data-revision": revision.pk})
class EditorTest(RequireRootArticleMixin, WebTestBase):
def setUp(self):
super().setUp()
# reset the cached editor class and instance
wiki.editors._editor, wiki.editors._EditorClass = None, None
def test_editor_widget_markitup(self):
response = self.get_url("wiki:edit", path="")
self.assertContains(
response,
'<textarea name="content" class="markItUp" rows="10" cols="40" id="id_content">',
)
def test_admin_widget_markitup(self):
response = self.get_url(
"admin:wiki_articlerevision_change",
object_id=self.root_article.current_revision.id,
)
self.assertContains(
response,
'<textarea name="content" class="markItUp" rows="10" cols="40" id="id_content">',
)
@wiki_override_settings(WIKI_EDITOR="wiki.editors.base.BaseEditor")
def test_editor_widget_base(self):
response = self.get_url("wiki:edit", path="")
self.assertContains(
response,
'<textarea name="content" cols="40" rows="10" id="id_content">',
)
@wiki_override_settings(WIKI_EDITOR="wiki.editors.base.BaseEditor")
def test_admin_widget_base(self):
response = self.get_url(
"admin:wiki_articlerevision_change",
object_id=self.root_article.current_revision.id,
)
self.assertContains(
response,
'<textarea name="content" cols="40" rows="10" id="id_content">',
)
@wiki_override_settings(WIKI_EDITOR="tests.core.test_editor.CustomEditor")
def test_editor_widget_custom(self):
response = self.get_url("wiki:edit", path="")
self.assertContains(
response,
'<textarea name="content" cols="40" rows="10" data-revision="{}" id="id_content">'.format(
self.root_article.current_revision.id
),
)
@wiki_override_settings(WIKI_EDITOR="tests.core.test_editor.CustomEditor")
def test_admin_widget_custom(self):
response = self.get_url(
"admin:wiki_articlerevision_change",
object_id=self.root_article.current_revision.id,
)
self.assertContains(
response,
'<textarea name="content" cols="40" rows="10" data-revision="{}" id="id_content">'.format(
self.root_article.current_revision.id
),
)

39
tests/core/test_forms.py Normal file
View File

@@ -0,0 +1,39 @@
from django.test import TestCase
from django.utils.translation import gettext
from wiki.forms import DeleteForm
from wiki.forms import UserCreationForm
from tests.base import DjangoClientTestBase
from tests.base import RequireRootArticleMixin
class DeleteFormTests(RequireRootArticleMixin, DjangoClientTestBase):
def test_not_sure(self):
data = {"purge": True, "confirm": False}
form = DeleteForm(
article=self.root_article, has_children=True, data=data
)
self.assertIs(form.is_valid(), False)
self.assertEqual(
form.errors["__all__"], [gettext("You are not sure enough!")]
)
class UserCreationFormTests(TestCase):
def test_honeypot(self):
data = {
"address": "Wiki Road 123",
"phone": "12345678",
"email": "wiki@wiki.com",
"username": "WikiMan",
"password1": "R@ndomString",
"password2": "R@ndomString",
}
form = UserCreationForm(data=data)
self.assertIs(form.is_valid(), False)
self.assertEqual(
form.errors["__all__"],
[
"Thank you, non-human visitor. Please keep trying to fill in the form."
],
)

View File

@@ -0,0 +1,81 @@
"""
Tests that the custom queryset methods work, this is important
because the pattern of building them is different from Django
1.5 to 1.6 to 1.7 so there will be 3 patterns in play at the
same time.
"""
from wiki.models import Article
from wiki.models import URLPath
from wiki.plugins.attachments.models import Attachment
from ..base import ArticleTestBase
class ArticleManagerTests(ArticleTestBase):
def test_queryset_methods_directly_on_manager(self):
self.assertEqual(Article.objects.can_read(self.superuser1).count(), 1)
self.assertEqual(Article.objects.can_write(self.superuser1).count(), 1)
self.assertEqual(Article.objects.active().count(), 1)
def test_mass_deletion(self):
"""
https://github.com/django-wiki/django-wiki/issues/857
"""
Article.objects.all().delete()
self.assertEqual(Article.objects.all().count(), 0)
def test_queryset_methods_on_querysets(self):
self.assertEqual(
Article.objects.all().can_read(self.superuser1).count(), 1
)
self.assertEqual(
Article.objects.all().can_write(self.superuser1).count(), 1
)
self.assertEqual(Article.objects.all().active().count(), 1)
# See: https://code.djangoproject.com/ticket/22817
def test_queryset_empty_querysets(self):
self.assertEqual(
Article.objects.none().can_read(self.superuser1).count(), 0
)
self.assertEqual(
Article.objects.none().can_write(self.superuser1).count(), 0
)
self.assertEqual(Article.objects.none().active().count(), 0)
class AttachmentManagerTests(ArticleTestBase):
def test_queryset_methods_directly_on_manager(self):
# Do the same for Attachment which uses ArtickeFkManager
self.assertEqual(
Attachment.objects.can_read(self.superuser1).count(), 0
)
self.assertEqual(
Attachment.objects.can_write(self.superuser1).count(), 0
)
self.assertEqual(Attachment.objects.active().count(), 0)
def test_queryset_methods_on_querysets(self):
self.assertEqual(
Attachment.objects.all().can_read(self.superuser1).count(), 0
)
self.assertEqual(
Attachment.objects.all().can_write(self.superuser1).count(), 0
)
self.assertEqual(Attachment.objects.all().active().count(), 0)
# See: https://code.djangoproject.com/ticket/22817
def test_queryset_empty_query_sets(self):
self.assertEqual(
Attachment.objects.none().can_read(self.superuser1).count(), 0
)
self.assertEqual(
Attachment.objects.none().can_write(self.superuser1).count(), 0
)
self.assertEqual(Attachment.objects.none().active().count(), 0)
class URLPathManagerTests(ArticleTestBase):
def test_related_manager_works_with_filters(self):
root = URLPath.root()
self.assertNotIn(root.id, [p.id for p in root.children.active()])

127
tests/core/test_markdown.py Normal file
View File

@@ -0,0 +1,127 @@
from unittest.mock import patch
import markdown
from django.test import TestCase
from wiki.core.markdown import ArticleMarkdown
from wiki.core.markdown.mdx.codehilite import WikiCodeHiliteExtension
from wiki.core.markdown.mdx.responsivetable import ResponsiveTableExtension
from wiki.models import URLPath
from ..base import ArticleTestBase
try:
import pygments
pygments = True # NOQA
except ImportError:
pygments = False
class ArticleMarkdownTests(ArticleTestBase):
@patch("wiki.core.markdown.settings")
def test_do_not_modify_extensions(self, settings):
extensions = ["footnotes", "attr_list", "sane_lists"]
settings.MARKDOWN_KWARGS = {"extensions": extensions}
number_of_extensions = len(extensions)
ArticleMarkdown(None)
self.assertEqual(len(extensions), number_of_extensions)
def test_html_removal(self):
urlpath = URLPath.create_urlpath(
self.root,
"html_removal",
title="Test 1",
content="</html>only_this",
)
self.assertEqual(urlpath.article.render(), "<p>only_this</p>")
class ResponsiveTableExtensionTests(TestCase):
def setUp(self):
super().setUp()
self.md = markdown.Markdown(
extensions=["extra", ResponsiveTableExtension()]
)
self.md_without = markdown.Markdown(extensions=["extra"])
def test_wrapping(self):
text = "|th|th|\n|--|--|\n|td|td|"
expected = (
'<div class="table-responsive">\n'
+ self.md_without.convert(text)
+ "\n</div>"
)
self.assertEqual(self.md.convert(text), expected)
class CodehiliteTests(TestCase):
def test_fenced_code(self):
md = markdown.Markdown(extensions=["extra", WikiCodeHiliteExtension()])
text = (
"Code:\n"
"\n"
"```python\n"
"echo 'line 1'\n"
"echo 'line 2'\n"
"```\n"
)
result = (
(
"""<p>Code:</p>\n"""
"""<div class="codehilite-wrap"><div class="codehilite"><pre><span></span><span class="n">echo</span> <span class="s1">&#39;line 1&#39;</span>\n"""
"""<span class="n">echo</span> <span class="s1">&#39;line 2&#39;</span>\n"""
"""</pre></div>\n"""
"""</div>"""
)
if pygments
else (
"""<p>Code:</p>\n"""
"""<div class="codehilite-wrap"><pre class="codehilite"><code class="language-python">echo 'line 1'\n"""
"""echo 'line 2'\n</code></pre>\n"""
"""</div>"""
)
)
self.assertEqual(
md.convert(text),
result,
)
def test_indented_code(self):
md = markdown.Markdown(extensions=["extra", WikiCodeHiliteExtension()])
text = (
"Code:\n"
"\n"
" #!/usr/bin/python\n"
" print('line 1')\n"
" print('line 2')\n"
" print('æøå')\n"
"\n"
)
result = (
(
"""<p>Code:</p>\n"""
"""<div class="codehilite-wrap"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1\n"""
"""2\n"""
"""3\n"""
"""4</pre></div></td><td class="code"><div class="codehilite"><pre><span></span><span class="ch">#!/usr/bin/python</span>\n"""
"""<span class="k">print</span><span class="p">(</span><span class="s1">&#39;line 1&#39;</span><span class="p">)</span>\n"""
"""<span class="k">print</span><span class="p">(</span><span class="s1">&#39;line 2&#39;</span><span class="p">)</span>\n"""
"""<span class="k">print</span><span class="p">(</span><span class="s1">&#39;æøå&#39;</span><span class="p">)</span>\n"""
"""</pre></div>\n"""
"""</td></tr></table></div>"""
)
if pygments
else (
"""<p>Code:</p>\n"""
"""<div class="codehilite-wrap"><pre class="codehilite"><code class="language-python linenums">#!/usr/bin/python\n"""
"""print('line 1')\n"""
"""print('line 2')\n"""
"""print('æøå')\n</code></pre>\n"""
"""</div>"""
)
)
self.assertEqual(
md.convert(text),
result,
)

147
tests/core/test_models.py Normal file
View File

@@ -0,0 +1,147 @@
from django.apps import apps
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.test.testcases import TestCase
from django.urls import re_path
from wiki.conf import settings
from wiki.managers import ArticleManager
from wiki.models import Article
from wiki.models import ArticleRevision
from wiki.models import URLPath
from wiki.urls import WikiURLPatterns
User = get_user_model()
Group = apps.get_model(settings.GROUP_MODEL)
class WikiCustomUrlPatterns(WikiURLPatterns):
def get_article_urls(self):
urlpatterns = [
re_path(
"^my-wiki/(?P<article_id>[0-9]+)/$",
self.article_view_class.as_view(),
name="get",
),
]
return urlpatterns
def get_article_path_urls(self):
urlpatterns = [
re_path(
"^my-wiki/(?P<path>.+/|)$",
self.article_view_class.as_view(),
name="get",
),
]
return urlpatterns
class ArticleModelTest(TestCase):
def test_default_fields_of_empty_article(self):
a = Article.objects.create()
self.assertIsNone(a.current_revision)
self.assertIsNone(a.owner)
self.assertIsNone(a.group)
self.assertIsNotNone(a.created)
self.assertIsNotNone(a.modified)
self.assertIsNotNone(a.group_read)
self.assertIsNotNone(a.group_write)
self.assertIsNotNone(a.other_read)
self.assertIsNotNone(a.other_write)
# XXX maybe redundant test
def test_model_manager_class(self):
self.assertIsInstance(Article.objects, ArticleManager)
def test_str_method_if_have_current_revision(self):
title = "Test title"
a = Article.objects.create()
ArticleRevision.objects.create(article=a, title=title)
self.assertEqual(str(a), title)
def test_str_method_if_dont_have_current_revision(self):
a = Article.objects.create()
expected = "Article without content (1)"
self.assertEqual(str(a), expected)
def test_get_absolute_url_if_urlpath_set_is_exists(self):
a1 = Article.objects.create()
s1 = Site.objects.create(domain="something.com", name="something.com")
u1 = URLPath.objects.create(article=a1, site=s1)
a2 = Article.objects.create()
s2 = Site.objects.create(
domain="somethingelse.com", name="somethingelse.com"
)
URLPath.objects.create(
article=a2, site=s2, parent=u1, slug="test_slug"
)
url = a2.get_absolute_url()
expected = "/test_slug/"
self.assertEqual(url, expected)
def test_get_absolute_url_if_urlpath_set_is_not_exists(self):
a = Article.objects.create()
url = a.get_absolute_url()
expected = "/1/"
self.assertEqual(url, expected)
def test_article_is_related_to_articlerevision(self):
title = "Test title"
a = Article.objects.create()
r = ArticleRevision.objects.create(article=a, title=title)
self.assertEqual(r.article, a)
self.assertIn(r, a.articlerevision_set.all())
def test_article_is_related_to_owner(self):
u = User.objects.create(username="Noman", password="pass")
a = Article.objects.create(owner=u)
self.assertEqual(a.owner, u)
self.assertIn(a, u.owned_articles.all())
def test_article_is_related_to_group(self):
g = Group.objects.create()
a = Article.objects.create(group=g)
self.assertEqual(a.group, g)
self.assertIn(a, g.article_set.all())
def test_cache(self):
a = Article.objects.create()
ArticleRevision.objects.create(
article=a, title="test", content="# header"
)
expected = """<h1 id="wiki-toc-header">header""" """.*</h1>"""
# cached content does not exist yet. this will create it
self.assertRegex(a.get_cached_content(), expected)
# actual cached content test
self.assertRegex(a.get_cached_content(), expected)
def test_articlerevision_presave_signals(self):
a = Article.objects.create()
ar1 = ArticleRevision(article=a, title="revision1")
a.add_revision(ar1)
self.assertEqual(ar1, a.current_revision)
ar2 = ArticleRevision(article=a, title="revision2")
ar2.save()
self.assertEqual(ar2.previous_revision, ar1)

View File

@@ -0,0 +1,39 @@
from django.test import TestCase
from wiki.core.paginator import WikiPaginator
class PaginatorTest(TestCase):
"""
Test the WikiPaginator and it's page_range() function
"""
def test_paginator(self):
objects = [1]
p = WikiPaginator(objects, 2, side_pages=2)
self.assertEqual(p.num_pages, 1)
p.page(1)
self.assertEqual(p.page_range, [1])
objects = [1, 2, 3, 4, 5, 6, 7, 8, 9]
p = WikiPaginator(objects, 2, side_pages=2)
self.assertEqual(p.num_pages, 5)
p.page(1)
self.assertEqual(p.page_range, [1, 2, 3, 0, 5])
p.page(3)
self.assertEqual(p.page_range, [1, 2, 3, 4, 5])
objects = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
p = WikiPaginator(objects, 2, side_pages=2)
self.assertEqual(p.num_pages, 9)
p.page(1)
self.assertEqual(p.page_range, [1, 2, 3, 0, 9])
p.page(5)
self.assertEqual(p.page_range, [1, 0, 3, 4, 5, 6, 7, 0, 9])
p.page(8)
self.assertEqual(p.page_range, [1, 0, 6, 7, 8, 9])

106
tests/core/test_sites.py Normal file
View File

@@ -0,0 +1,106 @@
from importlib import reload
from django.contrib.sites.models import Site
from django.test.testcases import TestCase
from django.urls import include
from django.urls import re_path
from wiki import sites
from wiki import urls
from wiki.apps import WikiConfig
from wiki.models import Article
from wiki.models import URLPath
from ..base import wiki_override_settings
class WikiCustomSite(sites.WikiSite):
def get_article_urls(self):
urlpatterns = [
re_path(
"^some-prefix/(?P<article_id>[0-9]+)/$",
self.article_view,
name="get",
),
]
return urlpatterns
def get_article_path_urls(self):
urlpatterns = [
re_path(
"^some-other-prefix/(?P<path>.+/|)$",
self.article_view,
name="get",
),
]
return urlpatterns
class WikiCustomConfig(WikiConfig):
default_site = "tests.core.test_sites.WikiCustomSite"
urlpatterns = [
re_path(r"^notify/", include("django_nyt.urls")),
re_path(r"", include("wiki.urls")),
]
@wiki_override_settings(
INSTALLED_APPS=[
"tests.testdata",
"django.contrib.auth.apps.AuthConfig",
"django.contrib.contenttypes.apps.ContentTypesConfig",
"django.contrib.sessions.apps.SessionsConfig",
"django.contrib.admin.apps.AdminConfig",
"django.contrib.humanize.apps.HumanizeConfig",
"django.contrib.sites.apps.SitesConfig",
"django_nyt.apps.DjangoNytConfig",
"mptt",
"sekizai",
"sorl.thumbnail",
"tests.core.test_sites.WikiCustomConfig",
"wiki.plugins.attachments.apps.AttachmentsConfig",
"wiki.plugins.notifications.apps.NotificationsConfig",
"wiki.plugins.images.apps.ImagesConfig",
"wiki.plugins.macros.apps.MacrosConfig",
"wiki.plugins.globalhistory.apps.GlobalHistoryConfig",
],
ROOT_URLCONF="tests.core.test_sites",
)
class CustomWikiSiteTest(TestCase):
def setUp(self):
# Reload wiki.urls since it may have already been instantiated by another test app.
self._old_site = sites.site
sites.site = sites.DefaultWikiSite()
reload(urls)
def tearDown(self):
sites.site = self._old_site
reload(urls)
def test_use_custom_wiki_site(self):
self.assertEqual(sites.site.__class__.__name__, "WikiCustomSite")
def test_get_absolute_url_if_urlpath_set_is_not_exists__no_root_urlconf(
self
):
a = Article.objects.create()
self.assertEqual(a.get_absolute_url(), "/some-prefix/1/")
def test_get_absolute_url_if_urlpath_set_is_exists__no_root_urlconf(self):
a1 = Article.objects.create()
s1 = Site.objects.create(domain="something.com", name="something.com")
u1 = URLPath.objects.create(article=a1, site=s1)
a2 = Article.objects.create()
s2 = Site.objects.create(
domain="somethingelse.com", name="somethingelse.com"
)
URLPath.objects.create(
article=a2, site=s2, parent=u1, slug="test_slug"
)
self.assertEqual(
a2.get_absolute_url(), "/some-other-prefix/test_slug/"
)

View File

@@ -0,0 +1,368 @@
from django.contrib.auth import get_user_model
from wiki.models import Article
from wiki.models import ArticleRevision
from wiki.templatetags.wiki_tags import can_delete
from wiki.templatetags.wiki_tags import can_moderate
from wiki.templatetags.wiki_tags import can_read
from wiki.templatetags.wiki_tags import can_write
from wiki.templatetags.wiki_tags import get_content_snippet
from wiki.templatetags.wiki_tags import is_locked
from ..base import TemplateTestCase
from ..base import wiki_override_settings
User = get_user_model()
class GetContentSnippet(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ some_content|get_content_snippet:"keyword, max_words" }}
"""
def test_keyword_at_the_end_of_the_content(self):
text = "lorem " * 80
content = text + " list"
expected = (
"lorem lorem lorem lorem lorem lorem lorem lorem lorem "
"lorem lorem lorem lorem lorem lorem <strong>list</strong>"
)
output = get_content_snippet(content, "list")
self.assertEqual(output, expected)
def test_keyword_at_the_beginning_of_the_content(self):
text = "lorem " * 80
content = "list " + text
expected = (
"<strong>list</strong> lorem lorem lorem lorem lorem "
"lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem "
"lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem "
"lorem lorem lorem"
)
output = get_content_snippet(content, "list")
self.assertEqual(output, expected)
def test_whole_content_consists_of_keywords(self):
content = "lorem " * 80
expected = "<strong>lorem</strong>" + 30 * " <strong>lorem</strong>"
output = get_content_snippet(content, "lorem")
self.assertEqual(output, expected)
def test_keyword_is_not_in_a_content(self):
content = "lorem " * 80
expected = (
"lorem lorem lorem lorem lorem lorem lorem lorem lorem "
"lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem "
"lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem lorem"
)
output = get_content_snippet(content, "list")
self.assertEqual(output, expected)
def test_a_few_keywords_in_content(self):
text = "lorem " * 80
content = "list " + text
text = "ipsum " * 80
content += text + " list "
text = "dolorum " * 80
content += text + " list"
expected = "<strong>list</strong>" + 30 * " lorem"
output = get_content_snippet(content, "list")
self.assertEqual(output, expected)
# XXX bug or feature?
def test_keyword_is_in_content_and_max_words_is_zero(self):
text = "spam " * 800
content = text + " list"
output = get_content_snippet(content, "list", 0)
expected = "spam " * 800 + "<strong>list</strong>"
self.assertEqual(output, expected)
# XXX bug or feature?
def test_keyword_is_in_content_and_max_words_is_negative(self):
text = "spam " * 80
content = text + " list"
output = get_content_snippet(content, "list", -10)
expected = "spam " * 75 + "<strong>list</strong>"
self.assertEqual(output, expected)
# XXX bug or feature?
def test_keyword_is_not_in_content_and_max_words_is_zero(self):
content = "spam " * 15
output = get_content_snippet(content, "list", 0)
expected = ""
self.assertEqual(output, expected)
# XXX bug or feature?
def test_keyword_is_not_in_content_and_max_words_is_negative(self):
content = "spam " * 15
output = get_content_snippet(content, "list", -10)
expected = "spam spam spam spam spam"
self.assertEqual(output, expected)
def test_no_content(self):
content = ""
output = get_content_snippet(content, "list")
self.assertEqual(output, "")
content = " "
output = get_content_snippet(content, "list")
self.assertEqual(output, "")
def test_strip_tags(self):
keyword = "maybe"
content = """
I should citate Shakespeare or Byron.
Or <a>maybe</a> copy paste from <a href="http://python.org">python</a>
or django documentation. Maybe.
"""
expected = (
"I should citate Shakespeare or Byron. "
"Or <strong>maybe</strong> copy paste from python "
"or django documentation. <strong>Maybe.</strong>"
)
output = get_content_snippet(content, keyword, 30)
self.assertEqual(output, expected)
def test_max_words_arg(self):
keyword = "eggs"
content = """
knight eggs spam ham eggs guido python eggs circus
"""
expected = (
"knight <strong>eggs</strong> spam ham "
"<strong>eggs</strong> guido"
)
output = get_content_snippet(content, keyword, 5)
self.assertEqual(output, expected)
output = get_content_snippet(content, keyword, 0)
expected = (
"knight <strong>eggs</strong> spam ham "
"<strong>eggs</strong> guido python <strong>eggs</strong>"
)
self.assertEqual(output, expected)
def test_content_case_preserved(self):
keyword = "DOlOr"
match = "DoLoR"
content = "lorem ipsum %s sit amet" % match
output = get_content_snippet(content, keyword)
self.assertIn(match, output)
self.assertNotIn(keyword, output)
class CanRead(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ article|can_read:user }}
"""
@wiki_override_settings(WIKI_CAN_READ=lambda *args: True)
def test_user_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Nobody", password="pass")
output = can_read(a, u)
self.assertIs(output, True)
output = self.render({"article": a, "user": u})
self.assertIn("True", output)
@wiki_override_settings(WIKI_CAN_READ=lambda *args: False)
def test_user_dont_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Noman", password="pass")
output = can_read(a, u)
self.assertIs(output, False)
output = self.render({"article": a, "user": u})
self.assertIn("False", output)
class CanWrite(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ article|can_write:user }}
"""
@wiki_override_settings(WIKI_CAN_DELETE=lambda *args: True)
def test_user_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Nobody", password="pass")
output = can_write(a, u)
self.assertIs(output, True)
output = self.render({"article": a, "user": u})
self.assertIn("True", output)
@wiki_override_settings(WIKI_CAN_WRITE=lambda *args: False)
def test_user_dont_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Noman", password="pass")
output = can_write(a, u)
self.assertIs(output, False)
output = self.render({"article": a, "user": u})
self.assertIn("False", output)
class CanDelete(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ article|can_delete:user }}
"""
@wiki_override_settings(WIKI_CAN_DELETE=lambda *args: True)
def test_user_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Nobody", password="pass")
output = can_delete(a, u)
self.assertIs(output, True)
output = self.render({"article": a, "user": u})
self.assertIn("True", output)
@wiki_override_settings(WIKI_CAN_WRITE=lambda *args: False)
def test_user_dont_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Noman", password="pass")
output = can_delete(a, u)
self.assertIs(output, False)
output = self.render({"article": a, "user": u})
self.assertIn("False", output)
class CanModerate(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ article|can_moderate:user }}
"""
@wiki_override_settings(WIKI_CAN_MODERATE=lambda *args: True)
def test_user_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Nobody", password="pass")
output = can_moderate(a, u)
self.assertIs(output, True)
output = self.render({"article": a, "user": u})
self.assertIn("True", output)
def test_user_dont_have_permission(self):
a = Article.objects.create()
u = User.objects.create(username="Noman", password="pass")
output = can_moderate(a, u)
self.assertIs(output, False)
output = self.render({"article": a, "user": u})
self.assertIn("False", output)
class IsLocked(TemplateTestCase):
template = """
{% load wiki_tags %}
{{ article|is_locked }}
"""
def test_no_current_revision(self):
a = Article.objects.create()
output = is_locked(a)
self.assertIsNone(output)
output = self.render({"article": a})
self.assertIn("None", output)
def test_have_current_revision_and_not_locked(self):
a = Article.objects.create()
ArticleRevision.objects.create(article=a, locked=False)
b = Article.objects.create()
ArticleRevision.objects.create(article=b)
output = is_locked(a)
self.assertIs(output, False)
output = is_locked(b)
self.assertIs(output, False)
output = self.render({"article": a})
self.assertIn("False", output)
def test_have_current_revision_and_locked(self):
a = Article.objects.create()
ArticleRevision.objects.create(article=a, locked=True)
output = is_locked(a)
self.assertIs(output, True)
output = self.render({"article": a})
self.assertIn("True", output)
class PluginEnabled(TemplateTestCase):
template = """
{% load wiki_tags %}
{% if "wiki.plugins.attachments"|plugin_enabled %}It is enabled{% endif %}
"""
def test_true(self):
output = self.render({})
self.assertIn("It is enabled", output)
class WikiSettings(TemplateTestCase):
template = """
{% load wiki_tags %}
{% if "ACCOUNT_HANDLING"|wiki_settings %}It is enabled{% endif %}
"""
@wiki_override_settings(WIKI_ACCOUNT_HANDLING=lambda *args: True)
def test_setting(self):
output = self.render({})
self.assertIn("It is enabled", output)

View File

@@ -0,0 +1,353 @@
"""
Almost all test cases covers both tag calling and template using.
"""
from django.conf import settings as django_settings
from django.contrib.contenttypes.models import ContentType
from django.http import HttpRequest
from wiki.conf import settings
from wiki.forms import CreateRootForm
from wiki.models import Article
from wiki.models import ArticleForObject
from wiki.models import ArticleRevision
from wiki.templatetags.wiki_tags import article_for_object
from wiki.templatetags.wiki_tags import login_url
from wiki.templatetags.wiki_tags import wiki_form
from wiki.templatetags.wiki_tags import wiki_render
from ..base import TemplateTestCase
if not django_settings.configured:
django_settings.configure()
# XXX article_for_object accepts context, but not using it
class ArticleForObjectTemplatetagTest(TemplateTestCase):
template = """
{% load wiki_tags %}
{% article_for_object obj as anything %}
{{ anything }}
"""
def setUp(self):
super().setUp()
from wiki.templatetags import wiki_tags
wiki_tags._cache = {}
def test_obj_arg_is_not_a_django_model(self):
from wiki.templatetags import wiki_tags
with self.assertRaises(TypeError):
article_for_object({}, "")
with self.assertRaises(TypeError):
article_for_object({"request": 100500}, {})
with self.assertRaises(TypeError):
self.render({"obj": "tiger!"})
self.assertEqual(len(wiki_tags._cache), 0)
def test_obj_is_not_in__cache_and_articleforobject_is_not_exist(self):
from wiki.templatetags.wiki_tags import _cache as cache
obj = Article.objects.create()
article_for_object({}, obj)
self.assertIn(obj, cache)
self.assertIsNone(cache[obj])
self.assertEqual(len(cache), 1)
self.render({"obj": obj})
self.assertIn(obj, cache)
self.assertIsNone(cache[obj])
self.assertEqual(len(cache), 1)
def test_obj_is_not_in__cache_and_articleforobjec_is_exist(self):
from wiki.templatetags.wiki_tags import _cache as cache
a = Article.objects.create()
content_type = ContentType.objects.get_for_model(a)
ArticleForObject.objects.create(
article=a, content_type=content_type, object_id=1
)
output = article_for_object({}, a)
self.assertEqual(output, a)
self.assertIn(a, cache)
self.assertEqual(cache[a], a)
self.assertEqual(len(cache), 1)
self.render({"obj": a})
self.assertIn(a, cache)
self.assertEqual(cache[a], a)
self.assertEqual(len(cache), 1)
def test_obj_in__cache_and_articleforobject_is_not_exist(self):
model = Article.objects.create()
from wiki.templatetags import wiki_tags
wiki_tags._cache = {model: "spam"}
article_for_object({}, model)
self.assertIn(model, wiki_tags._cache)
self.assertIsNone(wiki_tags._cache[model])
self.assertEqual(len(wiki_tags._cache), 1)
self.render({"obj": model})
self.assertIn(model, wiki_tags._cache)
self.assertIsNone(wiki_tags._cache[model])
self.assertEqual(len(wiki_tags._cache), 1)
self.assertNotIn("spam", wiki_tags._cache.values())
def test_obj_in__cache_and_articleforobjec_is_exist(self):
article = Article.objects.create()
content_type = ContentType.objects.get_for_model(article)
ArticleForObject.objects.create(
article=article, content_type=content_type, object_id=1
)
from wiki.templatetags import wiki_tags
wiki_tags._cache = {article: "spam"}
output = article_for_object({}, article)
self.assertEqual(output, article)
self.assertIn(article, wiki_tags._cache)
self.assertEqual(wiki_tags._cache[article], article)
output = self.render({"obj": article})
self.assertIn(article, wiki_tags._cache)
self.assertEqual(wiki_tags._cache[article], article)
expected = "Article without content (1)"
self.assertIn(expected, output)
# TODO manage plugins in template
class WikiRenderTest(TemplateTestCase):
template = """
{% load wiki_tags %}
{% wiki_render article pc %}
"""
def tearDown(self):
from wiki.core.plugins import registry
registry._cache = {}
super().tearDown()
keys = [
"article",
"content",
"preview",
"plugins",
"STATIC_URL",
"CACHE_TIMEOUT",
]
def test_if_preview_content_is_none(self):
# monkey patch
from wiki.core.plugins import registry
registry._cache = {"ham": "spam"}
article = Article.objects.create()
output = wiki_render({}, article)
self.assertCountEqual(self.keys, output)
self.assertEqual(output["article"], article)
self.assertIsNone(output["content"])
self.assertIs(output["preview"], False)
self.assertEqual(output["plugins"], {"ham": "spam"})
self.assertEqual(output["STATIC_URL"], django_settings.STATIC_URL)
self.assertEqual(output["CACHE_TIMEOUT"], settings.CACHE_TIMEOUT)
# Additional check
self.render({"article": article, "pc": None})
def test_called_with_preview_content_and_article_have_current_revision(
self
):
article = Article.objects.create()
ArticleRevision.objects.create(
article=article,
title="Test title",
content="Some beauty test text",
)
content = (
"""This is a normal paragraph\n"""
"""\n"""
"""Headline\n"""
"""========\n"""
)
expected = (
"""(?s).*<p>This is a normal paragraph</p>\n"""
"""<h1 id="wiki-toc-headline">Headline"""
""".*</h1>.*"""
)
# monkey patch
from wiki.core.plugins import registry
registry._cache = {"spam": "eggs"}
output = wiki_render({}, article, preview_content=content)
self.assertCountEqual(self.keys, output)
self.assertEqual(output["article"], article)
self.assertRegex(output["content"], expected)
self.assertIs(output["preview"], True)
self.assertEqual(output["plugins"], {"spam": "eggs"})
self.assertEqual(output["STATIC_URL"], django_settings.STATIC_URL)
self.assertEqual(output["CACHE_TIMEOUT"], settings.CACHE_TIMEOUT)
output = self.render({"article": article, "pc": content})
self.assertRegex(output, expected)
def test_called_with_preview_content_and_article_dont_have_current_revision(
self
):
article = Article.objects.create()
content = (
"""This is a normal paragraph\n"""
"""\n"""
"""Headline\n"""
"""========\n"""
)
# monkey patch
from wiki.core.plugins import registry
registry._cache = {"spam": "eggs"}
output = wiki_render({}, article, preview_content=content)
self.assertCountEqual(self.keys, output)
self.assertEqual(output["article"], article)
self.assertMultiLineEqual(output["content"], "")
self.assertIs(output["preview"], True)
self.assertEqual(output["plugins"], {"spam": "eggs"})
self.assertEqual(output["STATIC_URL"], django_settings.STATIC_URL)
self.assertEqual(output["CACHE_TIMEOUT"], settings.CACHE_TIMEOUT)
self.render({"article": article, "pc": content})
class WikiFormTest(TemplateTestCase):
template = """
{% load wiki_tags %}
{% wiki_form form_obj %}
"""
def test_form_obj_is_not_baseform_instance(self):
context = {"test_key": "test_value"}
form_obj = "ham"
with self.assertRaises(TypeError):
wiki_form(context, form_obj)
self.assertEqual(context, {"test_key": "test_value"})
with self.assertRaises(TypeError):
self.render({"test_key": 100500})
self.assertEqual(context, {"test_key": "test_value"})
def test_form_obj_is_baseform_instance(self):
context = {"test_key": "test_value"}
# not by any special reasons, just a form
form_obj = CreateRootForm()
wiki_form(context, form_obj)
self.assertEqual(context, {"test_key": "test_value", "form": form_obj})
self.render({"form_obj": form_obj})
self.assertEqual(context, {"test_key": "test_value", "form": form_obj})
class LoginUrlTest(TemplateTestCase):
template = """
{% load wiki_tags %}
{% login_url as some_url %}
{{ some_url }}
"""
def test_no_request_in_context(self):
with self.assertRaises(KeyError):
login_url({})
with self.assertRaises(KeyError):
self.render({})
def test_login_url_if_no_query_string_in_request(self):
r = HttpRequest()
r.META = {}
r.path = "best/test/page/ever/"
output = login_url({"request": r})
expected = "/_accounts/login/?next=best/test/page/ever/"
self.assertEqual(output, expected)
output = self.render({"request": r})
self.assertIn(expected, output)
def test_login_url_if_query_string_is_empty(self):
r = HttpRequest()
r.META = {"QUERY_STRING": ""}
r.path = "best/test/page/ever/"
output = login_url({"request": r})
expected = "/_accounts/login/?next=best/test/page/ever/"
self.assertEqual(output, expected)
output = self.render({"request": r})
self.assertIn(expected, output)
def test_login_url_if_query_string_is_not_empty(self):
r = HttpRequest()
r.META = {"QUERY_STRING": "title=Main_page&action=raw"}
r.path = "best/test/page/ever/"
context = {"request": r}
output = login_url(context)
expected = (
"/_accounts/login/"
"?next=best/test/page/ever/%3Ftitle%3DMain_page%26action%3Draw"
)
self.assertEqual(output, expected)
output = self.render({"request": r})
self.assertIn(expected, output)

78
tests/core/test_urls.py Normal file
View File

@@ -0,0 +1,78 @@
from django.conf.urls.static import static
from django.contrib.sites.models import Site
from django.test.testcases import TestCase
from django.urls import include
from django.urls import re_path
from wiki.models import Article
from wiki.models import URLPath
from wiki.urls import get_pattern as get_wiki_pattern
from wiki.urls import WikiURLPatterns
from ..base import wiki_override_settings
class WikiCustomUrlPatterns(WikiURLPatterns):
def get_article_urls(self):
urlpatterns = [
re_path(
"^some-prefix/(?P<article_id>[0-9]+)/$",
self.article_view_class.as_view(),
name="get",
),
]
return urlpatterns
def get_article_path_urls(self):
urlpatterns = [
re_path(
"^some-other-prefix/(?P<path>.+/|)$",
self.article_view_class.as_view(),
name="get",
),
]
return urlpatterns
urlpatterns = [
re_path(r"^notify/", include("django_nyt.urls")),
re_path(
r"^elsewhere/",
get_wiki_pattern(url_config_class=WikiCustomUrlPatterns),
),
] + static("/static/", document_root="./")
@wiki_override_settings(
WIKI_URL_CONFIG_CLASS="tests.core.test_models.WikiCustomUrlPatterns",
ROOT_URLCONF="tests.core.test_urls",
)
class ArticleModelReverseMethodTest(TestCase):
def test_get_absolute_url_if_urlpath_set_is_not_exists__no_root_urlconf(
self
):
a = Article.objects.create()
url = a.get_absolute_url()
expected = "/elsewhere/some-prefix/1/"
self.assertEqual(url, expected)
def test_get_absolute_url_if_urlpath_set_is_exists__no_root_urlconf(self):
a1 = Article.objects.create()
s1 = Site.objects.create(domain="something.com", name="something.com")
u1 = URLPath.objects.create(article=a1, site=s1)
a2 = Article.objects.create()
s2 = Site.objects.create(
domain="somethingelse.com", name="somethingelse.com"
)
URLPath.objects.create(
article=a2, site=s2, parent=u1, slug="test_slug"
)
url = a2.get_absolute_url()
expected = "/elsewhere/some-other-prefix/test_slug/"
self.assertEqual(url, expected)

14
tests/core/test_utils.py Normal file
View File

@@ -0,0 +1,14 @@
from django.test import TestCase
from wiki.core.utils import object_to_json_response
class TestUtils(TestCase):
def test_object_to_json(self):
"""
Simple test, the actual serialization happens in json.dumps and we
don't wanna test this core module in depth.
"""
obj = []
response = object_to_json_response(obj)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content, b"[]")

982
tests/core/test_views.py Normal file
View File

@@ -0,0 +1,982 @@
import pprint
from django.contrib.messages import constants
from django.contrib.messages import get_messages
from django.http import JsonResponse
from django.shortcuts import resolve_url
from django.test import override_settings
from django.utils import translation
from django.utils.html import escape
from django_functest import FuncBaseMixin
from wiki import models
from wiki.conf import settings as wiki_settings
from wiki.forms import PermissionsForm
from wiki.forms import validate_slug_numbers
from wiki.models import ArticleRevision
from wiki.models import reverse
from wiki.models import URLPath
from ..base import ArticleWebTestUtils
from ..base import DjangoClientTestBase
from ..base import NORMALUSER1_PASSWORD
from ..base import NORMALUSER1_USERNAME
from ..base import RequireRootArticleMixin
from ..base import SeleniumBase
from ..base import SUPERUSER1_USERNAME
from ..base import WebTestBase
from tests.testdata.models import CustomGroup
class RootArticleViewTestsBase(FuncBaseMixin):
"""Tests for creating/viewing the root article."""
def test_root_article(self):
"""
Test redirecting to /create-root/,
creating the root article and a simple markup.
"""
self.get_url("wiki:root")
self.assertUrlsEqual(resolve_url("wiki:root_create"))
self.fill(
{
"#id_content": "test heading h1\n====\n",
"#id_title": "Wiki Test",
}
)
self.submit('button[name="save_changes"]')
self.assertUrlsEqual("/")
self.assertTextPresent("test heading h1")
article = URLPath.root().article
self.assertIn("test heading h1", article.current_revision.content)
class RootArticleViewTestsWebTest(RootArticleViewTestsBase, WebTestBase):
pass
class RootArticleViewTestsSelenium(RootArticleViewTestsBase, SeleniumBase):
pass
class ArticleViewViewTests(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
"""
Tests for article views, assuming a root article already created.
"""
def dump_db_status(self, message=""):
"""Debug printing of the complete important database content."""
print(f"*** db status *** {message}")
from wiki.models import Article, ArticleRevision
for klass in (Article, ArticleRevision, URLPath):
print(f"* {klass.__name__} *")
pprint.pprint(list(klass.objects.values()), width=240)
def test_redirects_to_create_if_the_slug_is_unknown(self):
response = self.get_by_path("unknown/")
self.assertRedirects(
response, resolve_url("wiki:create", path="") + "?slug=unknown"
)
def test_redirects_to_create_with_lowercased_slug(self):
response = self.get_by_path("Unknown_Linked_Page/")
self.assertRedirects(
response,
resolve_url("wiki:create", path="") + "?slug=unknown_linked_page",
)
def test_article_list_update(self):
"""
Test automatic adding and removing the new article to/from article_list.
"""
root_data = {
"content": "[article_list depth:2]",
"current_revision": str(
URLPath.root().article.current_revision.id
),
"preview": "1",
"title": "Root Article",
}
response = self.client.post(
resolve_url("wiki:edit", path=""), root_data
)
self.assertRedirects(response, resolve_url("wiki:root"))
# verify the new article is added to article_list
response = self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Sub Article 1", "slug": "SubArticle1"},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="subarticle1/")
)
self.assertContains(self.get_by_path(""), "Sub Article 1")
self.assertContains(self.get_by_path(""), "subarticle1/")
# verify the deleted article is removed from article_list
response = self.client.post(
resolve_url("wiki:delete", path="SubArticle1/"),
{
"confirm": "on",
"purge": "on",
"revision": str(
URLPath.objects.get(
slug="subarticle1"
).article.current_revision.id
),
},
)
self.assertRedirects(response, resolve_url("wiki:get", path=""))
messages = [m.message for m in get_messages(response.wsgi_request)]
self.assertIn(
"This article together with all its contents are now completely gone",
messages[0],
)
self.assertNotContains(self.get_by_path(""), "Sub Article 1")
def test_anonymous_root(self):
self.client.logout()
response = self.client.get(
reverse("wiki:get", kwargs={"article_id": self.root_article.pk})
)
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("wiki:get", kwargs={"path": ""}))
self.assertEqual(response.status_code, 200)
def test_normaluser_root(self):
self.client.login(
username=NORMALUSER1_USERNAME, password=NORMALUSER1_PASSWORD
)
response = self.client.get(
reverse("wiki:get", kwargs={"article_id": self.root_article.pk})
)
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("wiki:get", kwargs={"path": ""}))
self.assertEqual(response.status_code, 200)
def test_show_max_children(self):
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Main",
"slug": "WikiRoot",
"content": "Content level 1",
},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="wikiroot/")
)
response = self.client.get(
reverse("wiki:get", kwargs={"path": "wikiroot/"})
)
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response.context["children_slice"], list)
self.assertEqual(len(response.context["children_slice"]), 0)
for idx in range(1, 40):
response = self.client.post(
resolve_url("wiki:create", path="wikiroot/"),
{
"title": f"Sub Article {idx}",
"slug": f"SubArticle{idx}",
"content": f"Sub Article {idx}",
},
)
self.assertRedirects(
response,
resolve_url("wiki:get", path=f"wikiroot/subarticle{idx}/"),
)
response = self.client.get(
reverse("wiki:get", kwargs={"path": "wikiroot/"})
)
self.assertEqual(response.status_code, 200)
self.assertEqual(
len(response.context["children_slice"]),
wiki_settings.SHOW_MAX_CHILDREN,
)
class CreateViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_create_nested_article_in_article(self):
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Level 1",
"slug": "Level1",
"content": "Content level 1",
},
)
self.assertRedirects(response, resolve_url("wiki:get", path="level1/"))
response = self.client.post(
resolve_url("wiki:create", path="Level1/"),
{"title": "test", "slug": "Test", "content": "Content on level 2"},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="level1/test/")
)
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "test",
"slug": "Test",
"content": "Other content on level 1",
},
)
self.assertRedirects(response, resolve_url("wiki:get", path="test/"))
self.assertContains(
self.get_by_path("Test/"), "Other content on level 1"
)
self.assertContains(
self.get_by_path("Level1/Test/"), "Content"
) # on level 2')
def test_illegal_slug(self):
# A slug cannot be '123' because it gets confused with an article ID.
response = self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Illegal slug", "slug": "123", "content": "blah"},
)
self.assertContains(response, escape(validate_slug_numbers.message))
class MoveViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_illegal_slug(self):
# A slug cannot be '123' because it gets confused with an article ID.
response = self.client.post(
resolve_url("wiki:move", path=""),
{"destination": "", "slug": "123", "redirect": ""},
)
self.assertContains(response, escape(validate_slug_numbers.message))
def test_move(self):
# Create a hierarchy of pages
self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Test", "slug": "test0", "content": "Content .0."},
)
self.client.post(
resolve_url("wiki:create", path="test0/"),
{"title": "Test00", "slug": "test00", "content": "Content .00."},
)
self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Test1", "slug": "test1", "content": "Content .1."},
)
self.client.post(
resolve_url("wiki:create", path="test1/"),
{"title": "Tes10", "slug": "test10", "content": "Content .10."},
)
self.client.post(
resolve_url("wiki:create", path="test1/test10/"),
{
"title": "Test100",
"slug": "test100",
"content": "Content .100.",
},
)
# Move /test1 => /test0 (an already existing destination slug!)
response = self.client.post(
resolve_url("wiki:move", path="test1/"),
{
"destination": str(URLPath.root().article.current_revision.id),
"slug": "test0",
"redirect": "",
},
)
self.assertContains(response, "A slug named")
self.assertContains(response, "already exists.")
# Move /test1 >= /test2 (valid slug), no redirect
test0_id = URLPath.objects.get(
slug="test0"
).article.current_revision.id
response = self.client.post(
resolve_url("wiki:move", path="test1/"),
{"destination": str(test0_id), "slug": "test2", "redirect": ""},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="test0/test2/")
)
# Check that there is no article displayed in this path anymore
response = self.get_by_path("test1/")
self.assertRedirects(response, "/_create/?slug=test1")
# Create /test0/test2/test020
response = self.client.post(
resolve_url("wiki:create", path="test0/test2/"),
{
"title": "Test020",
"slug": "test020",
"content": "Content .020.",
},
)
# Move /test0/test2 => /test1new + create redirect
response = self.client.post(
resolve_url("wiki:move", path="test0/test2/"),
{
"destination": str(URLPath.root().article.current_revision.id),
"slug": "test1new",
"redirect": "true",
},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="test1new/")
)
# Check that /test1new is a valid path
response = self.get_by_path("test1new/")
self.assertContains(response, "Content .1.")
# Check that the child article test0/test2/test020 was also moved
response = self.get_by_path("test1new/test020/")
self.assertContains(response, "Content .020.")
response = self.get_by_path("test0/test2/")
self.assertContains(response, "Moved: Test1")
self.assertRegex(
response.rendered_content, r"moved to <a[^>]*>wiki:/test1new/"
)
response = self.get_by_path("test0/test2/test020/")
self.assertContains(response, "Moved: Test020")
self.assertRegex(
response.rendered_content,
r"moved to <a[^>]*>wiki:/test1new/test020",
)
# Check that moved_to was correctly set
urlsrc = URLPath.get_by_path("/test0/test2/")
urldst = URLPath.get_by_path("/test1new/")
self.assertEqual(urlsrc.moved_to, urldst)
# Check that moved_to was correctly set on the child's previous path
urlsrc = URLPath.get_by_path("/test0/test2/test020/")
urldst = URLPath.get_by_path("/test1new/test020/")
self.assertEqual(urlsrc.moved_to, urldst)
def test_translation(self):
# Test that translation of "Be careful, links to this article" exists.
self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Test", "slug": "test0", "content": "Content"},
)
url = resolve_url("wiki:move", path="test0/")
response_en = self.client.get(url)
self.assertIn("Move article", response_en.rendered_content)
self.assertIn("Be careful", response_en.rendered_content)
with translation.override("da-DK"):
response_da = self.client.get(url)
self.assertNotIn("Move article", response_da.rendered_content)
self.assertNotIn("Be careful", response_da.rendered_content)
class DeleteViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_render_delete_view(self):
"""
Other tests do not render the delete view but just sends a POST
"""
self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Test delete",
"slug": "testdelete",
"content": "To be deleted",
},
)
response = self.client.get(
resolve_url("wiki:delete", path="testdelete/"),
)
# test the cache
self.assertContains(response, "Delete article")
def test_articles_cache_is_cleared_after_deleting(self):
# That bug is tested by one individual test, otherwise it could be
# revealed only by sequence of tests in some particular order
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Test cache",
"slug": "testcache",
"content": "Content 1",
},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="testcache/")
)
response = self.client.post(
resolve_url("wiki:delete", path="testcache/"),
{
"confirm": "on",
"purge": "on",
"revision": str(
URLPath.objects.get(
slug="testcache"
).article.current_revision.id
),
},
)
self.assertRedirects(response, resolve_url("wiki:get", path=""))
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Test cache",
"slug": "TestCache",
"content": "Content 2",
},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="testcache/")
)
self.assertContains(self.get_by_path("TestCache/"), "Content 2")
def test_deleted_view(self):
"""
Test that a special page is shown for restoring/purging a deleted
article.
"""
# 1. Create the article
self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Test delete",
"slug": "testdelete",
"content": "To be deleted",
},
)
# 2. Soft delete it
self.client.post(
resolve_url("wiki:delete", path="testdelete/"),
{
"confirm": "on",
"purge": "",
"revision": str(
URLPath.objects.get(
slug="testdelete"
).article.current_revision.id
),
},
)
# 3. Get and test that it redirects to the deleted page
response = self.client.get(
resolve_url("wiki:get", path="testdelete/"),
follow=True,
)
# test that it's the Deleted page
self.assertContains(response, "Article deleted")
# 4. Test that we can purge the page now
self.client.post(
resolve_url("wiki:deleted", path="testdelete/"),
{
"confirm": "on",
"purge": "on",
"revision": str(
URLPath.objects.get(
slug="testdelete"
).article.current_revision.id
),
},
)
# 5. Test that it's not found anymore
response = self.client.get(
resolve_url("wiki:get", path="testdelete/"),
follow=True,
)
self.assertContains(response, "Add new article")
# def test_delete_article_without_urlpath(self):
# """
# We need a test that tests that articles without URLpaths are correctly
# deleted.
# """
# pass
# def test_dont_delete_children(self):
# Article.objects.create()
class EditViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_preview_save(self):
"""Test edit preview, edit save and messages."""
example_data = {
"content": "The modified text",
"current_revision": str(
URLPath.root().article.current_revision.id
),
"preview": "1",
# 'save': '1', # probably not too important
"summary": "why edited",
"title": "wiki test",
}
# test preview
response = self.client.post(
resolve_url("wiki:preview", path=""),
example_data, # url: '/_preview/'
)
self.assertContains(response, "The modified text")
def test_preview_xframe_options_sameorigin(self):
"""Ensure that preview response has X-Frame-Options: SAMEORIGIN"""
example_data = {
"content": "The modified text",
"current_revision": str(
URLPath.root().article.current_revision.id
),
"preview": "1",
"summary": "why edited",
"title": "wiki test",
}
response = self.client.post(
resolve_url("wiki:preview", path=""), example_data
)
self.assertEqual(response.get("X-Frame-Options"), "SAMEORIGIN")
def test_revision_conflict(self):
"""
Test the warning if the same article is being edited concurrently.
"""
example_data = {
"content": "More modifications",
"current_revision": str(
URLPath.root().article.current_revision.id
),
"preview": "0",
"save": "1",
"summary": "why edited",
"title": "wiki test",
}
response = self.client.post(
resolve_url("wiki:edit", path=""), example_data
)
self.assertRedirects(response, resolve_url("wiki:root"))
response = self.client.post(
resolve_url("wiki:edit", path=""), example_data
)
self.assertContains(
response,
"While you were editing, someone else changed the revision.",
)
class DiffViewTests(RequireRootArticleMixin, DjangoClientTestBase):
def setUp(self):
super().setUp()
self.root_article.add_revision(
ArticleRevision(title="New Revision"), save=True
)
self.new_revision = self.root_article.current_revision
def test_diff(self):
response = self.client.get(
reverse("wiki:diff", kwargs={"revision_id": self.root_article.pk})
)
diff = {
"diff": ["+ root article content"],
"other_changes": [["New title", "Root Article"]],
}
self.assertJSONEqual(str(response.content, encoding="utf8"), diff)
self.assertIsInstance(response, JsonResponse)
self.assertEqual(response.status_code, 200)
class EditViewTestsBase(RequireRootArticleMixin, FuncBaseMixin):
def test_edit_save(self):
old_revision = URLPath.root().article.current_revision
self.get_url("wiki:edit", path="")
self.fill(
{
"#id_content": "Something 2",
"#id_summary": "why edited",
"#id_title": "wiki test",
}
)
self.submit("#id_save")
self.assertTextPresent("Something 2")
self.assertTextPresent("successfully added")
new_revision = URLPath.root().article.current_revision
self.assertIn("Something 2", new_revision.content)
self.assertEqual(
new_revision.revision_number, old_revision.revision_number + 1
)
class EditViewTestsWebTest(EditViewTestsBase, WebTestBase):
pass
class EditViewTestsSelenium(EditViewTestsBase, SeleniumBase):
# Javascript only tests:
def test_preview_and_save(self):
self.get_url("wiki:edit", path="")
self.fill(
{
"#id_content": "Some changed stuff",
"#id_summary": "why edited",
"#id_title": "wiki test",
}
)
self.click("#id_preview")
self.submit("#id_preview_save_changes")
new_revision = URLPath.root().article.current_revision
self.assertIn("Some changed stuff", new_revision.content)
class SearchViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_query_string(self):
response = self.client.get(
resolve_url("wiki:search"), {"q": "Article"}
)
self.assertContains(response, "Root Article")
def test_empty_query_string(self):
response = self.client.get(resolve_url("wiki:search"), {"q": ""})
self.assertFalse(response.context["articles"])
def test_hierarchy_search(self):
c = self.client
c.post(
resolve_url("wiki:create", path=""),
{"title": "Test0", "slug": "test0", "content": "Content test0"},
)
c.post(
resolve_url("wiki:create", path=""),
{"title": "Test1", "slug": "test1", "content": "Content test1"},
)
c.post(
resolve_url("wiki:create", path="test0/"),
{
"title": "Subtest0",
"slug": "subtest0",
"content": "Content test2",
},
)
response = c.get(
resolve_url("wiki:search", path="test0/"), {"q": "Content test"}
)
articles = response.context["articles"]
def contains_title(articles, title):
return any(
article.current_revision.title == title for article in articles
)
self.assertIs(contains_title(articles, "Test0"), True)
self.assertIs(contains_title(articles, "Test1"), False)
self.assertIs(contains_title(articles, "Subtest0"), True)
def test_hierarchy_search_404(self):
c = self.client
response = c.get(
resolve_url("wiki:search", path="test0/"), {"q": "Content test"}
)
self.assertEqual(response.status_code, 404)
class DeletedListViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_deleted_articles_list(self):
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Delete Me",
"slug": "deleteme",
"content": "delete me please!",
},
)
self.assertRedirects(
response, resolve_url("wiki:get", path="deleteme/")
)
response = self.client.post(
resolve_url("wiki:delete", path="deleteme/"),
{
"confirm": "on",
"revision": URLPath.objects.get(
slug="deleteme"
).article.current_revision.id,
},
)
self.assertRedirects(response, resolve_url("wiki:get", path=""))
response = self.client.get(resolve_url("wiki:deleted_list"))
self.assertContains(response, "Delete Me")
class MergeViewTest(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_merge_preview(self):
"""Test merge preview"""
first_revision = self.root_article.current_revision
example_data = {
"content": "More modifications\n\nMerge new line",
"current_revision": str(first_revision.id),
"preview": "0",
"save": "1",
"summary": "testing merge",
"title": "wiki test",
}
# save a new revision
self.client.post(resolve_url("wiki:edit", path=""), example_data)
new_revision = models.Article.objects.get(
id=self.root_article.id
).current_revision
response = self.client.get(
resolve_url(
"wiki:merge_revision_preview",
article_id=self.root_article.id,
revision_id=first_revision.id,
),
)
self.assertContains(response, "Previewing merge between:")
self.assertContains(
response,
f"#{first_revision.revision_number}",
)
self.assertContains(
response,
f"#{new_revision.revision_number}",
)
class SourceViewTests(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_template_used(self):
response = self.client.get(
reverse("wiki:source", kwargs={"article_id": self.root_article.pk})
)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, template_name="wiki/source.html")
def test_can_read_permission(self):
# everybody can see the source of an article
self.client.logout()
response = self.client.get(
reverse("wiki:source", kwargs={"article_id": self.root_article.pk})
)
self.assertEqual(response.status_code, 200)
def test_content(self):
response = self.client.get(
reverse("wiki:source", kwargs={"article_id": self.root_article.pk})
)
self.assertIn("Source of ", str(response.content))
self.assertEqual(response.context["selected_tab"], "source")
class HistoryViewTests(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_can_read_permission(self):
response = self.client.get(
reverse(
"wiki:history", kwargs={"article_id": self.root_article.pk}
)
)
self.assertEqual(response.status_code, 200)
def test_content(self):
response = self.client.get(
reverse(
"wiki:history", kwargs={"article_id": self.root_article.pk}
)
)
self.assertContains(response, "History:")
self.assertEqual(response.context["selected_tab"], "history")
class DirViewTests(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_browse_root(self):
response = self.client.get(
reverse("wiki:dir", kwargs={"path": ""}),
)
self.assertRegex(
response.rendered_content,
r'Browsing\s+<strong><a href=".+">/</a></strong>',
)
def test_browse_root_query(self):
self.client.post(
resolve_url("wiki:create", path=""),
{"title": "Test", "slug": "test0", "content": "Content .0."},
)
self.client.post(
resolve_url("wiki:create", path="test0/"),
{"title": "Test00", "slug": "test00", "content": "Content .00."},
)
response = self.client.get(
reverse("wiki:dir", kwargs={"path": ""}),
{"query": "Test"},
)
self.assertRegex(response.rendered_content, r"1 article")
response = self.client.get(
reverse("wiki:dir", kwargs={"path": "test0/"}),
{"query": "Test00"},
)
self.assertRegex(response.rendered_content, r"1 article")
class SettingsViewTests(
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
):
def test_change_group(self):
group = CustomGroup.objects.create()
response = self.client.post(
resolve_url("wiki:settings", article_id=self.root_article.pk)
+ "?f=form0",
{"group": group.pk, "owner_username": SUPERUSER1_USERNAME},
follow=True,
)
self.root_article.refresh_from_db()
self.assertEqual(self.root_article.group, group)
self.assertEqual(self.root_article.owner, self.superuser1)
messages = list(get_messages(response.wsgi_request))
self.assertEqual(len(messages), 1)
message = messages[0]
self.assertEqual(message.level, constants.SUCCESS)
self.assertEqual(
message.message,
"Permission settings for the article were updated.",
)
def test_change_invalid_owner(self):
self.assertIsNone(self.root_article.owner)
response = self.client.post(
resolve_url("wiki:settings", article_id=self.root_article.pk)
+ "?f=form0",
{"owner_username": "invalid"},
follow=True,
)
self.assertEqual(
response.context["forms"][0].errors["owner_username"],
["No user with that username"],
)
def test_unchanged_message(self):
# 1. This is not pretty: Constructs a request object to use to construct
# the PermissionForm
get_response = self.client.get(
resolve_url("wiki:settings", article_id=self.root_article.pk)
)
# 2. Construct a PermissionForm
form = PermissionsForm(self.root_article, get_response.wsgi_request)
# 3. ...in order to get the POST form values that will be transmitted
form_values = {field.html_name: field.value() or "" for field in form}
# 4. Send an unchanged form
response = self.client.post(
resolve_url("wiki:settings", article_id=self.root_article.pk)
+ "?f=form0",
form_values,
follow=True,
)
messages = list(get_messages(response.wsgi_request))
self.assertEqual(len(messages), 1)
message = messages[0]
self.assertEqual(message.level, constants.SUCCESS)
self.assertEqual(
message.message,
"Your permission settings were unchanged, so nothing saved.",
)
@override_settings(ACCOUNT_HANDLING=True)
def test_login_required(self):
self.client.logout()
response = self.client.get(
reverse(
"wiki:settings", kwargs={"article_id": self.root_article.pk}
)
)
# it's redirecting
self.assertEqual(response.status_code, 302)
def test_auth_user(self):
response = self.client.get(
reverse(
"wiki:settings", kwargs={"article_id": self.root_article.pk}
)
)
self.assertEqual(response.status_code, 200)
def test_normal_user(self):
"""
Tests that the settings view page renders for a normal user
Regression test: https://github.com/django-wiki/django-wiki/issues/1058
"""
response = self.client.post(
resolve_url("wiki:create", path=""),
{
"title": "Level 1",
"slug": "Level1",
"content": "Content level 1",
},
)
self.client.login(
username=NORMALUSER1_USERNAME, password=NORMALUSER1_PASSWORD
)
response = self.client.get(
reverse("wiki:settings", kwargs={"path": "level1/"})
)
self.assertEqual(response.status_code, 200)
def test_content(self):
response = self.client.get(
reverse(
"wiki:settings", kwargs={"article_id": self.root_article.pk}
)
)
self.assertEqual(response.context["selected_tab"], "settings")