summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevin Torres <devin@devintorr.es>2014-09-13 00:11:30 -0500
committerDevin Torres <devin@devintorr.es>2014-09-13 00:11:30 -0500
commitd20dd8ee04016b100531567219467b15713af94a (patch)
tree765ae1790e98be978f228d83b3c7af51f0bd89f8
parentb92c4545b0a9a2a0c37aad8c4e6bb4b1dc6b6340 (diff)
parent00a5b7abc25a3f88afb7f4f44c1328a119343270 (diff)
downloadrust-hoedown-d20dd8ee04016b100531567219467b15713af94a.tar.gz
Merge pull request #122 from uranusjr/unittest
New test framework based on Python’s unittest module
-rw-r--r--Makefile2
-rw-r--r--test/Tests/Escape character.html (renamed from test/MarkdownTest_1.0.3/Tests/Escape character.html)0
-rw-r--r--test/Tests/Escape character.text (renamed from test/MarkdownTest_1.0.3/Tests/Escape character.text)0
-rw-r--r--test/Tests/Math.html31
-rw-r--r--test/Tests/Math.text31
-rw-r--r--test/config.json101
-rwxr-xr-xtest/runner.py108
-rwxr-xr-xtest/runner.sh50
8 files changed, 272 insertions, 51 deletions
diff --git a/Makefile b/Makefile
index fb0f79c..9faec03 100644
--- a/Makefile
+++ b/Makefile
@@ -46,7 +46,7 @@ src/html_blocks.c: html_block_names.gperf
# Testing
test: hoedown
- test/runner.sh ./hoedown test/MarkdownTest_1.0.3/Tests
+ python test/runner.py
test-pl: hoedown
perl test/MarkdownTest_1.0.3/MarkdownTest.pl \
diff --git a/test/MarkdownTest_1.0.3/Tests/Escape character.html b/test/Tests/Escape character.html
index a6863ba..a6863ba 100644
--- a/test/MarkdownTest_1.0.3/Tests/Escape character.html
+++ b/test/Tests/Escape character.html
diff --git a/test/MarkdownTest_1.0.3/Tests/Escape character.text b/test/Tests/Escape character.text
index 3eab090..3eab090 100644
--- a/test/MarkdownTest_1.0.3/Tests/Escape character.text
+++ b/test/Tests/Escape character.text
diff --git a/test/Tests/Math.html b/test/Tests/Math.html
new file mode 100644
index 0000000..5e2fd3e
--- /dev/null
+++ b/test/Tests/Math.html
@@ -0,0 +1,31 @@
+<p>\[
+1*2*3 multi-line math
+\]</p>
+
+<p>\( 1*2*3 inline-math \)</p>
+
+<p>\[ 1*2*3 math with dollar \]</p>
+
+<p>\[ 1*2*3 \$ \\ \text{dollar with escapes} \]</p>
+
+<p>\( \\ \text{backslash with escapes} \$ 1*2*3 \)</p>
+
+<p>( not <em>really</em> math )</p>
+
+<p>$$ also <em>not</em> math $$</p>
+
+<p>this$$ should <em>not</em> be$$ math</p>
+
+<p>nor $$ <em>should</em> $$this</p>
+
+<p>this \(*should* be\) math</p>
+
+<p>Something \{ like <em>math</em> but \} is not</p>
+
+<p>Also \(like <em>math</em> but \) is not</p>
+
+<p>\\( should not be <em>math</em> either \\)</p>
+
+<p>This is \( math, and the \\\( inner one \\\) should be \) preserved</p>
+
+<p>\[ did you &lt;em&gt; know &lt;/em&gt; this is math? \]</p>
diff --git a/test/Tests/Math.text b/test/Tests/Math.text
new file mode 100644
index 0000000..789c213
--- /dev/null
+++ b/test/Tests/Math.text
@@ -0,0 +1,31 @@
+\\[
+1*2*3 multi-line math
+\\]
+
+\\( 1*2*3 inline-math \\)
+
+$$ 1*2*3 math with dollar $$
+
+$$ 1*2*3 \$ \\ \text{dollar with escapes} $$
+
+\\( \\ \text{backslash with escapes} \$ 1*2*3 \\)
+
+\( not *really* math \)
+
+\$$ also *not* math \$$
+
+this$$ should *not* be$$ math
+
+nor $$ *should* $$this
+
+this $$*should* be$$ math
+
+Something \\{ like *math* but \\} is not
+
+Also \\\(like *math* but \\\) is not
+
+\\\\( should not be *math* either \\\\)
+
+This is \\( math, and the \\\( inner one \\\) should be \\) preserved
+
+$$ did you <em> know </em> this is math? $$
diff --git a/test/config.json b/test/config.json
new file mode 100644
index 0000000..63cb1d7
--- /dev/null
+++ b/test/config.json
@@ -0,0 +1,101 @@
+{
+ "tests": [
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Amps and angle encoding.text",
+ "output": "MarkdownTest_1.0.3/Tests/Amps and angle encoding.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Auto links.text",
+ "output": "MarkdownTest_1.0.3/Tests/Auto links.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Backslash escapes.text",
+ "output": "MarkdownTest_1.0.3/Tests/Backslash escapes.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text",
+ "output": "MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Code Blocks.text",
+ "output": "MarkdownTest_1.0.3/Tests/Code Blocks.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Code Spans.text",
+ "output": "MarkdownTest_1.0.3/Tests/Code Spans.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text",
+ "output": "MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Horizontal rules.text",
+ "output": "MarkdownTest_1.0.3/Tests/Horizontal rules.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text",
+ "output": "MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text",
+ "output": "MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Inline HTML comments.text",
+ "output": "MarkdownTest_1.0.3/Tests/Inline HTML comments.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Links, inline style.text",
+ "output": "MarkdownTest_1.0.3/Tests/Links, inline style.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Links, reference style.text",
+ "output": "MarkdownTest_1.0.3/Tests/Links, reference style.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Links, shortcut references.text",
+ "output": "MarkdownTest_1.0.3/Tests/Links, shortcut references.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Literal quotes in titles.text",
+ "output": "MarkdownTest_1.0.3/Tests/Literal quotes in titles.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text",
+ "output": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text",
+ "output": "MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Nested blockquotes.text",
+ "output": "MarkdownTest_1.0.3/Tests/Nested blockquotes.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text",
+ "output": "MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Strong and em together.text",
+ "output": "MarkdownTest_1.0.3/Tests/Strong and em together.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Tabs.text",
+ "output": "MarkdownTest_1.0.3/Tests/Tabs.html"
+ },
+ {
+ "input": "MarkdownTest_1.0.3/Tests/Tidyness.text",
+ "output": "MarkdownTest_1.0.3/Tests/Tidyness.html"
+ },
+ {
+ "input": "Tests/Escape character.text",
+ "output": "Tests/Escape character.html"
+ },
+ {
+ "input": "Tests/Math.text",
+ "output": "Tests/Math.html",
+ "flags": ["--math"]
+ }
+ ]
+}
diff --git a/test/runner.py b/test/runner.py
new file mode 100755
index 0000000..4102fad
--- /dev/null
+++ b/test/runner.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import difflib
+import json
+import os
+import re
+import subprocess
+import unittest
+
+TEST_ROOT = os.path.dirname(__file__)
+PROJECT_ROOT = os.path.dirname(TEST_ROOT)
+HOEDOWN = [os.path.abspath(os.path.join(PROJECT_ROOT, 'hoedown'))]
+TIDY = ['tidy', '--show-body-only', '1', '--show-warnings', '0',
+ '--quiet', '1']
+CONFIG_PATH = os.path.join(TEST_ROOT, 'config.json')
+SLUGIFY_PATTERN = re.compile(r'\W')
+
+
+def with_metaclass(meta, *bases):
+ """Metaclass injection utility from six.
+
+ See: https://pythonhosted.org/six/
+ """
+ class metaclass(meta):
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+ return type.__new__(metaclass, 'temporary_class', (), {})
+
+
+class TestFailed(AssertionError):
+ def __init__(self, name, expected, got):
+ super(TestFailed, self).__init__(self)
+ diff = difflib.unified_diff(
+ expected.splitlines(), got.splitlines(),
+ fromfile='Expected', tofile='Got',
+ )
+ self.description = '{name}\n{diff}'.format(
+ name=name, diff='\n'.join(diff),
+ )
+
+ def __str__(self):
+ return self.description
+
+
+def _test_func(test_case):
+ flags = test_case.get('flags') or []
+ hoedown_proc = subprocess.Popen(
+ HOEDOWN + flags + [os.path.join(TEST_ROOT, test_case['input'])],
+ stdout=subprocess.PIPE,
+ )
+ hoedown_proc.wait()
+ got_tidy_proc = subprocess.Popen(
+ TIDY, stdin=hoedown_proc.stdout, stdout=subprocess.PIPE,
+ )
+ got_tidy_proc.wait()
+ got = got_tidy_proc.stdout.read().strip()
+
+ expected_tidy_proc = subprocess.Popen(
+ TIDY + [os.path.join(TEST_ROOT, test_case['output'])],
+ stdout=subprocess.PIPE,
+ )
+ expected_tidy_proc.wait()
+ expected = expected_tidy_proc.stdout.read().strip()
+
+ # Cleanup.
+ hoedown_proc.stdout.close()
+ got_tidy_proc.stdout.close()
+ expected_tidy_proc.stdout.close()
+
+ try:
+ assert expected == got
+ except AssertionError:
+ raise TestFailed(test_case['input'], expected, got)
+
+
+def _make_test(test_case):
+ return lambda self: _test_func(test_case)
+
+
+class MarkdownTestsMeta(type):
+ """Meta class for ``MarkdownTestCase`` to inject test cases on the fly.
+ """
+ def __new__(meta, name, bases, attrs):
+ with open(CONFIG_PATH) as f:
+ config = json.load(f)
+
+ for test in config['tests']:
+ input_name = test['input']
+ attr_name = 'test_' + SLUGIFY_PATTERN.sub(
+ '_', os.path.splitext(input_name)[0].lower(),
+ )
+ func = _make_test(test)
+ func.__doc__ = input_name
+ if test.get('skip', False):
+ func = unittest.skip(input_name)(func)
+ if test.get('fail', False):
+ func = unittest.expectsFailure(func)
+ attrs[attr_name] = func
+ return type.__new__(meta, name, bases, attrs)
+
+
+class MarkdownTests(with_metaclass(MarkdownTestsMeta, unittest.TestCase)):
+ pass
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/runner.sh b/test/runner.sh
deleted file mode 100755
index d60eac5..0000000
--- a/test/runner.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-
-POSIXLY_CORRECT=1
-export POSIXLY_CORRECT
-
-TIDY='tidy --show-body-only 1 --quiet 1 --show-warnings 0'
-SCRIPT="$1"
-TESTDIR="$2"
-PASSED=0
-FAILED=0
-
-abort() {
- echo "Error: $*"
- exit 1
-}
-
-test -f "$SCRIPT" || abort "argument #1 invalid; not a file"
-test -x "$SCRIPT" || abort "argument #1 invalid; not executable"
-echo "" | "$SCRIPT" || abort "argument #1 invalid; script failed to run"
-test -d "$TESTDIR" || abort "argument #2 invalid; not a directory"
-
-for TEXT in "$TESTDIR"/*.text; do
- test -f "$TEXT" || abort "empty or invalid test directory"
- printf "$(basename "$TEXT" .text) ... "
- HTML=$(echo "$TEXT" | sed 's/\.text$/.html/')
-
- # We use mktemp to create an unpredictable, temporary filename.
- # The created file is immediately deleted, since we only want a
- # name to pass to mkfifo and "mktemp -u" is not portable.
- PIPE=$(mktemp .testpipe-XXXXXXXX)
- test -f "$PIPE" -a -n "$PIPE" || abort "mktemp failed"
- trap 'rm -f "$PIPE"' EXIT INT TERM HUP
- rm -f "$PIPE"
- mkfifo -m 0600 "$PIPE" || abort "unable to create named pipe"
-
- $SCRIPT "$TEXT" | $TIDY > "$PIPE" &
- DIFF=$($TIDY "$HTML" | diff "$PIPE" -)
- if test "$?" = 0; then
- PASSED=$(expr $PASSED + 1)
- echo OK
- else
- FAILED=$(expr $FAILED + 1)
- echo FAILED
- printf "\n$DIFF\n\n"
- fi
- rm -f "$PIPE"
-done
-
-printf "\n\n$PASSED passed; $FAILED failed.\n"
-test "$FAILED" = 0 || exit 1