aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/__init__.py44
-rw-r--r--tests/base.py62
-rw-r--r--tests/extensions-x-abbr/test.cfg2
-rw-r--r--tests/extensions-x-codehilite/test.cfg2
-rw-r--r--tests/extensions-x-def_list/markdown-syntax.html10
-rw-r--r--tests/extensions-x-def_list/test.cfg2
-rw-r--r--tests/extensions-x-footnotes/test.cfg2
-rw-r--r--tests/extensions-x-tables/test.cfg2
-rw-r--r--tests/extensions-x-toc/syntax-toc.html10
-rw-r--r--tests/extensions-x-toc/test.cfg2
-rw-r--r--tests/extensions-x-wikilinks/test.cfg2
-rw-r--r--tests/extensions-x-wikilinks/wikilinks.html3
-rw-r--r--tests/html4/test.cfg2
-rw-r--r--tests/markdown-test/markdown-syntax.html10
-rw-r--r--tests/markdown-test/tabs.html4
-rw-r--r--tests/misc/em-around-links.html13
-rw-r--r--tests/misc/multi-paragraph-block-quote.html2
-rw-r--r--tests/misc/tabs-in-lists.html2
-rw-r--r--tests/plugins.py113
-rw-r--r--tests/safe_mode/test.cfg2
-rwxr-xr-xtests/test_apis.py234
-rw-r--r--tests/util.py15
22 files changed, 513 insertions, 27 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..63ddf5b
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,44 @@
+import os
+import markdown
+import codecs
+import difflib
+import nose
+import util
+from plugins import MdSyntaxError, HtmlOutput, MdSyntaxErrorPlugin
+from test_apis import *
+
+test_dir = os.path.abspath(os.path.dirname(__file__))
+
+def normalize(text):
+ return ['%s\n' % l for l in text.strip().split('\n')]
+
+def check_syntax(file, config):
+ input_file = file + ".txt"
+ input = codecs.open(input_file, encoding="utf-8").read()
+ output_file = file + ".html"
+ expected_output = codecs.open(output_file, encoding="utf-8").read()
+ output = normalize(markdown.markdown(input,
+ config.get('DEFAULT', 'extensions'),
+ config.get('DEFAULT', 'safe_mode'),
+ config.get('DEFAULT', 'output_format')))
+ diff = [l for l in difflib.unified_diff(normalize(expected_output),
+ output, output_file,
+ 'actual_output.html', n=3)]
+ if diff:
+ raise util.MdSyntaxError('Output from "%s" failed to match expected '
+ 'output.\n\n%s' % (input_file, ''.join(diff)))
+
+def test_markdown_syntax():
+ for dir_name, sub_dirs, files in os.walk(test_dir):
+ # Get dir specific config settings.
+ config = util.CustomConfigParser({'extensions': '',
+ 'safe_mode': False,
+ 'output_format': 'xhtml1'})
+ config.read(os.path.join(dir_name, 'test.cfg'))
+ # Loop through files and generate tests.
+ for file in files:
+ root, ext = os.path.splitext(file)
+ if ext == '.txt':
+ yield check_syntax, os.path.join(dir_name, root), config
+
+nose.main(addplugins=[HtmlOutput(), MdSyntaxErrorPlugin()])
diff --git a/tests/base.py b/tests/base.py
new file mode 100644
index 0000000..9e70996
--- /dev/null
+++ b/tests/base.py
@@ -0,0 +1,62 @@
+import os, codecs
+import markdown
+from nose.tools import assert_equal
+import difflib
+from plugins import MdSyntaxError
+
+class SyntaxBase:
+ """
+ Generator that steps through all files in a dir and runs each text file
+ (*.txt) as a seperate unit test.
+
+ Each subclass of SyntaxBase should define `dir` as a string containing the
+ name of the directory which holds the test files. For example:
+
+ dir = "path/to/mytests"
+
+ A subclass may redefine the `setUp` method to create a custom `Markdown`
+ instance specific to that batch of tests.
+
+ """
+
+ dir = ""
+
+ def __init__(self):
+ self.files = [x.replace(".txt", "")
+ for x in os.listdir(self.dir) if x.endswith(".txt")]
+
+ def setUp(self):
+ """
+ Create Markdown instance.
+
+ Override this method to create a custom `Markdown` instance assigned to
+ `self.md`. For example:
+
+ self.md = markdown.Markdown(extensions=["footnotes"], safe_mode="replace")
+
+ """
+ self.md = markdown.Markdown()
+
+ def tearDown(self):
+ """ tearDown is not implemented. """
+ pass
+
+ def test_syntax(self):
+ for file in self.files:
+ yield self.check_syntax, file
+
+ def check_syntax(self, file):
+ input_file = os.path.join(self.dir, file + ".txt")
+ input = codecs.open(input_file, encoding="utf-8").read()
+ output_file = os.path.join(self.dir, file + ".html")
+ expected_output = codecs.open(output_file, encoding="utf-8").read()
+ output = self.normalize(self.md.convert(input))
+ diff = [l for l in difflib.unified_diff(self.normalize(expected_output),
+ output, output_file,
+ 'actual_output.html', n=3)]
+ if diff:
+ #assert False,
+ raise MdSyntaxError('Output from "%s" failed to match expected output.\n\n%s' % (input_file, ''.join(diff)))
+
+ def normalize(self, text):
+ return ['%s\n' % l for l in text.strip().split('\n')]
diff --git a/tests/extensions-x-abbr/test.cfg b/tests/extensions-x-abbr/test.cfg
new file mode 100644
index 0000000..32d437f
--- /dev/null
+++ b/tests/extensions-x-abbr/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=abbr
diff --git a/tests/extensions-x-codehilite/test.cfg b/tests/extensions-x-codehilite/test.cfg
new file mode 100644
index 0000000..6ed10a2
--- /dev/null
+++ b/tests/extensions-x-codehilite/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=codehilite
diff --git a/tests/extensions-x-def_list/markdown-syntax.html b/tests/extensions-x-def_list/markdown-syntax.html
index 2f63b4b..038c9d1 100644
--- a/tests/extensions-x-def_list/markdown-syntax.html
+++ b/tests/extensions-x-def_list/markdown-syntax.html
@@ -484,12 +484,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -660,10 +660,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/extensions-x-def_list/test.cfg b/tests/extensions-x-def_list/test.cfg
new file mode 100644
index 0000000..c9f352d
--- /dev/null
+++ b/tests/extensions-x-def_list/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=def_list
diff --git a/tests/extensions-x-footnotes/test.cfg b/tests/extensions-x-footnotes/test.cfg
new file mode 100644
index 0000000..a5f0818
--- /dev/null
+++ b/tests/extensions-x-footnotes/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=footnotes
diff --git a/tests/extensions-x-tables/test.cfg b/tests/extensions-x-tables/test.cfg
new file mode 100644
index 0000000..ce5a83d
--- /dev/null
+++ b/tests/extensions-x-tables/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=tables
diff --git a/tests/extensions-x-toc/syntax-toc.html b/tests/extensions-x-toc/syntax-toc.html
index eea5347..3559d45 100644
--- a/tests/extensions-x-toc/syntax-toc.html
+++ b/tests/extensions-x-toc/syntax-toc.html
@@ -461,12 +461,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -634,10 +634,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/extensions-x-toc/test.cfg b/tests/extensions-x-toc/test.cfg
new file mode 100644
index 0000000..e4bc0fe
--- /dev/null
+++ b/tests/extensions-x-toc/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=toc
diff --git a/tests/extensions-x-wikilinks/test.cfg b/tests/extensions-x-wikilinks/test.cfg
new file mode 100644
index 0000000..959f38a
--- /dev/null
+++ b/tests/extensions-x-wikilinks/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+extensions=wikilinks
diff --git a/tests/extensions-x-wikilinks/wikilinks.html b/tests/extensions-x-wikilinks/wikilinks.html
index 1a38535..a76a693 100644
--- a/tests/extensions-x-wikilinks/wikilinks.html
+++ b/tests/extensions-x-wikilinks/wikilinks.html
@@ -1,5 +1,8 @@
<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
<p>A link with <a class="wikilink" href="/white_space_and_underscores/">white space and_underscores</a> and a empty one.</p>
+<p>Another with <a class="wikilink" href="/double_spaces/">double spaces</a> and <a class="wikilink" href="/double__underscores/">double__underscores</a> and
+one that <a class="wikilink" href="/has_emphasis_inside/">has <em>emphasis</em> inside</a> and one <a class="wikilink" href="/with_multiple_underscores/">with_multiple_underscores</a>
+and one that is <em><a class="wikilink" href="/emphasised/">emphasised</a></em>.</p>
<p>And a <a href="http://example.com/RealLink">RealLink</a>.</p>
<p><a href="http://example.com/And_A_AutoLink">http://example.com/And_A_AutoLink</a></p>
<p>And a <a href="/MarkdownLink/" title="A MarkdownLink">MarkdownLink</a> for
diff --git a/tests/html4/test.cfg b/tests/html4/test.cfg
new file mode 100644
index 0000000..a3fc498
--- /dev/null
+++ b/tests/html4/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+output_format=html4
diff --git a/tests/markdown-test/markdown-syntax.html b/tests/markdown-test/markdown-syntax.html
index 2f63b4b..038c9d1 100644
--- a/tests/markdown-test/markdown-syntax.html
+++ b/tests/markdown-test/markdown-syntax.html
@@ -484,12 +484,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -660,10 +660,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/markdown-test/tabs.html b/tests/markdown-test/tabs.html
index b26391b..3c11f14 100644
--- a/tests/markdown-test/tabs.html
+++ b/tests/markdown-test/tabs.html
@@ -1,11 +1,11 @@
<ul>
<li>
<p>this is a list item
-indented with tabs</p>
+ indented with tabs</p>
</li>
<li>
<p>this is a list item
-indented with spaces</p>
+ indented with spaces</p>
</li>
</ul>
<p>Code:</p>
diff --git a/tests/misc/em-around-links.html b/tests/misc/em-around-links.html
index 06bfa8e..fafac28 100644
--- a/tests/misc/em-around-links.html
+++ b/tests/misc/em-around-links.html
@@ -1,16 +1,13 @@
<h1>Title</h1>
-
<ul>
- <li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
+<li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
great folks</em> - This <em>does</em> work as expected.</li>
- <li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
+<li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
great folks</em> - This <em>does</em> work as expected.</li>
- <li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> by some
+<li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> by some
great folks - This <em>does</em> work as expected.</li>
- <li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> <em>by some
+<li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> <em>by some
great folks</em> - This <em>does</em> work as expected.</li>
</ul>
-
<p><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
- great folks</em> - This <em>does</em> work as expected.</p>
-
+great folks</em> - This <em>does</em> work as expected.</p> \ No newline at end of file
diff --git a/tests/misc/multi-paragraph-block-quote.html b/tests/misc/multi-paragraph-block-quote.html
index e13986a..f01b5e4 100644
--- a/tests/misc/multi-paragraph-block-quote.html
+++ b/tests/misc/multi-paragraph-block-quote.html
@@ -1,6 +1,6 @@
<blockquote>
<p>This is line one of paragraph one
- This is line two of paragraph one</p>
+This is line two of paragraph one</p>
<p>This is line one of paragraph two</p>
<p>This is another blockquote.</p>
</blockquote> \ No newline at end of file
diff --git a/tests/misc/tabs-in-lists.html b/tests/misc/tabs-in-lists.html
index a1a92ec..fdb7cb6 100644
--- a/tests/misc/tabs-in-lists.html
+++ b/tests/misc/tabs-in-lists.html
@@ -19,7 +19,7 @@
<p>Now a list with 4 spaces and some text:</p>
<ul>
<li>A
-abcdef</li>
+ abcdef</li>
<li>B</li>
</ul>
<p>Now with a tab and an extra space:</p>
diff --git a/tests/plugins.py b/tests/plugins.py
new file mode 100644
index 0000000..d0cb7f8
--- /dev/null
+++ b/tests/plugins.py
@@ -0,0 +1,113 @@
+import traceback
+from util import MdSyntaxError
+from nose.plugins import Plugin
+from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin
+
+class MdSyntaxErrorPlugin(ErrorClassPlugin):
+ """ Add MdSyntaxError and ensure proper formatting. """
+ mdsyntax = ErrorClass(MdSyntaxError, label='MdSyntaxError', isfailure=True)
+ enabled = True
+
+ def configure(self, options, conf):
+ self.conf = conf
+
+ def addError(self, test, err):
+ """ Ensure other plugins see the error by returning nothing here. """
+ pass
+
+ def formatError(self, test, err):
+ """ Remove unnessecary and unhelpful traceback from error report. """
+ et, ev, tb = err
+ if et.__name__ == 'MdSyntaxError':
+ return et, ev, ''
+ return err
+
+
+def escape(html):
+ """ Escape HTML for display as source within HTML. """
+ html = html.replace('&', '&amp;')
+ html = html.replace('<', '&lt;')
+ html = html.replace('>', '&gt;')
+ return html
+
+
+class HtmlOutput(Plugin):
+ """Output test results as ugly, unstyled html. """
+
+ name = 'html-output'
+ score = 2 # run late
+ enabled = True
+
+ def __init__(self):
+ super(HtmlOutput, self).__init__()
+ self.html = [ '<html><head>',
+ '<title>Test output</title>',
+ '</head><body>' ]
+
+ def configure(self, options, conf):
+ self.conf = conf
+
+ def addSuccess(self, test):
+ self.html.append('<span>ok</span>')
+
+ def addError(self, test, err):
+ err = self.formatErr(err)
+ self.html.append('<span>ERROR</span>')
+ self.html.append('<pre>%s</pre>' % escape(err))
+
+ def addFailure(self, test, err):
+ err = self.formatErr(err)
+ self.html.append('<span>FAIL</span>')
+ self.html.append('<pre>%s</pre>' % escape(err))
+
+ def finalize(self, result):
+ self.html.append('<div>')
+ self.html.append("Ran %d test%s" %
+ (result.testsRun, result.testsRun != 1 and "s"
+or ""))
+ self.html.append('</div>')
+ self.html.append('<div>')
+ if not result.wasSuccessful():
+ self.html.extend(['<span>FAILED (',
+ 'failures=%d ' % len(result.failures),
+ 'errors=%d' % len(result.errors)])
+ for cls in result.errorClasses.keys():
+ storage, label, isfail = result.errorClasses[cls]
+ if isfail:
+ self.html.append(' %ss=%d' % (label, len(storage)))
+ self.html.append(')</span>')
+ else:
+ self.html.append('OK')
+ self.html.append('</div></body></html>')
+ f = open('tmp/test-output.html', 'w')
+ for l in self.html:
+ f.write(l)
+ f.close()
+
+ def formatErr(self, err):
+ exctype, value, tb = err
+ return ''.join(traceback.format_exception(exctype, value, tb))
+
+ def startContext(self, ctx):
+ try:
+ n = ctx.__name__
+ except AttributeError:
+ n = str(ctx).replace('<', '').replace('>', '')
+ self.html.extend(['<fieldset>', '<legend>', n, '</legend>'])
+ try:
+ path = ctx.__file__.replace('.pyc', '.py')
+ self.html.extend(['<div>', path, '</div>'])
+ except AttributeError:
+ pass
+
+ def stopContext(self, ctx):
+ self.html.append('</fieldset>')
+
+ def startTest(self, test):
+ self.html.extend([ '<div><span>',
+ test.shortDescription() or str(test),
+ '</span>' ])
+
+ def stopTest(self, test):
+ self.html.append('</div>')
+
diff --git a/tests/safe_mode/test.cfg b/tests/safe_mode/test.cfg
new file mode 100644
index 0000000..d23e418
--- /dev/null
+++ b/tests/safe_mode/test.cfg
@@ -0,0 +1,2 @@
+[DEFAULT]
+safe_mode=escape
diff --git a/tests/test_apis.py b/tests/test_apis.py
new file mode 100755
index 0000000..59b5a2e
--- /dev/null
+++ b/tests/test_apis.py
@@ -0,0 +1,234 @@
+#!/usr/bin/python
+"""
+Python-Markdown Regression Tests
+================================
+
+Tests of the various APIs with the python markdown lib.
+
+"""
+
+import unittest
+from doctest import DocTestSuite
+import os
+import markdown
+
+class TestMarkdownBasics(unittest.TestCase):
+ """ Tests basics of the Markdown class. """
+
+ def setUp(self):
+ """ Create instance of Markdown. """
+ self.md = markdown.Markdown()
+
+ def testBlankInput(self):
+ """ Test blank input. """
+ self.assertEqual(self.md.convert(''), '')
+
+ def testWhitespaceOnly(self):
+ """ Test input of only whitespace. """
+ self.assertEqual(self.md.convert(' '), '')
+
+ def testSimpleInput(self):
+ """ Test simple input. """
+ self.assertEqual(self.md.convert('foo'), '<p>foo</p>')
+
+class TestBlockParser(unittest.TestCase):
+ """ Tests of the BlockParser class. """
+
+ def setUp(self):
+ """ Create instance of BlockParser. """
+ self.parser = markdown.Markdown().parser
+
+ def testParseChunk(self):
+ """ Test BlockParser.parseChunk. """
+ root = markdown.etree.Element("div")
+ text = 'foo'
+ self.parser.parseChunk(root, text)
+ self.assertEqual(markdown.etree.tostring(root), "<div><p>foo</p></div>")
+
+ def testParseDocument(self):
+ """ Test BlockParser.parseDocument. """
+ lines = ['#foo', '', 'bar', '', ' baz']
+ tree = self.parser.parseDocument(lines)
+ self.assert_(isinstance(tree, markdown.etree.ElementTree))
+ self.assert_(markdown.etree.iselement(tree.getroot()))
+ self.assertEqual(markdown.etree.tostring(tree.getroot()),
+ "<div><h1>foo</h1><p>bar</p><pre><code>baz\n</code></pre></div>")
+
+
+class TestBlockParserState(unittest.TestCase):
+ """ Tests of the State class for BlockParser. """
+
+ def setUp(self):
+ self.state = markdown.blockparser.State()
+
+ def testBlankState(self):
+ """ Test State when empty. """
+ self.assertEqual(self.state, [])
+
+ def testSetSate(self):
+ """ Test State.set(). """
+ self.state.set('a_state')
+ self.assertEqual(self.state, ['a_state'])
+ self.state.set('state2')
+ self.assertEqual(self.state, ['a_state', 'state2'])
+
+ def testIsSate(self):
+ """ Test State.isstate(). """
+ self.assertEqual(self.state.isstate('anything'), False)
+ self.state.set('a_state')
+ self.assertEqual(self.state.isstate('a_state'), True)
+ self.state.set('state2')
+ self.assertEqual(self.state.isstate('state2'), True)
+ self.assertEqual(self.state.isstate('a_state'), False)
+ self.assertEqual(self.state.isstate('missing'), False)
+
+ def testReset(self):
+ """ Test State.reset(). """
+ self.state.set('a_state')
+ self.state.reset()
+ self.assertEqual(self.state, [])
+ self.state.set('state1')
+ self.state.set('state2')
+ self.state.reset()
+ self.assertEqual(self.state, ['state1'])
+
+class TestHtmlStash(unittest.TestCase):
+ """ Test Markdown's HtmlStash. """
+
+ def setUp(self):
+ self.stash = markdown.preprocessors.HtmlStash()
+ self.placeholder = self.stash.store('foo')
+
+ def testSimpleStore(self):
+ """ Test HtmlStash.store. """
+ self.assertEqual(self.placeholder,
+ markdown.preprocessors.HTML_PLACEHOLDER % 0)
+ self.assertEqual(self.stash.html_counter, 1)
+ self.assertEqual(self.stash.rawHtmlBlocks, [('foo', False)])
+
+ def testStoreMore(self):
+ """ Test HtmlStash.store with additional blocks. """
+ placeholder = self.stash.store('bar')
+ self.assertEqual(placeholder,
+ markdown.preprocessors.HTML_PLACEHOLDER % 1)
+ self.assertEqual(self.stash.html_counter, 2)
+ self.assertEqual(self.stash.rawHtmlBlocks,
+ [('foo', False), ('bar', False)])
+
+ def testSafeStore(self):
+ """ Test HtmlStash.store with 'safe' html. """
+ self.stash.store('bar', True)
+ self.assertEqual(self.stash.rawHtmlBlocks,
+ [('foo', False), ('bar', True)])
+
+ def testReset(self):
+ """ Test HtmlStash.reset. """
+ self.stash.reset()
+ self.assertEqual(self.stash.html_counter, 0)
+ self.assertEqual(self.stash.rawHtmlBlocks, [])
+
+class TestOrderedDict(unittest.TestCase):
+ """ Test OrderedDict storage class. """
+
+ def setUp(self):
+ self.odict = markdown.odict.OrderedDict()
+ self.odict['first'] = 'This'
+ self.odict['third'] = 'a'
+ self.odict['fourth'] = 'self'
+ self.odict['fifth'] = 'test'
+
+ def testValues(self):
+ """ Test output of OrderedDict.values(). """
+ self.assertEqual(self.odict.values(), ['This', 'a', 'self', 'test'])
+
+ def testKeys(self):
+ """ Test output of OrderedDict.keys(). """
+ self.assertEqual(self.odict.keys(),
+ ['first', 'third', 'fourth', 'fifth'])
+
+ def testItems(self):
+ """ Test output of OrderedDict.items(). """
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test')])
+
+ def testAddBefore(self):
+ """ Test adding an OrderedDict item before a given key. """
+ self.odict.add('second', 'is', '<third')
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('second', 'is'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test')])
+
+ def testAddAfter(self):
+ """ Test adding an OrderDict item after a given key. """
+ self.odict.add('second', 'is', '>first')
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('second', 'is'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test')])
+
+ def testAddAfterEnd(self):
+ """ Test adding an OrderedDict item after the last key. """
+ self.odict.add('sixth', '.', '>fifth')
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test'), ('sixth', '.')])
+
+ def testAdd_begin(self):
+ """ Test adding an OrderedDict item using "_begin". """
+ self.odict.add('zero', 'CRAZY', '_begin')
+ self.assertEqual(self.odict.items(),
+ [('zero', 'CRAZY'), ('first', 'This'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test')])
+
+ def testAdd_end(self):
+ """ Test adding an OrderedDict item using "_end". """
+ self.odict.add('sixth', '.', '_end')
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('third', 'a'),
+ ('fourth', 'self'), ('fifth', 'test'), ('sixth', '.')])
+
+ def testAddBadLocation(self):
+ """ Test Error on bad location in OrderedDict.add(). """
+ self.assertRaises(ValueError, self.odict.add, 'sixth', '.', '<seventh')
+ self.assertRaises(ValueError, self.odict.add, 'second', 'is', 'third')
+
+ def testDeleteItem(self):
+ """ Test deletion of an OrderedDict item. """
+ del self.odict['fourth']
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('third', 'a'), ('fifth', 'test')])
+
+ def testChangeValue(self):
+ """ Test OrderedDict change value. """
+ self.odict['fourth'] = 'CRAZY'
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('third', 'a'),
+ ('fourth', 'CRAZY'), ('fifth', 'test')])
+
+ def testChangeOrder(self):
+ """ Test OrderedDict change order. """
+ self.odict.link('fourth', '<third')
+ self.assertEqual(self.odict.items(),
+ [('first', 'This'), ('fourth', 'self'),
+ ('third', 'a'), ('fifth', 'test')])
+
+def suite():
+ """ Build a test suite of the above tests and extension doctests. """
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestMarkdown))
+ suite.addTest(unittest.makeSuite(TestBlockParser))
+ suite.addTest(unittest.makeSuite(TestBlockParserState))
+ suite.addTest(unittest.makeSuite(TestHtmlStash))
+ suite.addTest(unittest.makeSuite(TestOrderedDict))
+
+ for filename in os.listdir('markdown/extensions'):
+ if filename.endswith('.py'):
+ module = 'markdown.extensions.%s' % filename[:-3]
+ try:
+ suite.addTest(DocTestSuite(module))
+ except: ValueError
+ # No tests
+ return suite
+
+if __name__ == '__main__':
+ unittest.TextTestRunner(verbosity=2).run(suite())
diff --git a/tests/util.py b/tests/util.py
new file mode 100644
index 0000000..3b0175d
--- /dev/null
+++ b/tests/util.py
@@ -0,0 +1,15 @@
+from ConfigParser import SafeConfigParser
+
+class MdSyntaxError(Exception):
+ pass
+
+
+class CustomConfigParser(SafeConfigParser):
+ def get(self, section, option):
+ value = SafeConfigParser.get(self, section, option)
+ if option == 'extensions':
+ if len(value.strip()):
+ return value.split(',')
+ else:
+ return []
+ return value