Adding some tests and a improved version of the wikilinks extension

remotes/origin/enhancement/email-actions
Jesús Espino 2014-05-16 12:22:02 +02:00
parent 06170b868f
commit be5e37187c
5 changed files with 131 additions and 31 deletions

View File

@ -8,6 +8,7 @@ from . import hidden_hilite
from . import semi_sane_lists from . import semi_sane_lists
from . import spaced_link from . import spaced_link
from . import strikethrough from . import strikethrough
from . import wikilinks
AutolinkExtension = autolink.AutolinkExtension AutolinkExtension = autolink.AutolinkExtension
AutomailExtension = automail.AutomailExtension AutomailExtension = automail.AutomailExtension
@ -15,3 +16,4 @@ HiddenHiliteExtension = hidden_hilite.HiddenHiliteExtension
SemiSaneListExtension = semi_sane_lists.SemiSaneListExtension SemiSaneListExtension = semi_sane_lists.SemiSaneListExtension
SpacedLinkExtension = spaced_link.SpacedLinkExtension SpacedLinkExtension = spaced_link.SpacedLinkExtension
StrikethroughExtension = strikethrough.StrikethroughExtension StrikethroughExtension = strikethrough.StrikethroughExtension
WikiLinkExtension = wikilinks.WikiLinkExtension

View File

@ -0,0 +1,79 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from markdown import Extension
from markdown.inlinepatterns import Pattern
from markdown.util import etree
import re
def build_url(label, base, end):
""" Build a url from the label, a base, and an end. """
clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label)
return '%s%s%s'% (base, clean_label, end)
class WikiLinkExtension(Extension):
def __init__(self, configs):
# set extension defaults
self.config = {
'base_url' : ['/', 'String to append to beginning or URL.'],
'end_url' : ['/', 'String to append to end of URL.'],
'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
'build_url' : [build_url, 'Callable formats URL from label.'],
}
configs = dict(configs) or {}
# Override defaults with user settings
for key, value in configs.items():
self.setConfig(key, value)
def extendMarkdown(self, md, md_globals):
self.md = md
# append to end of inline patterns
WIKILINK_RE = r'\[\[([\w0-9_ -]+)(\|[\w0-9_ -]+)?\]\]'
wikilinkPattern = WikiLinks(WIKILINK_RE, self.getConfigs())
wikilinkPattern.md = md
md.inlinePatterns.add('wikilink', wikilinkPattern, "<not_strong")
class WikiLinks(Pattern):
def __init__(self, pattern, config):
super(WikiLinks, self).__init__(pattern)
self.config = config
def handleMatch(self, m):
if m.group(2).strip():
base_url, end_url, html_class = self._getMeta()
label = m.group(2).strip()
url = self.config['build_url'](label, base_url, end_url)
if m.group(3):
title = m.group(3).strip()[1:]
else:
title = label
a = etree.Element('a')
a.text = title
a.set('href', url)
if html_class:
a.set('class', html_class)
else:
a = ''
return a
def _getMeta(self):
""" Return meta data or config data. """
base_url = self.config['base_url']
end_url = self.config['end_url']
html_class = self.config['html_class']
if hasattr(self.md, 'Meta'):
if 'wiki_base_url' in self.md.Meta:
base_url = self.md.Meta['wiki_base_url'][0]
if 'wiki_end_url' in self.md.Meta:
end_url = self.md.Meta['wiki_end_url'][0]
if 'wiki_html_class' in self.md.Meta:
html_class = self.md.Meta['wiki_html_class'][0]
return base_url, end_url, html_class
def makeExtension(configs=None) :
return WikiLinkExtension(configs=configs)

View File

@ -5,7 +5,7 @@ from django.core.cache import cache
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from markdown import markdown from markdown import markdown
from markdown.extensions.wikilinks import WikiLinkExtension #from markdown.extensions.wikilinks import WikiLinkExtension
from fn import F from fn import F
from .gfm import AutolinkExtension from .gfm import AutolinkExtension
@ -14,6 +14,7 @@ from .gfm import HiddenHiliteExtension
from .gfm import SemiSaneListExtension from .gfm import SemiSaneListExtension
from .gfm import SpacedLinkExtension from .gfm import SpacedLinkExtension
from .gfm import StrikethroughExtension from .gfm import StrikethroughExtension
from .gfm import WikiLinkExtension
from .processors.emoji import emoji from .processors.emoji import emoji
from .processors.mentions import mentions from .processors.mentions import mentions

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

View File

@ -6,10 +6,15 @@ import taiga.base
from taiga.mdrender.processors import emoji from taiga.mdrender.processors import emoji
from taiga.mdrender.processors import mentions from taiga.mdrender.processors import mentions
from taiga.mdrender.processors import references from taiga.mdrender.processors import references
from taiga.mdrender.service import render
class DummyClass: class DummyClass:
pass pass
dummy_project = DummyClass()
dummy_project.id = 1
dummy_project.slug = "test"
def test_proccessor_valid_emoji(): def test_proccessor_valid_emoji():
result = emoji.emoji("<b>:smile:</b>") result = emoji.emoji("<b>:smile:</b>")
assert result == '<b><img class="emoji" title="smile" alt="smile" height="20" width="20" src="http://localhost:8000/static/img/emojis/smile.png" align="top"></b>' assert result == '<b><img class="emoji" title="smile" alt="smile" height="20" width="20" src="http://localhost:8000/static/img/emojis/smile.png" align="top"></b>'
@ -49,11 +54,7 @@ def test_proccessor_valid_us_reference():
UserStoryBack = references.UserStory UserStoryBack = references.UserStory
references.UserStory = MockModelWithInstance references.UserStory = MockModelWithInstance
DummyProject = DummyClass() result = references.references(dummy_project, "**#us1**")
DummyProject.id = 1
DummyProject.slug = "test"
result = references.references(DummyProject, "**#us1**")
assert result == '**[#us1](/#/project/test/user-story/1 "test-subject")**' assert result == '**[#us1](/#/project/test/user-story/1 "test-subject")**'
references.UserStory = UserStoryBack references.UserStory = UserStoryBack
@ -65,14 +66,10 @@ def test_proccessor_invalid_us_reference():
def filter(*args, **kwargs): def filter(*args, **kwargs):
return [] return []
DummyProject = DummyClass()
DummyProject.id = 1
DummyProject.slug = "test"
UserStoryBack = references.UserStory UserStoryBack = references.UserStory
references.UserStory = MockModelEmpty references.UserStory = MockModelEmpty
result = references.references(DummyProject, "**#us1**") result = references.references(dummy_project, "**#us1**")
assert result == "**#us1**" assert result == "**#us1**"
references.UserStory = UserStoryBack references.UserStory = UserStoryBack
@ -87,11 +84,7 @@ def test_proccessor_valid_issue_reference():
IssueBack = references.Issue IssueBack = references.Issue
references.Issue = MockModelWithInstance references.Issue = MockModelWithInstance
DummyProject = DummyClass() result = references.references(dummy_project, "**#issue1**")
DummyProject.id = 1
DummyProject.slug = "test"
result = references.references(DummyProject, "**#issue1**")
assert result == '**[#issue1](/#/project/test/issues/1 "test-subject")**' assert result == '**[#issue1](/#/project/test/issues/1 "test-subject")**'
references.Issue = IssueBack references.Issue = IssueBack
@ -103,14 +96,10 @@ def test_proccessor_invalid_issue_reference():
def filter(*args, **kwargs): def filter(*args, **kwargs):
return [] return []
DummyProject = DummyClass()
DummyProject.id = 1
DummyProject.slug = "test"
IssueBack = references.Issue IssueBack = references.Issue
references.Issue = MockModelEmpty references.Issue = MockModelEmpty
result = references.references(DummyProject, "**#issue1**") result = references.references(dummy_project, "**#issue1**")
assert result == "**#issue1**" assert result == "**#issue1**"
references.Issue = IssueBack references.Issue = IssueBack
@ -125,11 +114,7 @@ def test_proccessor_valid_task_reference():
TaskBack = references.Task TaskBack = references.Task
references.Task = MockModelWithInstance references.Task = MockModelWithInstance
DummyProject = DummyClass() result = references.references(dummy_project, "**#task1**")
DummyProject.id = 1
DummyProject.slug = "test"
result = references.references(DummyProject, "**#task1**")
assert result == '**[#task1](/#/project/test/tasks/1 "test-subject")**' assert result == '**[#task1](/#/project/test/tasks/1 "test-subject")**'
references.Task = TaskBack references.Task = TaskBack
@ -141,14 +126,10 @@ def test_proccessor_invalid_task_reference():
def filter(*args, **kwargs): def filter(*args, **kwargs):
return [] return []
DummyProject = DummyClass()
DummyProject.id = 1
DummyProject.slug = "test"
TaskBack = references.Task TaskBack = references.Task
references.Task = MockModelEmpty references.Task = MockModelEmpty
result = references.references(DummyProject, "**#task1**") result = references.references(dummy_project, "**#task1**")
assert result == "**#task1**" assert result == "**#task1**"
references.Task = TaskBack references.Task = TaskBack
@ -156,3 +137,40 @@ def test_proccessor_invalid_task_reference():
def test_proccessor_invalid_type_reference(): def test_proccessor_invalid_type_reference():
result = references.references(None, "**#invalid1**") result = references.references(None, "**#invalid1**")
assert result == "**#invalid1**" assert result == "**#invalid1**"
def test_render_wiki_strong():
assert render(dummy_project, "**test**") == "<p><strong>test</strong></p>"
def test_render_absolute_link():
assert render(dummy_project, "[test](/test)") == "<p><a href=\"/test\">test</a></p>"
def test_render_relative_link():
assert render(dummy_project, "[test](test)") == "<p><a href=\"test\">test</a></p>"
def test_render_wikilink():
expected_result = "<p><a class=\"wikilink\" href=\"#/project/test/wiki/test\">test</a></p>"
assert render(dummy_project, "[[test]]") == expected_result
def test_render_wikilink_with_custom_title():
expected_result = "<p><a class=\"wikilink\" href=\"#/project/test/wiki/test\">custom</a></p>"
assert render(dummy_project, "[[test|custom]]") == expected_result
def test_render_absolute_image():
assert render(dummy_project, "![test](/test.png)") == "<p><img alt=\"test\" src=\"/test.png\" /></p>"
def test_render_relative_image():
assert render(dummy_project, "![test](test.png)") == "<p><img alt=\"test\" src=\"test.png\" /></p>"
# def test_render_wikilink_attachment():
# assert render(dummy_project, "![[test.png]]") == "<p><img alt=\"test.png\" src=\"test.png\" /></p>"
#
# def test_render_wikilink_attachment_with_custom_alt():
# assert render(dummy_project, "![[test.png|test]]") == "<p><img alt=\"test\" src=\"test.png\" /></p>"
def test_render_triple_quote_code():
expected_result = "<div class=\"codehilite\"><pre><span class=\"n\">print</span><span class=\"p\">(</span><span class=\"s\">&quot;test&quot;</span><span class=\"p\">)</span>\n</pre></div>"
assert render(dummy_project, "```\nprint(\"test\")\n```") == expected_result
def test_render_triple_quote_and_lang_code():
expected_result = "<div class=\"codehilite\"><pre><span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s\">&quot;test&quot;</span><span class=\"p\">)</span>\n</pre></div>"
assert render(dummy_project, "```python\nprint(\"test\")\n```") == expected_result