aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWaylan Limberg <waylan@gmail.com>2009-05-30 22:29:56 -0400
committerWaylan Limberg <waylan@gmail.com>2009-06-05 22:25:51 -0400
commitcc452998dc1af441cf3f9c5d0c7287cb5de48c4a (patch)
treef138bb00542b47bf382d4ba8f10f0d2a9470ccfe
parent0ae9951f49eb75c8a9fb9f841673b889763c1811 (diff)
downloadmarkdown-cc452998dc1af441cf3f9c5d0c7287cb5de48c4a.tar.gz
markdown-cc452998dc1af441cf3f9c5d0c7287cb5de48c4a.tar.bz2
markdown-cc452998dc1af441cf3f9c5d0c7287cb5de48c4a.zip
Initial implementation of nose testing. Still some cleanup to do, but this shows the differances between the old and the new. Also left one test failing (unsignificant white space only) to demonstrate what a failing test looks like.
-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