aboutsummaryrefslogtreecommitdiffstats
path: root/tests/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/__init__.py')
-rw-r--r--tests/__init__.py117
1 files changed, 117 insertions, 0 deletions
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..d07ae7d
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,117 @@
+import os
+import markdown
+import codecs
+import difflib
+import nose
+import util
+from plugins import HtmlOutput, Markdown
+try:
+ import tidy
+except ImportError:
+ tidy = None
+
+
+test_dir = os.path.abspath(os.path.dirname(__file__))
+
+def relpath(path, start=test_dir):
+ """ reimplement relpath for python 2.3-2.5 from 2.6 """
+ if not path:
+ raise ValueError('no path secified')
+ start_list = os.path.abspath(start).split(os.path.sep)
+ path_list = os.path.abspath(path).split(os.path.sep)
+ # Work out how much of the filepath is shared by start and path.
+ i = len(os.path.commonprefix([start_list, path_list]))
+ rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return test_dir
+ return os.path.join(*rel_list)
+
+def get_section(file, config):
+ """ Get name of config section for given file. """
+ filename = os.path.basename(file)
+ if config.has_section(filename):
+ return filename
+ else:
+ return 'DEFAULT'
+
+def get_args(file, config):
+ """ Get args to pass to markdown from config for a given file. """
+ args = {}
+ section = get_section(file, config)
+ for key in ['extensions', 'safe_mode', 'output_format']:
+ args[key] = config.get(section, key)
+ return args
+
+def normalize(text):
+ """ Normalize whitespace for a string of html using tidy. """
+ return str(tidy.parseString(text.encode('utf-8'),
+ drop_empty_paras=0,
+ fix_backslash=0,
+ fix_bad_comments=0,
+ fix_uri=0,
+ join_styles=0,
+ lower_literals=0,
+ merge_divs=0,
+ output_xhtml=1,
+ quote_ampersand=0,
+ show_body_only=1,
+ char_encoding='utf8',
+ newline='LF')).decode('string-escape')
+
+class CheckSyntax(object):
+ def __init__(self, description=None):
+ if description:
+ self.description = 'TestSyntax: "%s"' % description
+
+ def __call__(self, file, config):
+ """ Compare expected output to actual output and report result. """
+ cfg_section = get_section(file, config)
+ if config.getboolean(cfg_section, 'skip'):
+ raise nose.plugins.skip.SkipTest, 'Test skipped per config.'
+ input_file = file + config.get(cfg_section, 'input_ext')
+ input = codecs.open(input_file, encoding="utf-8").read()
+ output_file = file + config.get(cfg_section, 'output_ext')
+ expected_output = codecs.open(output_file, encoding="utf-8").read()
+ output = markdown.markdown(input, **get_args(file, config))
+ if tidy and config.getboolean(cfg_section, 'normalize'):
+ # Normalize whitespace before comparing.
+ expected_output = normalize(expected_output)
+ output = normalize(output)
+ elif config.getboolean(cfg_section, 'normalize'):
+ # Tidy is not available. Skip this test.
+ raise nose.plugins.skip.SkipTest, 'Test skipped. Tidy not available in system.'
+ diff = [l for l in difflib.unified_diff(expected_output.splitlines(True),
+ output.splitlines(True),
+ output_file,
+ 'actual_output.html',
+ n=3)]
+ if diff:
+ raise util.MarkdownSyntaxError('Output from "%s" failed to match expected '
+ 'output.\n\n%s' % (input_file, ''.join(diff)))
+
+def TestSyntax():
+ 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',
+ 'normalize': '0',
+ 'skip': '0',
+ 'input_ext': '.txt',
+ 'output_ext': '.html'})
+ 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 == config.get(get_section(file, config), 'input_ext'):
+ path = os.path.join(dir_name, root)
+ check_syntax = CheckSyntax(description=relpath(path, test_dir))
+ yield check_syntax, path, config
+
+def run():
+ nose.main(addplugins=[HtmlOutput(), Markdown()])
+
+# Hack to make nose run with extensions. Once extensions can be added from
+# setup.cfg, the below line can be removed.
+# See nose [Issue 271](http://code.google.com/p/python-nose/issues/detail?id=271)
+run()