initial
This commit is contained in:
0
tests/plugins/__init__.py
Normal file
0
tests/plugins/__init__.py
Normal file
0
tests/plugins/attachments/__init__.py
Normal file
0
tests/plugins/attachments/__init__.py
Normal file
38
tests/plugins/attachments/test_commands.py
Normal file
38
tests/plugins/attachments/test_commands.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
from wiki.models import URLPath
|
||||
from wiki.plugins.attachments import models
|
||||
|
||||
from tests.core.test_commands import TestManagementCommands
|
||||
|
||||
|
||||
class TestAttachmentManagementCommands(TestManagementCommands):
|
||||
"""
|
||||
Add some more data
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.test_file = tempfile.NamedTemporaryFile(
|
||||
"w", delete=False, suffix=".txt"
|
||||
)
|
||||
self.test_file.write("test")
|
||||
|
||||
self.child1 = URLPath.create_urlpath(
|
||||
self.root, "test-slug", title="Test 1"
|
||||
)
|
||||
|
||||
self.attachment1 = models.Attachment.objects.create(
|
||||
article=self.child1.article
|
||||
)
|
||||
|
||||
self.attachment1_revision1 = models.AttachmentRevision.objects.create(
|
||||
attachment=self.attachment1,
|
||||
file=self.test_file.name,
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
os.unlink(self.test_file.name)
|
||||
super().tearDown()
|
||||
42
tests/plugins/attachments/test_models.py
Normal file
42
tests/plugins/attachments/test_models.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from wiki.plugins.attachments.models import Attachment
|
||||
from wiki.plugins.attachments.models import AttachmentRevision
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class AttachmentRevisionTests(RequireRootArticleMixin, TestBase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.attachment = Attachment.objects.create(
|
||||
article=self.root_article,
|
||||
original_filename="blah.txt",
|
||||
)
|
||||
self.revision = AttachmentRevision.objects.create(
|
||||
attachment=self.attachment,
|
||||
file=None,
|
||||
description="muh",
|
||||
revision_number=1,
|
||||
)
|
||||
|
||||
def test_revision_no_file(self):
|
||||
# Intentionally, there are no asserts, as the test just needs to
|
||||
# target an if-branch in the pre-delete signal for AttachmentRevision
|
||||
self.revision.delete()
|
||||
|
||||
def test_revision_file_size(self):
|
||||
self.assertIsNone(self.revision.get_size())
|
||||
|
||||
def test_get_filename_no_file(self):
|
||||
self.assertIsNone(self.revision.get_filename())
|
||||
|
||||
def test_str(self):
|
||||
self.assertEqual(
|
||||
str(self.revision),
|
||||
"%s: %s (r%d)"
|
||||
% (
|
||||
"Root Article",
|
||||
"blah.txt",
|
||||
1,
|
||||
),
|
||||
)
|
||||
183
tests/plugins/attachments/test_views.py
Normal file
183
tests/plugins/attachments/test_views.py
Normal file
@@ -0,0 +1,183 @@
|
||||
from io import BytesIO
|
||||
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.urls import reverse
|
||||
from wiki.models import URLPath
|
||||
|
||||
from ...base import ArticleWebTestUtils
|
||||
from ...base import DjangoClientTestBase
|
||||
from ...base import RequireRootArticleMixin
|
||||
|
||||
|
||||
class AttachmentTests(
|
||||
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
|
||||
):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.article = self.root_article
|
||||
self.test_data = "This is a plain text file"
|
||||
self.test_description = "My file"
|
||||
|
||||
def _createTxtFilestream(self, strData, **kwargs):
|
||||
"""
|
||||
Helper function to create filestream for upload.
|
||||
|
||||
Parameters :
|
||||
strData : str, test string data
|
||||
|
||||
Optional Arguments :
|
||||
filename : str, Defaults to 'test.txt'
|
||||
"""
|
||||
filename = kwargs.get("filename", "test.txt")
|
||||
data = strData.encode("utf-8")
|
||||
filedata = BytesIO(data)
|
||||
filestream = InMemoryUploadedFile(
|
||||
filedata, None, filename, "text", len(data), None
|
||||
)
|
||||
return filestream
|
||||
|
||||
def _create_test_attachment(self, path):
|
||||
url = reverse("wiki:attachments_index", kwargs={"path": path})
|
||||
filestream = self._createTxtFilestream(self.test_data)
|
||||
response = self.client.post(
|
||||
url,
|
||||
{
|
||||
"description": self.test_description,
|
||||
"file": filestream,
|
||||
"save": "1",
|
||||
},
|
||||
)
|
||||
self.assertRedirects(response, url)
|
||||
|
||||
def test_upload(self):
|
||||
"""
|
||||
Tests that simple file upload uploads correctly
|
||||
Uploading a file should preserve the original filename.
|
||||
Uploading should not modify file in any way.
|
||||
"""
|
||||
self._create_test_attachment("")
|
||||
# Check the object was created.
|
||||
attachment = self.article.shared_plugins_set.all()[0].attachment
|
||||
self.assertEqual(attachment.original_filename, "test.txt")
|
||||
self.assertEqual(
|
||||
attachment.current_revision.file.file.read(),
|
||||
self.test_data.encode("utf-8"),
|
||||
)
|
||||
|
||||
def test_replace(self):
|
||||
"""
|
||||
Tests that previous revisions are not deleted
|
||||
Tests that only the most recent revision is deleted when
|
||||
"replace" is checked.
|
||||
"""
|
||||
# Upload initial file
|
||||
url = reverse("wiki:attachments_index", kwargs={"path": ""})
|
||||
data = "This is a plain text file"
|
||||
filestream = self._createTxtFilestream(data)
|
||||
self.client.post(
|
||||
url, {"description": "My file", "file": filestream, "save": "1"}
|
||||
)
|
||||
attachment = self.article.shared_plugins_set.all()[0].attachment
|
||||
|
||||
# uploading for the first time should mean that there is only one revision.
|
||||
self.assertEqual(attachment.attachmentrevision_set.count(), 1)
|
||||
|
||||
# Change url to replacement page.
|
||||
url = reverse(
|
||||
"wiki:attachments_replace",
|
||||
kwargs={
|
||||
"attachment_id": attachment.id,
|
||||
"article_id": self.article.id,
|
||||
},
|
||||
)
|
||||
|
||||
# Upload replacement without removing revisions
|
||||
replacement_data = data + " And this is my edit"
|
||||
replacement_filestream = self._createTxtFilestream(replacement_data)
|
||||
self.client.post(
|
||||
url,
|
||||
{
|
||||
"description": "Replacement upload",
|
||||
"file": replacement_filestream,
|
||||
},
|
||||
)
|
||||
attachment = self.article.shared_plugins_set.all()[0].attachment
|
||||
# Revision count should be two
|
||||
self.assertEqual(attachment.attachmentrevision_set.count(), 2)
|
||||
# Original filenames should not be modified
|
||||
self.assertEqual(attachment.original_filename, "test.txt")
|
||||
# Latest revision should equal replacment_data
|
||||
self.assertEqual(
|
||||
attachment.current_revision.file.file.read(),
|
||||
replacement_data.encode("utf-8"),
|
||||
)
|
||||
first_replacement = attachment.current_revision
|
||||
|
||||
# Upload another replacement, this time removing most recent revision
|
||||
replacement_data2 = data + " And this is a different edit"
|
||||
replacement_filestream2 = self._createTxtFilestream(replacement_data2)
|
||||
self.client.post(
|
||||
url,
|
||||
{
|
||||
"description": "Replacement upload",
|
||||
"file": replacement_filestream2,
|
||||
"replace": "on",
|
||||
},
|
||||
)
|
||||
attachment = self.article.shared_plugins_set.all()[0].attachment
|
||||
# Revision count should still be two
|
||||
self.assertEqual(attachment.attachmentrevision_set.count(), 2)
|
||||
# Latest revision should equal replacment_data2
|
||||
self.assertEqual(
|
||||
attachment.current_revision.file.file.read(),
|
||||
replacement_data2.encode("utf-8"),
|
||||
)
|
||||
# The first replacement should no longer be in the filehistory
|
||||
self.assertNotIn(
|
||||
first_replacement, attachment.attachmentrevision_set.all()
|
||||
)
|
||||
|
||||
def test_search(self):
|
||||
"""
|
||||
Call the search view
|
||||
"""
|
||||
self._create_test_attachment("")
|
||||
url = reverse("wiki:attachments_search", kwargs={"path": ""})
|
||||
response = self.client.get(url, {"query": self.test_description})
|
||||
self.assertContains(response, self.test_description)
|
||||
|
||||
def get_article(self, cont):
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "html_attach", title="TestAttach", content=cont
|
||||
)
|
||||
self._create_test_attachment(urlpath.path)
|
||||
return urlpath.article.render()
|
||||
|
||||
def test_render(self):
|
||||
output = self.get_article("[attachment:1]")
|
||||
expected = (
|
||||
r'<span class="attachment"><a href=".*attachments/download/1/"'
|
||||
r' title="Click to download test\.txt">\s*test\.txt\s*</a>'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
def test_render_missing(self):
|
||||
output = self.get_article("[attachment:2]")
|
||||
expected = r'<span class="attachment attachment-deleted">\s*Attachment with ID #2 is deleted.\s*</span>'
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
def test_render_title(self):
|
||||
output = self.get_article('[attachment:1 title:"Test title"]')
|
||||
expected = (
|
||||
r'<span class="attachment"><a href=".*attachments/download/1/"'
|
||||
r' title="Click to download test\.txt">\s*Test title\s*</a>'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
def test_render_title_size(self):
|
||||
output = self.get_article('[attachment:1 title:"Test title 2" size]')
|
||||
expected = (
|
||||
r'<span class="attachment"><a href=".*attachments/download/1/"'
|
||||
r' title="Click to download test\.txt">\s*Test title 2 \[25[^b]bytes\]\s*</a>'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
0
tests/plugins/editsection/__init__.py
Normal file
0
tests/plugins/editsection/__init__.py
Normal file
207
tests/plugins/editsection/test_editsection.py
Normal file
207
tests/plugins/editsection/test_editsection.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import re
|
||||
|
||||
from django.urls import reverse
|
||||
from django_functest import FuncBaseMixin
|
||||
from wiki.models import URLPath
|
||||
|
||||
from ...base import DjangoClientTestBase
|
||||
from ...base import RequireRootArticleMixin
|
||||
from ...base import WebTestBase
|
||||
|
||||
TEST_CONTENT = (
|
||||
"Title 1\n"
|
||||
"=======\n"
|
||||
"## Title 2\n"
|
||||
"Title 3\n"
|
||||
"-------\n"
|
||||
"a\n"
|
||||
"Paragraph\n"
|
||||
"-------\n"
|
||||
"### Title 4\n"
|
||||
"## Title 5\n"
|
||||
"# Title 6\n"
|
||||
)
|
||||
|
||||
|
||||
TEST_CONTENT_SRC_COMMENT = """
|
||||
# Section 1
|
||||
Section 1 Lorem ipsum dolor sit amet
|
||||
|
||||
```python
|
||||
# hello world
|
||||
print("hello world")
|
||||
```
|
||||
|
||||
# Section 2
|
||||
Section 2 Lorem ipsum dolor sit amet
|
||||
"""
|
||||
|
||||
|
||||
class EditSectionTests(RequireRootArticleMixin, DjangoClientTestBase):
|
||||
def test_editsection(self):
|
||||
# Test creating links to allow editing all sections individually
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "testedit", title="TestEdit", content=TEST_CONTENT
|
||||
)
|
||||
output = urlpath.article.render()
|
||||
expected = (
|
||||
r"(?s)"
|
||||
r'Title 1<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-1/">\[edit\]</a>.*'
|
||||
r'Title 2<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-2/">\[edit\]</a>.*'
|
||||
r'Title 3<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-3/">\[edit\]</a>.*'
|
||||
r'Title 4<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-4/">\[edit\]</a>.*'
|
||||
r'Title 5<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-5/">\[edit\]</a>.*'
|
||||
r'Title 6<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-6/">\[edit\]</a>.*'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
# Test wrong header text. Editing should fail with a redirect.
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit/", "header": "does-not-exist"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:get", kwargs={"path": "testedit/"})
|
||||
)
|
||||
|
||||
# Test extracting sections for editing
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit/", "header": "wiki-toc-title-4"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
expected = ">### Title 4[\r\n]*" "<"
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit/", "header": "wiki-toc-title-3"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
expected = (
|
||||
">Title 3[\r\n]*"
|
||||
"-------[\r\n]*"
|
||||
"a[\r\n]*"
|
||||
"Paragraph[\r\n]*"
|
||||
"-------[\r\n]*"
|
||||
"### Title 4[\r\n]*"
|
||||
"<"
|
||||
)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
def test_broken_content(self):
|
||||
# Regression test for https://github.com/django-wiki/django-wiki/issues/1094
|
||||
TEST_CONTENT = "### [Here we go](#anchor)"
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "testedit", title="TestEdit", content=TEST_CONTENT
|
||||
)
|
||||
output = urlpath.article.render()
|
||||
print(output)
|
||||
|
||||
def get_section_content(self, response):
|
||||
# extract actual section content from response (editor)
|
||||
m = re.search(
|
||||
r"<textarea[^>]+>(?P<content>[^<]+)</textarea>",
|
||||
response.rendered_content,
|
||||
re.DOTALL,
|
||||
)
|
||||
if m:
|
||||
return m.group("content")
|
||||
else:
|
||||
return ""
|
||||
|
||||
def test_sourceblock_with_comment(self):
|
||||
# https://github.com/django-wiki/django-wiki/issues/1246
|
||||
URLPath.create_urlpath(
|
||||
URLPath.root(),
|
||||
"testedit_src",
|
||||
title="TestEditSourceComment",
|
||||
content=TEST_CONTENT_SRC_COMMENT,
|
||||
)
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit_src/", "header": "wiki-toc-section-2"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
actual = self.get_section_content(response)
|
||||
expected = "# Section 2\r\nSection 2 Lorem ipsum dolor sit amet\r\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_nonunique_headers(self):
|
||||
"""test whether non-unique headers will be handled properly"""
|
||||
source = """# Investigation 1\n\n## Date\n2023-01-01\n\n# Investigation 2\n\n## Date\n2023-01-02"""
|
||||
URLPath.create_urlpath(
|
||||
URLPath.root(),
|
||||
"testedit_src",
|
||||
title="TestEditSourceComment",
|
||||
content=source,
|
||||
)
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit_src/", "header": "wiki-toc-date"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
actual = self.get_section_content(response)
|
||||
expected = "## Date\r\n2023-01-01\r\n\r\n"
|
||||
|
||||
self.assertEqual(actual, expected)
|
||||
url = reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit_src/", "header": "wiki-toc-date_1"},
|
||||
)
|
||||
response = self.client.get(url)
|
||||
actual = self.get_section_content(response)
|
||||
expected = "## Date\r\n2023-01-02"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_underscore_and_dot(self):
|
||||
"""test whether we can handle non-slug characters like dots in header IDs"""
|
||||
# Explanation: While autogenerated ids are slugified, Markdown allows to manually
|
||||
# specify the ID using the {#custom_id_value} syntax. As HTML5 only requires ID
|
||||
# values not to contain whitespace, we should be able to handle any valid HTML5 ID, too.
|
||||
source = """# Title 1 {#some_id_with.dot}\n\n"""
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "testedit", title="TestEdit", content=source
|
||||
)
|
||||
# rendering causes NoReverseMatch without the fix
|
||||
actual = urlpath.article.render()
|
||||
expected = '<h1 id="some_id_with.dot">Title 1<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/some_id_with.dot/">[edit]</a></h1>'
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
|
||||
class EditSectionEditBase(RequireRootArticleMixin, FuncBaseMixin):
|
||||
pass
|
||||
|
||||
|
||||
class EditSectionEditTests(EditSectionEditBase, WebTestBase):
|
||||
# Test editing a section
|
||||
def test_editsection_edit(self):
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "testedit", title="TestEdit", content=TEST_CONTENT
|
||||
)
|
||||
old_number = urlpath.article.current_revision.revision_number
|
||||
|
||||
self.get_literal_url(
|
||||
reverse(
|
||||
"wiki:editsection",
|
||||
kwargs={"path": "testedit/", "header": "wiki-toc-title-3"},
|
||||
)
|
||||
)
|
||||
self.fill({"#id_content": "# Header 1\nContent of the new section"})
|
||||
self.submit("#id_save")
|
||||
expected = (
|
||||
r"(?s)"
|
||||
r'Title 1<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-1/">\[edit\]</a>.*'
|
||||
r'Title 2<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-2/">\[edit\]</a>.*'
|
||||
r'Header 1<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-header-1/">\[edit\]</a>.*'
|
||||
r"Content of the new section.*"
|
||||
r'Title 5<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-5/">\[edit\]</a>.*'
|
||||
r'Title 6<a class="article-edit-title-link" href="/testedit/_plugin/editsection/header/wiki-toc-title-6/">\[edit\]</a>.*'
|
||||
)
|
||||
self.assertRegex(self.last_response.content.decode("utf-8"), expected)
|
||||
|
||||
new_number = URLPath.objects.get(
|
||||
slug="testedit"
|
||||
).article.current_revision.revision_number
|
||||
self.assertEqual(new_number, old_number + 1)
|
||||
0
tests/plugins/globalhistory/__init__.py
Normal file
0
tests/plugins/globalhistory/__init__.py
Normal file
99
tests/plugins/globalhistory/test_globalhistory.py
Normal file
99
tests/plugins/globalhistory/test_globalhistory.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from django.urls import reverse
|
||||
from django.utils import translation
|
||||
from wiki.models import URLPath
|
||||
|
||||
from ...base import ArticleWebTestUtils
|
||||
from ...base import DjangoClientTestBase
|
||||
from ...base import RequireRootArticleMixin
|
||||
|
||||
|
||||
class GlobalhistoryTests(
|
||||
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
|
||||
):
|
||||
def test_history(self):
|
||||
url = reverse("wiki:globalhistory")
|
||||
url0 = reverse("wiki:globalhistory", kwargs={"only_last": "0"})
|
||||
url1 = reverse("wiki:globalhistory", kwargs={"only_last": "1"})
|
||||
|
||||
response = self.client.get(url)
|
||||
expected = "(?s).*Root Article.*no log message.*"
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
URLPath.create_urlpath(
|
||||
URLPath.root(),
|
||||
"testhistory1",
|
||||
title="TestHistory1",
|
||||
content="a page",
|
||||
user_message="Comment 1",
|
||||
)
|
||||
response = self.client.get(url)
|
||||
expected = (
|
||||
"(?s).*TestHistory1.*Comment 1.*" "Root Article.*no log message.*"
|
||||
)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(),
|
||||
"testhistory2",
|
||||
title="TestHistory2",
|
||||
content="a page",
|
||||
user_message="Comment 2",
|
||||
)
|
||||
expected = (
|
||||
"(?s).*TestHistory2.*Comment 2.*"
|
||||
"TestHistory1.*Comment 1.*"
|
||||
"Root Article.*no log message.*"
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
response = self.client.get(url0)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
response = self.client.get(url1)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("wiki:edit", kwargs={"path": "testhistory2/"}),
|
||||
{
|
||||
"content": "a page modified",
|
||||
"current_revision": str(urlpath.article.current_revision.id),
|
||||
"preview": "0",
|
||||
"save": "1",
|
||||
"summary": "Testing Revision",
|
||||
"title": "TestHistory2Mod",
|
||||
},
|
||||
)
|
||||
|
||||
expected = (
|
||||
"(?s).*TestHistory2Mod.*Testing Revision.*"
|
||||
"TestHistory2.*Comment 2.*"
|
||||
"TestHistory1.*Comment 1.*"
|
||||
"Root Article.*no log message.*"
|
||||
)
|
||||
response = self.client.get(url)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
response = self.client.get(url0)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
expected = (
|
||||
"(?s).*TestHistory2Mod.*Testing Revision.*"
|
||||
"TestHistory1.*Comment 1.*"
|
||||
"Root Article.*no log message.*"
|
||||
)
|
||||
response = self.client.get(url1)
|
||||
self.assertRegex(response.rendered_content, expected)
|
||||
|
||||
def test_translation(self):
|
||||
# Test that translation of "List of %s changes in the wiki." exists.
|
||||
url = reverse("wiki:globalhistory")
|
||||
response_en = self.client.get(url)
|
||||
self.assertIn("Global history", response_en.rendered_content)
|
||||
self.assertIn("in the wiki", response_en.rendered_content)
|
||||
|
||||
with translation.override("da-DK"):
|
||||
response_da = self.client.get(url)
|
||||
|
||||
self.assertNotIn("Global history", response_da.rendered_content)
|
||||
self.assertNotIn("in the wiki", response_da.rendered_content)
|
||||
0
tests/plugins/images/__init__.py
Normal file
0
tests/plugins/images/__init__.py
Normal file
16
tests/plugins/images/test_forms.py
Normal file
16
tests/plugins/images/test_forms.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from django.test import TestCase
|
||||
from django.utils.translation import gettext
|
||||
from wiki.plugins.images.forms import PurgeForm
|
||||
|
||||
|
||||
class PurgeFormTest(TestCase):
|
||||
def test_not_sure(self):
|
||||
form = PurgeForm(data={"confirm": False})
|
||||
self.assertIs(form.is_valid(), False)
|
||||
self.assertEqual(
|
||||
form.errors["confirm"], [gettext("You are not sure enough!")]
|
||||
)
|
||||
|
||||
def test_sure(self):
|
||||
form = PurgeForm(data={"confirm": True})
|
||||
self.assertIs(form.is_valid(), True)
|
||||
93
tests/plugins/images/test_markdown.py
Normal file
93
tests/plugins/images/test_markdown.py
Normal file
@@ -0,0 +1,93 @@
|
||||
import base64
|
||||
from io import BytesIO
|
||||
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from wiki.core import markdown
|
||||
from wiki.plugins.images import models
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class ImageMarkdownTests(RequireRootArticleMixin, TestBase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.image_revision = models.ImageRevision(
|
||||
image=self._create_test_gif_file(), width=1, height=1
|
||||
)
|
||||
self.image = models.Image(article=self.root_article)
|
||||
self.image.add_revision(self.image_revision)
|
||||
self.assertEqual(1, self.image.id)
|
||||
|
||||
def _create_test_gif_file(self):
|
||||
# A black 1x1 gif
|
||||
str_base64 = "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="
|
||||
filename = "test.gif"
|
||||
data = base64.b64decode(str_base64)
|
||||
filedata = BytesIO(data)
|
||||
return InMemoryUploadedFile(
|
||||
filedata, None, filename, "image", len(data), None
|
||||
)
|
||||
|
||||
def test_before_and_after(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert(
|
||||
"before [image:%s align:left] after" % self.image.id
|
||||
)
|
||||
before_pos = md_text.index("before")
|
||||
figure_pos = md_text.index("<figure")
|
||||
after_pos = md_text.index("after")
|
||||
self.assertTrue(before_pos < figure_pos < after_pos)
|
||||
|
||||
def test_markdown(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert("[image:%s align:left]" % self.image.id)
|
||||
self.assertIn("<figure", md_text)
|
||||
self.assertNotIn("[image:%s align:left]" % self.image.id, md_text)
|
||||
md_text = md.convert(
|
||||
"image: [image:%s align:left]\nadasd" % self.image.id
|
||||
)
|
||||
self.assertIn("<figure", md_text)
|
||||
self.assertIn("<figcaption", md_text)
|
||||
md_text = md.convert(
|
||||
"image: [image:%s align:right size:medium]\nadasd" % self.image.id
|
||||
)
|
||||
self.assertIn("<figure", md_text)
|
||||
self.assertIn("<figcaption", md_text)
|
||||
md_text = md.convert(
|
||||
"image: [image:123 align:left size:medium]\nadasd"
|
||||
)
|
||||
self.assertIn("Image not found", md_text)
|
||||
self.assertIn("<figcaption", md_text)
|
||||
|
||||
def test_caption(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert(
|
||||
"[image:%s align:left]\n this is visual" % self.image.id
|
||||
)
|
||||
self.assertIn("<figure", md_text)
|
||||
self.assertRegex(
|
||||
md_text,
|
||||
r'<figcaption class="caption">\s*this is visual\s*</figcaption>',
|
||||
)
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert(
|
||||
"[image:%s align:left]\n this is visual\n second line"
|
||||
% self.image.id
|
||||
)
|
||||
self.assertIn("<figure", md_text)
|
||||
self.assertRegex(
|
||||
md_text,
|
||||
r'<figcaption class="caption">\s*this is visual\s*second line\s*</figcaption>',
|
||||
)
|
||||
|
||||
def check_escape(self, text_to_escape):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert("`%s`" % text_to_escape)
|
||||
self.assertNotIn("<figure", md_text)
|
||||
self.assertIn(text_to_escape, md_text)
|
||||
|
||||
def test_escape(self):
|
||||
self.check_escape("[image:%s align:left]" % self.image.id)
|
||||
self.check_escape("image tag: [image:%s]" % self.image.id)
|
||||
303
tests/plugins/images/test_views.py
Normal file
303
tests/plugins/images/test_views.py
Normal file
@@ -0,0 +1,303 @@
|
||||
import base64
|
||||
import os
|
||||
import re
|
||||
from io import BytesIO
|
||||
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.urls import reverse
|
||||
from PIL import Image
|
||||
from wiki.core.plugins import registry as plugin_registry
|
||||
from wiki.models import URLPath
|
||||
from wiki.plugins.images import models
|
||||
from wiki.plugins.images.wiki_plugin import ImagePlugin
|
||||
|
||||
from ...base import ArticleWebTestUtils
|
||||
from ...base import DjangoClientTestBase
|
||||
from ...base import RequireRootArticleMixin
|
||||
from ...base import wiki_override_settings
|
||||
|
||||
|
||||
class ImageTests(
|
||||
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
|
||||
):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.article = self.root_article
|
||||
# A black 1x1 gif
|
||||
self.test_data = "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs="
|
||||
|
||||
def _create_gif_filestream_from_base64(self, str_base64, **kwargs):
|
||||
"""
|
||||
Helper function to create filestream for upload.
|
||||
|
||||
Parameters :
|
||||
strData : str, test string data
|
||||
|
||||
Optional Arguments :
|
||||
filename : str, Defaults to 'test.txt'
|
||||
"""
|
||||
filename = kwargs.get("filename", "test.gif")
|
||||
data = base64.b64decode(str_base64)
|
||||
filedata = BytesIO(data)
|
||||
filestream = InMemoryUploadedFile(
|
||||
filedata, None, filename, "image", len(data), None
|
||||
)
|
||||
return filestream
|
||||
|
||||
def _create_test_image(self, path):
|
||||
# Get the form index
|
||||
plugin_index = -1
|
||||
for cnt, plugin_instance in enumerate(plugin_registry.get_sidebar()):
|
||||
if isinstance(plugin_instance, ImagePlugin):
|
||||
plugin_index = cnt
|
||||
break
|
||||
self.assertGreaterEqual(
|
||||
plugin_index, 0, msg="Image plugin not activated"
|
||||
)
|
||||
base_edit_url = reverse("wiki:edit", kwargs={"path": path})
|
||||
url = base_edit_url + f"?f=form{plugin_index:d}"
|
||||
filestream = self._create_gif_filestream_from_base64(self.test_data)
|
||||
response = self.client.post(
|
||||
url,
|
||||
{
|
||||
"unsaved_article_title": self.article.current_revision.title,
|
||||
"unsaved_article_content": self.article.current_revision.content,
|
||||
"image": filestream,
|
||||
"images_save": "1",
|
||||
},
|
||||
)
|
||||
self.assertRedirects(response, base_edit_url)
|
||||
|
||||
def test_index(self):
|
||||
url = reverse("wiki:images_index", kwargs={"path": ""})
|
||||
response = self.client.get(
|
||||
url,
|
||||
)
|
||||
self.assertContains(response, "Images")
|
||||
|
||||
def test_upload(self):
|
||||
"""
|
||||
Tests that simple file upload uploads correctly
|
||||
Uploading a file should preserve the original filename.
|
||||
Uploading should not modify file in any way.
|
||||
"""
|
||||
self._create_test_image("")
|
||||
# Check the object was created.
|
||||
image = models.Image.objects.get()
|
||||
image_revision = image.current_revision.imagerevision
|
||||
self.assertEqual(image_revision.get_filename(), "test.gif")
|
||||
self.assertEqual(
|
||||
image_revision.image.file.read(), base64.b64decode(self.test_data)
|
||||
)
|
||||
|
||||
def get_article(self, cont, image):
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(), "html_image", title="TestImage", content=cont
|
||||
)
|
||||
if image:
|
||||
self._create_test_image(urlpath.path)
|
||||
return urlpath.article.render()
|
||||
|
||||
def test_image_missing(self):
|
||||
output = self.get_article("[image:1]", False)
|
||||
expected = (
|
||||
'<figure class="thumbnail"><a href="">'
|
||||
'<div class="caption"><em>Image not found</em></div>'
|
||||
'</a><figcaption class="caption"></figcaption></figure>'
|
||||
)
|
||||
self.assertEqual(output, expected)
|
||||
|
||||
def test_image_default(self):
|
||||
output = self.get_article("[image:1]", True)
|
||||
image_rev = models.Image.objects.get().current_revision.imagerevision
|
||||
expected = re.compile(
|
||||
r'<figure class="thumbnail">'
|
||||
r'<a href="' + re.escape(image_rev.image.url) + '">'
|
||||
r'<img src="/?cache/.*\.jpg" alt="test\.gif">'
|
||||
r'</a><figcaption class="caption"></figcaption></figure>'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
def test_image_large_right(self):
|
||||
output = self.get_article("[image:1 align:right size:large]", True)
|
||||
image_rev = models.Image.objects.get().current_revision.imagerevision
|
||||
expected = re.compile(
|
||||
r'<figure class="thumbnail float-right">'
|
||||
r'<a href="' + re.escape(image_rev.image.url) + '">'
|
||||
r'<img src="/?cache/.*\.jpg" alt="test\.gif"></a>'
|
||||
r'<figcaption class="caption"></figcaption></figure>'
|
||||
)
|
||||
self.assertRegex(output, expected)
|
||||
|
||||
def test_image_orig(self):
|
||||
output = self.get_article("[image:1 size:orig]", True)
|
||||
image_rev = models.Image.objects.get().current_revision.imagerevision
|
||||
expected = (
|
||||
'<figure class="thumbnail">'
|
||||
'<a href="' + image_rev.image.url + '">'
|
||||
'<img src="' + image_rev.image.url + '" alt="test.gif"></a>'
|
||||
'<figcaption class="caption"></figcaption></figure>'
|
||||
)
|
||||
self.assertEqual(output, expected)
|
||||
|
||||
# https://gist.github.com/guillaumepiot/817a70706587da3bd862835c59ef584e
|
||||
def generate_photo_file(self):
|
||||
file = BytesIO()
|
||||
image = Image.new("RGBA", size=(100, 100), color=(155, 0, 0))
|
||||
image.save(file, "gif")
|
||||
file.name = "test.gif"
|
||||
file.seek(0)
|
||||
return file
|
||||
|
||||
def test_add_revision(self):
|
||||
self._create_test_image(path="")
|
||||
image = models.Image.objects.get()
|
||||
before_edit_rev = image.current_revision.revision_number
|
||||
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"wiki:images_add_revision",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
),
|
||||
data={"image": self.generate_photo_file()},
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:edit", kwargs={"path": ""})
|
||||
)
|
||||
image = models.Image.objects.get()
|
||||
self.assertEqual(models.Image.objects.count(), 1)
|
||||
self.assertEqual(
|
||||
image.current_revision.previous_revision.revision_number,
|
||||
before_edit_rev,
|
||||
)
|
||||
|
||||
def test_delete_restore_revision(self):
|
||||
self._create_test_image(path="")
|
||||
image = models.Image.objects.get()
|
||||
before_edit_rev = image.current_revision.revision_number
|
||||
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"wiki:images_delete",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
),
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:images_index", kwargs={"path": ""})
|
||||
)
|
||||
image = models.Image.objects.get()
|
||||
self.assertEqual(models.Image.objects.count(), 1)
|
||||
self.assertEqual(
|
||||
image.current_revision.previous_revision.revision_number,
|
||||
before_edit_rev,
|
||||
)
|
||||
self.assertIs(image.current_revision.deleted, True)
|
||||
|
||||
# RESTORE
|
||||
before_edit_rev = image.current_revision.revision_number
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"wiki:images_restore",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
),
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:images_index", kwargs={"path": ""})
|
||||
)
|
||||
image = models.Image.objects.get()
|
||||
self.assertEqual(models.Image.objects.count(), 1)
|
||||
self.assertEqual(
|
||||
image.current_revision.previous_revision.revision_number,
|
||||
before_edit_rev,
|
||||
)
|
||||
self.assertFalse(image.current_revision.deleted)
|
||||
|
||||
def test_purge(self):
|
||||
"""
|
||||
Tests that an image is really purged
|
||||
"""
|
||||
self._create_test_image(path="")
|
||||
image = models.Image.objects.get()
|
||||
image_revision = image.current_revision.imagerevision
|
||||
f_path = image_revision.image.file.name
|
||||
|
||||
self.assertIs(os.path.exists(f_path), True)
|
||||
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"wiki:images_purge",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
),
|
||||
data={"confirm": True},
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:images_index", kwargs={"path": ""})
|
||||
)
|
||||
self.assertEqual(models.Image.objects.count(), 0)
|
||||
self.assertIs(os.path.exists(f_path), False)
|
||||
|
||||
def test_add_revision_purge_image(self):
|
||||
"""
|
||||
Tests that an image with more than one revision is really purged
|
||||
"""
|
||||
# use another test to stage this one
|
||||
self.test_add_revision()
|
||||
|
||||
image = models.Image.objects.get()
|
||||
image_revision = image.current_revision.imagerevision
|
||||
f_path = image_revision.image.file.name
|
||||
|
||||
self.assertIs(os.path.exists(f_path), True)
|
||||
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"wiki:images_purge",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
),
|
||||
data={"confirm": True},
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, reverse("wiki:images_index", kwargs={"path": ""})
|
||||
)
|
||||
self.assertEqual(models.Image.objects.count(), 0)
|
||||
self.assertIs(os.path.exists(f_path), False)
|
||||
|
||||
@wiki_override_settings(ACCOUNT_HANDLING=True)
|
||||
def test_login_on_revision_add(self):
|
||||
self._create_test_image(path="")
|
||||
self.client.logout()
|
||||
image = models.Image.objects.get()
|
||||
url = reverse(
|
||||
"wiki:images_add_revision",
|
||||
kwargs={
|
||||
"article_id": self.root_article,
|
||||
"image_id": image.pk,
|
||||
"path": "",
|
||||
},
|
||||
)
|
||||
response = self.client.post(
|
||||
url, data={"image": self.generate_photo_file()}
|
||||
)
|
||||
self.assertRedirects(
|
||||
response, "{}?next={}".format(reverse("wiki:login"), url)
|
||||
)
|
||||
0
tests/plugins/links/__init__.py
Normal file
0
tests/plugins/links/__init__.py
Normal file
124
tests/plugins/links/test_links.py
Normal file
124
tests/plugins/links/test_links.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import markdown
|
||||
from ddt import data
|
||||
from ddt import ddt
|
||||
from ddt import unpack
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse_lazy
|
||||
from wiki.models import URLPath
|
||||
from wiki.plugins.links.mdx.djangowikilinks import WikiPathExtension
|
||||
|
||||
from tests.base import wiki_override_settings
|
||||
|
||||
FIXTURE_POSITIVE_MATCHES_TRAILING_SLASH = [
|
||||
(
|
||||
"[Français](wiki:/fr)",
|
||||
'<p><a class="wikipath linknotfound" href="/fr/">Français</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to an existing page
|
||||
"[Test link](wiki:/linktest)",
|
||||
'<p><a class="wikipath" href="/linktest/">Test link</a></p>',
|
||||
),
|
||||
(
|
||||
# Link with an empty fragment
|
||||
"[Test link](wiki:/linktest#)",
|
||||
'<p><a class="wikipath" href="/linktest/#/">Test link</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to a header in an existing page
|
||||
"[Test head](wiki:/linktest#wiki-toc-a-section)",
|
||||
'<p><a class="wikipath" href="/linktest/#wiki-toc-a-section/">Test head</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to a header in a non existing page
|
||||
"[Test head nonExist](wiki:/linktesterr#wiki-toc-a-section)",
|
||||
'<p><a class="wikipath linknotfound" href="/linktesterr#wiki-toc-a-section/">Test head nonExist</a></p>',
|
||||
),
|
||||
(
|
||||
# Invalid Wiki link: The default markdown link parser takes over
|
||||
"[Test head err](wiki:/linktest#wiki-toc-a-section#err)",
|
||||
'<p><a href="wiki:/linktest#wiki-toc-a-section#err">Test head err</a></p>',
|
||||
),
|
||||
]
|
||||
FIXTURE_POSITIVE_MATCHES_NO_TRAILING_SLASH = [
|
||||
(
|
||||
"[Français](wiki:/fr)",
|
||||
'<p><a class="wikipath linknotfound" href="/fr">Français</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to an existing page
|
||||
"[Test link](wiki:/linktest)",
|
||||
'<p><a class="wikipath" href="/linktest">Test link</a></p>',
|
||||
),
|
||||
(
|
||||
# Relative path
|
||||
"[Test link](wiki:linktest)",
|
||||
'<p><a class="wikipath" href="/linktest">Test link</a></p>',
|
||||
),
|
||||
(
|
||||
# Link with an empty fragment
|
||||
"[Test link](wiki:/linktest#)",
|
||||
'<p><a class="wikipath" href="/linktest/#">Test link</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to a header in an existing page
|
||||
"[Test head](wiki:/linktest#wiki-toc-a-section)",
|
||||
'<p><a class="wikipath" href="/linktest/#wiki-toc-a-section">Test head</a></p>',
|
||||
),
|
||||
(
|
||||
# Link to a header in a non existing page
|
||||
"[Test head nonExist](wiki:/linktesterr#wiki-toc-a-section)",
|
||||
'<p><a class="wikipath linknotfound" href="/linktesterr#wiki-toc-a-section">Test head nonExist</a></p>',
|
||||
),
|
||||
(
|
||||
# Invalid Wiki link: The default markdown link parser takes over
|
||||
"[Test head err](wiki:/linktest#wiki-toc-a-section#err)",
|
||||
'<p><a href="wiki:/linktest#wiki-toc-a-section#err">Test head err</a></p>',
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@ddt
|
||||
class WikiPathExtensionTests(TestCase):
|
||||
"""
|
||||
Test the wikilinks markdown plugin.
|
||||
I could not get it to work with `@pytest.mark.parametrize` so using `ddt` instead
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
config = (("base_url", reverse_lazy("wiki:get", kwargs={"path": ""})),)
|
||||
URLPath.create_root()
|
||||
urlpath = URLPath.create_urlpath(
|
||||
URLPath.root(),
|
||||
"linktest",
|
||||
title="LinkTest",
|
||||
content="A page\n#A section\nA line",
|
||||
user_message="Comment1",
|
||||
)
|
||||
# TODO: Use wiki.core.markdown.article_markdown
|
||||
self.md = markdown.Markdown(
|
||||
extensions=["extra", WikiPathExtension(config)]
|
||||
)
|
||||
self.md.article = urlpath.article
|
||||
|
||||
@wiki_override_settings(WIKI_WIKILINKS_TRAILING_SLASH=True)
|
||||
@data(*FIXTURE_POSITIVE_MATCHES_TRAILING_SLASH)
|
||||
@unpack
|
||||
def test_works_with_lazy_functions_slashes(
|
||||
self, markdown_input, expected_output
|
||||
):
|
||||
self.assertEqual(
|
||||
self.md.convert(markdown_input),
|
||||
expected_output,
|
||||
)
|
||||
|
||||
@wiki_override_settings(WIKI_WIKILINKS_TRAILING_SLASH=False)
|
||||
@data(*FIXTURE_POSITIVE_MATCHES_NO_TRAILING_SLASH)
|
||||
@unpack
|
||||
def test_works_with_lazy_functions_no_slashes(
|
||||
self, markdown_input, expected_output
|
||||
):
|
||||
self.assertEqual(
|
||||
self.md.convert(markdown_input),
|
||||
expected_output,
|
||||
)
|
||||
262
tests/plugins/links/test_urlize.py
Normal file
262
tests/plugins/links/test_urlize.py
Normal file
@@ -0,0 +1,262 @@
|
||||
import html
|
||||
|
||||
import markdown
|
||||
import pytest
|
||||
from wiki.plugins.links.mdx.urlize import makeExtension
|
||||
from wiki.plugins.links.mdx.urlize import UrlizeExtension
|
||||
|
||||
# Template accepts two strings - href value and link text value.
|
||||
EXPECTED_LINK_TEMPLATE = (
|
||||
'<a href="%s" rel="nofollow" target="_blank">'
|
||||
'<span class="fa fa-external-link-alt">'
|
||||
"</span>"
|
||||
"<span>"
|
||||
" %s"
|
||||
"</span>"
|
||||
"</a>"
|
||||
)
|
||||
|
||||
# Template accepts two strings - href value and link text value.
|
||||
EXPECTED_PARAGRAPH_TEMPLATE = "<p>%s</p>" % EXPECTED_LINK_TEMPLATE
|
||||
|
||||
|
||||
FIXTURE_POSITIVE_MATCHES = [
|
||||
# Test surrounding begin/end characters.
|
||||
(
|
||||
"(example.com)",
|
||||
"<p>("
|
||||
+ EXPECTED_LINK_TEMPLATE % ("http://example.com", "example.com")
|
||||
+ ")</p>",
|
||||
),
|
||||
(
|
||||
"<example.com>",
|
||||
"<p><"
|
||||
+ EXPECTED_LINK_TEMPLATE % ("http://example.com", "example.com")
|
||||
+ "></p>",
|
||||
),
|
||||
# Test protocol specification.
|
||||
(
|
||||
"http://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://example.com", "http://example.com"),
|
||||
),
|
||||
(
|
||||
"https://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("https://example.com", "https://example.com"),
|
||||
),
|
||||
(
|
||||
"ftp://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("ftp://example.com", "ftp://example.com"),
|
||||
),
|
||||
(
|
||||
"ftps://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("ftps://example.com", "ftps://example.com"),
|
||||
),
|
||||
(
|
||||
"example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE % ("http://example.com", "example.com"),
|
||||
),
|
||||
(
|
||||
"onion://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("onion://example.com", "onion://example.com"),
|
||||
),
|
||||
(
|
||||
"onion9+.-://example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("onion9+.-://example.com", "onion9+.-://example.com"),
|
||||
),
|
||||
# Test various supported host variations.
|
||||
(
|
||||
"10.10.1.1",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE % ("http://10.10.1.1", "10.10.1.1"),
|
||||
),
|
||||
(
|
||||
"1122:3344:5566:7788:9900:aabb:ccdd:eeff",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% (
|
||||
"http://1122:3344:5566:7788:9900:aabb:ccdd:eeff",
|
||||
"1122:3344:5566:7788:9900:aabb:ccdd:eeff",
|
||||
),
|
||||
),
|
||||
(
|
||||
"1122:3344:5566:7788:9900:AaBb:cCdD:EeFf",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% (
|
||||
"http://1122:3344:5566:7788:9900:AaBb:cCdD:EeFf",
|
||||
"1122:3344:5566:7788:9900:AaBb:cCdD:EeFf",
|
||||
),
|
||||
),
|
||||
("::1", EXPECTED_PARAGRAPH_TEMPLATE % ("http://::1", "::1")),
|
||||
("1::2:3", EXPECTED_PARAGRAPH_TEMPLATE % ("http://1::2:3", "1::2:3")),
|
||||
("1::", EXPECTED_PARAGRAPH_TEMPLATE % ("http://1::", "1::")),
|
||||
("::", EXPECTED_PARAGRAPH_TEMPLATE % ("http://::", "::")),
|
||||
(
|
||||
"example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE % ("http://example.com", "example.com"),
|
||||
),
|
||||
(
|
||||
"example.horse",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://example.horse", "example.horse"),
|
||||
),
|
||||
(
|
||||
"my.long.domain.example.com",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://my.long.domain.example.com", "my.long.domain.example.com"),
|
||||
),
|
||||
# Test port section.
|
||||
(
|
||||
"10.1.1.1:8000",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://10.1.1.1:8000", "10.1.1.1:8000"),
|
||||
),
|
||||
# Test trailing path specification.
|
||||
(
|
||||
"http://example.com/",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://example.com/", "http://example.com/"),
|
||||
),
|
||||
(
|
||||
"http://example.com/my/path",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% ("http://example.com/my/path", "http://example.com/my/path"),
|
||||
),
|
||||
(
|
||||
"http://example.com/my/path?param1=value1¶m2=value2",
|
||||
EXPECTED_PARAGRAPH_TEMPLATE
|
||||
% (
|
||||
"http://example.com/my/path?param1=value1&param2=value2",
|
||||
"http://example.com/my/path?param1=value1&param2=value2",
|
||||
),
|
||||
),
|
||||
# Link positioned somewhere within the text, but around whitespace boundary.
|
||||
(
|
||||
"This is link myhost.example.com",
|
||||
"<p>This is link "
|
||||
+ EXPECTED_LINK_TEMPLATE
|
||||
% ("http://myhost.example.com", "myhost.example.com")
|
||||
+ "</p>",
|
||||
),
|
||||
(
|
||||
"myhost.example.com is the link",
|
||||
"<p>"
|
||||
+ EXPECTED_LINK_TEMPLATE
|
||||
% ("http://myhost.example.com", "myhost.example.com")
|
||||
+ " is the link</p>",
|
||||
),
|
||||
(
|
||||
"I have best myhost.example.com link ever",
|
||||
"<p>I have best "
|
||||
+ EXPECTED_LINK_TEMPLATE
|
||||
% ("http://myhost.example.com", "myhost.example.com")
|
||||
+ " link ever</p>",
|
||||
),
|
||||
(
|
||||
"I have best\nmyhost.example.com link ever",
|
||||
"<p>I have best\n"
|
||||
+ EXPECTED_LINK_TEMPLATE
|
||||
% ("http://myhost.example.com", "myhost.example.com")
|
||||
+ " link ever</p>",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
FIXTURE_NEGATIVE_MATCHES = [
|
||||
# localhost as part of another word.
|
||||
("localhosts", "<p>localhosts</p>"),
|
||||
("localhost", "<p>localhost</p>"),
|
||||
("localhost:8000", "<p>localhost:8000</p>"),
|
||||
# Incomplete FQDNs.
|
||||
("example.", "<p>example.</p>"),
|
||||
(".example .com", "<p>.example .com</p>"),
|
||||
# Invalid FQDNs.
|
||||
("example-.com", "<p>example-.com</p>"),
|
||||
("-example.com", "<p>-example.com</p>"),
|
||||
("my.-example.com", "<p>my.-example.com</p>"),
|
||||
# Invalid IPv6 patterns.
|
||||
(
|
||||
"1:2:3:4:5:6:7:8:a", # Use :a, because using a number would match as optional port
|
||||
"<p>1:2:3:4:5:6:7:8:a</p>",
|
||||
),
|
||||
(
|
||||
"1::2::3",
|
||||
"<p>1::2::3</p>",
|
||||
),
|
||||
(
|
||||
"::::1",
|
||||
"<p>::::1</p>",
|
||||
),
|
||||
(
|
||||
"1::::",
|
||||
"<p>1::::</p>",
|
||||
),
|
||||
# Invalid IPv4 patterns.
|
||||
(
|
||||
"1.2.3.4.5",
|
||||
"<p>1.2.3.4.5</p>",
|
||||
),
|
||||
# Invalid protocols.
|
||||
(
|
||||
"9onion://example.com",
|
||||
"<p>9onion://example.com</p>",
|
||||
),
|
||||
(
|
||||
"-onion://example.com",
|
||||
"<p>-onion://example.com</p>",
|
||||
),
|
||||
(
|
||||
"+onion://example.com",
|
||||
"<p>+onion://example.com</p>",
|
||||
),
|
||||
(
|
||||
".onion://example.com",
|
||||
"<p>.onion://example.com</p>",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class TestUrlizeExtension:
|
||||
def setup_method(self):
|
||||
self.md = markdown.Markdown(extensions=[UrlizeExtension()])
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"markdown_text, expected_output", FIXTURE_POSITIVE_MATCHES
|
||||
)
|
||||
def test_positive_matches(self, markdown_text, expected_output):
|
||||
assert self.md.convert(markdown_text) == expected_output
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"markdown_text, expected_output", FIXTURE_NEGATIVE_MATCHES
|
||||
)
|
||||
def test_negative_matches(self, markdown_text, expected_output):
|
||||
assert self.md.convert(markdown_text) == expected_output
|
||||
|
||||
def test_url_with_non_matching_begin_and_end_ignored(self):
|
||||
assert self.md.convert("(example.com>") == "<p>%s</p>" % html.escape(
|
||||
"(example.com>"
|
||||
)
|
||||
assert self.md.convert("<example.com)") == "<p>%s</p>" % html.escape(
|
||||
"<example.com)"
|
||||
)
|
||||
assert self.md.convert("(example.com") == "<p>%s</p>" % html.escape(
|
||||
"(example.com"
|
||||
)
|
||||
assert self.md.convert("example.com)") == "<p>%s</p>" % html.escape(
|
||||
"example.com)"
|
||||
)
|
||||
assert self.md.convert("<example.com") == "<p>%s</p>" % html.escape(
|
||||
"<example.com"
|
||||
)
|
||||
assert self.md.convert("example.com>") == "<p>%s</p>" % html.escape(
|
||||
"example.com>"
|
||||
)
|
||||
|
||||
|
||||
def test_makeExtension_return_value():
|
||||
extension = makeExtension()
|
||||
|
||||
assert isinstance(extension, UrlizeExtension)
|
||||
0
tests/plugins/macros/__init__.py
Normal file
0
tests/plugins/macros/__init__.py
Normal file
14
tests/plugins/macros/test_links.py
Normal file
14
tests/plugins/macros/test_links.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from wiki.core import markdown
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class WikiLinksTests(RequireRootArticleMixin, TestBase):
|
||||
def test_wikilink(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert("[[Root Article]]")
|
||||
self.assertEqual(
|
||||
md_text,
|
||||
'<p><a class="wiki_wikilink wiki-broken" href="/Root_Article/">Root Article</a></p>',
|
||||
)
|
||||
18
tests/plugins/macros/test_macro.py
Normal file
18
tests/plugins/macros/test_macro.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from wiki.core import markdown
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class MacroTests(RequireRootArticleMixin, TestBase):
|
||||
def test_article_list(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert("[article_list depth:2]")
|
||||
self.assertIn("Nothing below this level", md_text)
|
||||
self.assertNotIn("[article_list depth:2]", md_text)
|
||||
|
||||
def test_escape(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
md_text = md.convert("`[article_list depth:2]`")
|
||||
self.assertNotIn("Nothing below this level", md_text)
|
||||
self.assertIn("[article_list depth:2]", md_text)
|
||||
345
tests/plugins/macros/test_toc.py
Normal file
345
tests/plugins/macros/test_toc.py
Normal file
@@ -0,0 +1,345 @@
|
||||
from django.test import TestCase
|
||||
from markdown import Markdown
|
||||
from wiki.core import markdown
|
||||
from wiki.plugins.macros.mdx.toc import WikiTocExtension
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class TocMacroTests(TestCase):
|
||||
maxDiff = None
|
||||
|
||||
def test_toc_renders_table_of_content(self):
|
||||
"""Verifies that the [TOC] wiki code renders a Table of Content"""
|
||||
md = Markdown(extensions=["extra", WikiTocExtension()])
|
||||
text = (
|
||||
"[TOC]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc">\n'
|
||||
"<ul>\n"
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.</h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection</h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_with_kwargs(self):
|
||||
"""Verifies that the [TOC] wiki code renders a Table of Content"""
|
||||
md = Markdown(extensions=["extra", WikiTocExtension(title="test")])
|
||||
text = (
|
||||
"[TOC]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">test</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.</h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection</h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
|
||||
class TocMacroTestsInWiki(RequireRootArticleMixin, TestBase):
|
||||
def test_toc_renders_table_of_content_in_wiki(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_with_toc_class(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC toc_class:'nontoc test']\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="nontoc test"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_with_kwargs(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC title:test]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">test</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_with_depth(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC toc_depth:1]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_with_multi_kwargs(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC title:'test' toc_depth:'1' anchorlink:'True']\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">test</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title"><a class="toclink" '
|
||||
'href="#wiki-toc-first-title">First title.</a><a '
|
||||
'class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection"><a class="toclink" '
|
||||
'href="#wiki-toc-subsection">Subsection</a><a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_wrong_type(self):
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC anchorlink:Yes]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_test_bool_one(self):
|
||||
# Test if the integer is 1 and should be True
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC anchorlink:1]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title"><a class="toclink" '
|
||||
'href="#wiki-toc-first-title">First title.</a><a '
|
||||
'class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection"><a class="toclink" '
|
||||
'href="#wiki-toc-subsection">Subsection</a><a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_test_bool_zero(self):
|
||||
# Test if the integer is zero and should be false
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC anchorlink:0]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
|
||||
def test_toc_renders_table_of_content_in_wiki_test_bool_wrong(self):
|
||||
# Test if the integer is wrong value
|
||||
md = markdown.ArticleMarkdown(article=self.root_article)
|
||||
text = (
|
||||
"[TOC anchorlink:5]\n"
|
||||
"\n"
|
||||
"# First title.\n"
|
||||
"\n"
|
||||
"Paragraph 1\n"
|
||||
"\n"
|
||||
"## Subsection\n"
|
||||
"\n"
|
||||
"Paragraph 2"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="toc"><span class="toctitle">Contents</span><ul>\n'
|
||||
'<li><a href="#wiki-toc-first-title">First title.</a><ul>\n'
|
||||
'<li><a href="#wiki-toc-subsection">Subsection</a></li>\n'
|
||||
"</ul>\n"
|
||||
"</li>\n"
|
||||
"</ul>\n"
|
||||
"</div>\n"
|
||||
'<h1 id="wiki-toc-first-title">First title.<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-first-title/">[edit]</a></h1>\n'
|
||||
"<p>Paragraph 1</p>\n"
|
||||
'<h2 id="wiki-toc-subsection">Subsection<a class="article-edit-title-link" '
|
||||
'href="/_plugin/editsection/header/wiki-toc-subsection/">[edit]</a></h2>\n'
|
||||
"<p>Paragraph 2</p>"
|
||||
)
|
||||
self.assertEqual(md.convert(text), expected_output)
|
||||
0
tests/plugins/notifications/__init__.py
Normal file
0
tests/plugins/notifications/__init__.py
Normal file
9
tests/plugins/notifications/test_forms.py
Normal file
9
tests/plugins/notifications/test_forms.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.test import TestCase
|
||||
from wiki.plugins.notifications.forms import SettingsFormSet
|
||||
|
||||
from tests.base import RequireSuperuserMixin
|
||||
|
||||
|
||||
class SettingsFormTests(RequireSuperuserMixin, TestCase):
|
||||
def test_formset(self):
|
||||
SettingsFormSet(user=self.superuser1)
|
||||
76
tests/plugins/notifications/test_views.py
Normal file
76
tests/plugins/notifications/test_views.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from django.shortcuts import resolve_url
|
||||
from django_nyt.models import Settings
|
||||
|
||||
from tests.base import ArticleWebTestUtils
|
||||
from tests.base import DjangoClientTestBase
|
||||
from tests.base import RequireRootArticleMixin
|
||||
|
||||
|
||||
class NotificationSettingsTests(
|
||||
RequireRootArticleMixin, ArticleWebTestUtils, DjangoClientTestBase
|
||||
):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_login_required(self):
|
||||
self.client.logout()
|
||||
response = self.client.get(resolve_url("wiki:notification_settings"))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_when_logged_in(self):
|
||||
response = self.client.get(resolve_url("wiki:notification_settings"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
response, "wiki/plugins/notifications/settings.html"
|
||||
)
|
||||
|
||||
def test_change_settings(self):
|
||||
self.settings, __ = Settings.objects.get_or_create(
|
||||
user=self.superuser1, is_default=True
|
||||
)
|
||||
|
||||
url = resolve_url("wiki:notification_settings")
|
||||
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = {"csrf_token": response.context["csrf_token"]}
|
||||
|
||||
# management form information, needed because of the formset
|
||||
management_form = response.context["form"].management_form
|
||||
|
||||
for i in (
|
||||
"TOTAL_FORMS",
|
||||
"INITIAL_FORMS",
|
||||
"MIN_NUM_FORMS",
|
||||
"MAX_NUM_FORMS",
|
||||
):
|
||||
data[f"{management_form.prefix}-{i}"] = management_form[i].value()
|
||||
|
||||
for i in range(response.context["form"].total_form_count()):
|
||||
# get form index 'i'
|
||||
current_form = response.context["form"].forms[i]
|
||||
|
||||
# retrieve all the fields
|
||||
for field_name in current_form.fields:
|
||||
value = current_form[field_name].value()
|
||||
data[f"{current_form.prefix}-{field_name}"] = (
|
||||
value if value is not None else ""
|
||||
)
|
||||
|
||||
data["form-TOTAL_FORMS"] = 1
|
||||
data["form-0-email"] = 2
|
||||
data["form-0-interval"] = 0
|
||||
# post the request without any change
|
||||
|
||||
response = self.client.post(url, data, follow=True)
|
||||
|
||||
self.assertEqual(len(response.context.get("messages")), 1)
|
||||
|
||||
message = response.context.get("messages")._loaded_messages[0]
|
||||
self.assertIn(
|
||||
message.message,
|
||||
"You will receive notifications instantly for 0 articles",
|
||||
)
|
||||
|
||||
# Ensure we didn't create redundant Settings objects
|
||||
assert self.superuser1.nyt_settings.all().count() == 1
|
||||
0
tests/plugins/pymdown/__init__.py
Normal file
0
tests/plugins/pymdown/__init__.py
Normal file
339
tests/plugins/pymdown/test_pymdown.py
Normal file
339
tests/plugins/pymdown/test_pymdown.py
Normal file
@@ -0,0 +1,339 @@
|
||||
from django.test import TestCase
|
||||
from markdown import Markdown
|
||||
from wiki.core import markdown
|
||||
from wiki.plugins.pymdown import wiki_plugin
|
||||
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class TocMacroTests(TestCase):
|
||||
"""
|
||||
This is used to test the PyMdown extensions module independently of Django Wiki. If this fails
|
||||
it should because something has changed on with PyMdown or Markdown itself.
|
||||
"""
|
||||
|
||||
def test_pymdown_renders_block_details(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = "/// details | Some summary\n" "\n" "Some content\b" "///\n"
|
||||
expected_output = (
|
||||
"<details>\n"
|
||||
"<summary>Some summary</summary>\n"
|
||||
"<p>Some content\x08///</p>\n"
|
||||
"</details>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_details_with_type(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// details | Some summary\n"
|
||||
" type: warning\n"
|
||||
"\n"
|
||||
"Some content\b"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
'<details class="warning">\n'
|
||||
"<summary>Some summary</summary>\n"
|
||||
"<p>Some content\x08///</p>\n"
|
||||
"</details>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_admonition(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = "/// admonition | Some summary\n" "Some content\b" "///\n"
|
||||
expected_output = (
|
||||
'<div class="admonition">\n'
|
||||
'<p class="admonition-title">Some summary</p>\n'
|
||||
"<p>Some content\x08///</p>\n"
|
||||
"</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_admonition_with_type(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// admonition | Some summary\n"
|
||||
" type: warning\n"
|
||||
"Some content\b"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="admonition warning">\n'
|
||||
'<p class="admonition-title">Some summary</p>\n'
|
||||
"<p>Some content\x08///</p>\n"
|
||||
"</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_definition(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Apple\n"
|
||||
"\n"
|
||||
"- Pomaceous fruit of plants of the genus Malu in the family Rosaceae.\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Apple</dt>\n"
|
||||
"<dd>Pomaceous fruit of plants of the genus Malu in the family "
|
||||
"Rosaceae.</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_definition_multiples(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Apple\n"
|
||||
"\n"
|
||||
"- Pomaceous fruit of plants of the genus Malu in the family Rosaceae.\n"
|
||||
"\n"
|
||||
"Orange\n"
|
||||
"\n"
|
||||
"- The fruit of an evergreen tree of hte genus Citrus.\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Apple</dt>\n"
|
||||
"<dd>Pomaceous fruit of plants of the genus Malu in the family "
|
||||
"Rosaceae.</dd>\n"
|
||||
"<dt>Orange</dt>\n"
|
||||
"<dd>The fruit of an evergreen tree of hte genus Citrus.</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_definition_multiple_terms(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Term 1\n"
|
||||
"\n"
|
||||
"Term 2\n"
|
||||
"- Definition a\n"
|
||||
"\n"
|
||||
"Term 3\n"
|
||||
"\n"
|
||||
"- Definition b\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Term 1</dt>\n"
|
||||
"<dt>Term 2\n"
|
||||
"- Definition a</dt>\n"
|
||||
"<dt>Term 3</dt>\n"
|
||||
"<dd>Definition b</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_renders_block_html_wrap(self):
|
||||
extensions = ["extra"]
|
||||
extensions.extend(wiki_plugin.PymdownPlugin.markdown_extensions)
|
||||
md = Markdown(extensions=extensions)
|
||||
text = (
|
||||
"/// html | div[stype='border: 1px solid red;']\n"
|
||||
"some *markdown* content\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
'<div stype="border: 1px solid red;">\n'
|
||||
"<p>some <em>markdown</em> content</p>\n"
|
||||
"</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
|
||||
class TocMacroTestsInWiki(RequireRootArticleMixin, TestBase):
|
||||
def test_pymdown_in_wiki_renders_block_details(self):
|
||||
wiki_plugin.settings.update_whitelist() # Fixes testing bug
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = "/// details | Some summary\n" "\n" "Some content\n" "///\n"
|
||||
expected_output = (
|
||||
"<details>\n"
|
||||
"<summary>Some summary</summary>\n"
|
||||
"<p>Some content</p>\n"
|
||||
"</details>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_details_with_type(self):
|
||||
wiki_plugin.settings.update_whitelist() # Fixes testing bug
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// details | Some summary\n"
|
||||
" type: warning\n"
|
||||
"Some content\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
'<details class="warning">\n'
|
||||
"<summary>Some summary</summary>\n"
|
||||
"<p>Some content</p>\n"
|
||||
"</details>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_admonition(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = "/// admonition | Some summary\n" "Some content.\n" "///\n"
|
||||
expected_output = (
|
||||
'<div class="admonition">\n'
|
||||
'<p class="admonition-title">Some summary</p>\n'
|
||||
"<p>Some content.</p>\n"
|
||||
"</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_admonition_with_type(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// admonition | Some summary\n"
|
||||
" type: warning\n"
|
||||
"Some content.\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
'<div class="admonition warning">\n'
|
||||
'<p class="admonition-title">Some summary</p>\n'
|
||||
"<p>Some content.</p>\n"
|
||||
"</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_definition(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Apple\n"
|
||||
"\n"
|
||||
"- Pomaceous fruit of plants of the genus Malu in the family Rosaceae.\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Apple</dt>\n"
|
||||
"<dd>Pomaceous fruit of plants of the genus Malu in the family "
|
||||
"Rosaceae.</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_definition_multiples(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Apple\n"
|
||||
"\n"
|
||||
"- Pomaceous fruit of plants of the genus Malu in the family Rosaceae.\n"
|
||||
"\n"
|
||||
"Orange\n"
|
||||
"\n"
|
||||
"- The fruit of an evergreen tree of hte genus Citrus.\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Apple</dt>\n"
|
||||
"<dd>Pomaceous fruit of plants of the genus Malu in the family "
|
||||
"Rosaceae.</dd>\n"
|
||||
"<dt>Orange</dt>\n"
|
||||
"<dd>The fruit of an evergreen tree of hte genus Citrus.</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_definition_multiple_terms(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// define\n"
|
||||
"Term 1\n"
|
||||
"\n"
|
||||
"Term 2\n"
|
||||
"- Definition a\n"
|
||||
"\n"
|
||||
"Term 3\n"
|
||||
"\n"
|
||||
"- Definition b\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<dl>\n"
|
||||
"<dt>Term 1</dt>\n"
|
||||
"<dt>Term 2\n"
|
||||
"- Definition a</dt>\n"
|
||||
"<dt>Term 3</dt>\n"
|
||||
"<dd>Definition b</dd>\n"
|
||||
"</dl>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_html_wrap(self):
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = "/// html | div.my-class\n" "some *markdown* content\n" "///\n"
|
||||
expected_output = '<div class="my-class">\n<p>some <em>markdown</em> content</p>\n</div>'
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
|
||||
def test_pymdown_in_wiki_renders_block_html_wrap_test_bleach(self):
|
||||
"""
|
||||
The tags get bleached and thus this doesn't work.
|
||||
"""
|
||||
md = markdown.ArticleMarkdown(
|
||||
article=self.root_article,
|
||||
extensions=wiki_plugin.PymdownPlugin.markdown_extensions,
|
||||
)
|
||||
text = (
|
||||
"/// html | div[stype='border: 1px solid red;']\n"
|
||||
"some *markdown* content\n"
|
||||
"///\n"
|
||||
)
|
||||
expected_output = (
|
||||
"<div>\n<p>some <em>markdown</em> content</p>\n</div>"
|
||||
)
|
||||
self.assertEqual(expected_output, md.convert(text))
|
||||
0
tests/plugins/redlinks/__init__.py
Normal file
0
tests/plugins/redlinks/__init__.py
Normal file
97
tests/plugins/redlinks/test_redlinks.py
Normal file
97
tests/plugins/redlinks/test_redlinks.py
Normal file
@@ -0,0 +1,97 @@
|
||||
from django.urls import reverse
|
||||
from wiki.core import markdown
|
||||
from wiki.models import URLPath
|
||||
|
||||
from ...base import wiki_override_settings
|
||||
from tests.base import RequireRootArticleMixin
|
||||
from tests.base import TestBase
|
||||
|
||||
|
||||
class RedlinksTests(RequireRootArticleMixin, TestBase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.child = URLPath.create_urlpath(self.root, "child")
|
||||
|
||||
def test_root_to_self(self):
|
||||
self.assert_internal(self.root, "[Internal](./)")
|
||||
|
||||
def test_root_to_child(self):
|
||||
self.assert_internal(self.root, "[Child](child/)")
|
||||
|
||||
def test_child_to_self(self):
|
||||
self.assert_internal(self.child, "[Child](../child/)")
|
||||
|
||||
def test_child_to_self_no_slash(self):
|
||||
self.assert_internal(self.child, "[Child](../child)")
|
||||
|
||||
def test_root_to_outside(self):
|
||||
self.assert_external(
|
||||
self.root, "[Outside](http://outside.example.org/)"
|
||||
)
|
||||
|
||||
def test_absolute_external(self):
|
||||
if reverse("wiki:get", kwargs={"path": ""}) == "/":
|
||||
# All absolute paths could be wiki-internal, and the server root is
|
||||
# the the wiki root, which is bound to exist.
|
||||
self.assert_internal(self.root, "[Server Root](/)")
|
||||
else:
|
||||
# The wiki root is below the server root, so the server root is an
|
||||
# external link.
|
||||
self.assert_external(self.root, "[Server Root](/)")
|
||||
self.assert_external(self.root, "[Static File](/static/)")
|
||||
|
||||
def test_absolute_internal(self):
|
||||
wiki_root = reverse("wiki:get", kwargs={"path": ""})
|
||||
self.assert_internal(self.root, f"[Server Root]({wiki_root})")
|
||||
|
||||
def test_child_to_broken(self):
|
||||
self.assert_broken(self.child, "[Broken](../broken/)")
|
||||
|
||||
def test_root_to_broken(self):
|
||||
self.assert_broken(self.root, "[Broken](broken/)")
|
||||
|
||||
def test_not_a_link(self):
|
||||
self.assert_none(self.root, '<a id="anchor">old-style anchor</a>')
|
||||
|
||||
def test_invalid_url(self):
|
||||
self.assert_none(self.root, "[Invalid](http://127[.500.20.1/)")
|
||||
|
||||
def test_mailto(self):
|
||||
self.assert_none(self.root, "<foo@example.com>")
|
||||
|
||||
def assert_none(self, urlpath, md_text):
|
||||
md = markdown.ArticleMarkdown(article=urlpath.article)
|
||||
html = md.convert(md_text)
|
||||
self.assertNotIn("wiki-internal", html)
|
||||
self.assertNotIn("wiki-external", html)
|
||||
self.assertNotIn("wiki-broken", html)
|
||||
self.assertIn("<a", html)
|
||||
|
||||
def assert_internal(self, urlpath, md_text):
|
||||
md = markdown.ArticleMarkdown(article=urlpath.article)
|
||||
html = md.convert(md_text)
|
||||
self.assertIn("wiki-internal", html)
|
||||
self.assertNotIn("wiki-external", html)
|
||||
self.assertNotIn("wiki-broken", html)
|
||||
|
||||
def assert_external(self, urlpath, md_text):
|
||||
md = markdown.ArticleMarkdown(article=urlpath.article)
|
||||
html = md.convert(md_text)
|
||||
self.assertNotIn("wiki-internal", html)
|
||||
self.assertIn("wiki-external", html)
|
||||
self.assertNotIn("wiki-broken", html)
|
||||
|
||||
def assert_broken(self, urlpath, md_text):
|
||||
md = markdown.ArticleMarkdown(article=urlpath.article)
|
||||
html = md.convert(md_text)
|
||||
self.assertNotIn("wiki-internal", html)
|
||||
self.assertNotIn("wiki-external", html)
|
||||
self.assertIn("wiki-broken", html)
|
||||
|
||||
|
||||
@wiki_override_settings(
|
||||
WIKI_URL_CONFIG_CLASS="tests.core.test_models.WikiCustomUrlPatterns",
|
||||
ROOT_URLCONF="tests.core.test_urls",
|
||||
)
|
||||
class RedLinksWithChangedBaseURL(RedlinksTests):
|
||||
pass
|
||||
Reference in New Issue
Block a user