aboutsummaryrefslogtreecommitdiffstats
path: root/markdown
diff options
context:
space:
mode:
authorWaylan Limberg <waylan.limberg@icloud.com>2018-01-06 01:04:11 -0500
committerWaylan Limberg <waylan.limberg@icloud.com>2018-01-08 20:41:18 -0500
commit49249b3fb6c458c2cbc34c409ba57cfae6e72320 (patch)
treee5cdbb09bf193f40ccc8735679d93a8c14aa591a /markdown
parent76e0a63e12dd964311c4350a5735bb7f51ef87a6 (diff)
downloadmarkdown-49249b3fb6c458c2cbc34c409ba57cfae6e72320.tar.gz
markdown-49249b3fb6c458c2cbc34c409ba57cfae6e72320.tar.bz2
markdown-49249b3fb6c458c2cbc34c409ba57cfae6e72320.zip
Switch from nose to unittest
All file-based tests are now defined as unittest test cases via a metaclass which walks a directory and builds a unittest for each pair of test files. To run the tests just run `python -m unittest discover tests`. Or use tox as the tox config has been updated to run the new tests and all nose specific code has been removed. The test generator tools have been removed as well. If any changes or additions need to be made to tests, they should be implemented using the new framework rather than with the file-based tests. Eventually, only the PHP and pl tests should remain as file-based tests.
Diffstat (limited to 'markdown')
-rw-r--r--markdown/test_tools.py125
1 files changed, 124 insertions, 1 deletions
diff --git a/markdown/test_tools.py b/markdown/test_tools.py
index cebb2bb..9324bd4 100644
--- a/markdown/test_tools.py
+++ b/markdown/test_tools.py
@@ -1,6 +1,16 @@
+from __future__ import absolute_import
+import os
+import io
import unittest
import textwrap
-from markdown import markdown
+from . import markdown
+
+try:
+ import tidylib
+except ImportError:
+ tidylib = None
+
+__all__ = ['TestCase', 'LegacyTestCase', 'Kwargs']
class TestCase(unittest.TestCase):
@@ -42,3 +52,116 @@ class TestCase(unittest.TestCase):
# TODO: If/when actual output ends with a newline, then use:
# return textwrap.dedent(text.strip('/n'))
return textwrap.dedent(text).strip()
+
+
+#########################
+# Legacy Test Framework #
+#########################
+
+
+class Kwargs(dict):
+ """ A dict like class for holding keyword arguments. """
+ pass
+
+
+def _normalize_whitespace(text):
+ """ Normalize whitespace for a string of html using tidylib. """
+ output, errors = tidylib.tidy_fragment(text, options={
+ '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,
+ 'newline': 'LF'
+ })
+ return output
+
+
+class LegacyTestMeta(type):
+ def __new__(cls, name, bases, dct):
+
+ def generate_test(infile, outfile, normalize, kwargs):
+ def test(self):
+ with io.open(infile, encoding="utf-8") as f:
+ input = f.read()
+ with io.open(outfile, encoding="utf-8") as f:
+ # Normalize line endings
+ # (on Windows, git may have altered line endings).
+ expected = f.read().replace("\r\n", "\n")
+ output = markdown(input, **kwargs)
+ if tidylib and normalize:
+ expected = _normalize_whitespace(expected)
+ output = _normalize_whitespace(output)
+ elif normalize:
+ self.skipTest('Tidylib not available.')
+ self.assertMultiLineEqual(output, expected)
+ return test
+
+ location = dct.get('location', '')
+ exclude = dct.get('exclude', [])
+ normalize = dct.get('normalize', False)
+ input_ext = dct.get('input_ext', '.txt')
+ output_ext = dct.get('output_ext', '.html')
+ kwargs = dct.get('default_kwargs', Kwargs())
+
+ if os.path.isdir(location):
+ for file in os.listdir(location):
+ infile = os.path.join(location, file)
+ if os.path.isfile(infile):
+ tname, ext = os.path.splitext(file)
+ if ext == input_ext:
+ outfile = os.path.join(location, tname + output_ext)
+ tname = tname.replace(' ', '_').replace('-', '_')
+ kws = kwargs.copy()
+ if tname in dct:
+ kws.update(dct[tname])
+ test_name = 'test_%s' % tname
+ if tname not in exclude:
+ dct[test_name] = generate_test(infile, outfile, normalize, kws)
+ else:
+ dct[test_name] = unittest.skip('Excluded')(lambda: None)
+
+ return type.__new__(cls, name, bases, dct)
+
+
+# Define LegacyTestCase class with metaclass in Py2 & Py3 compatable way.
+# See https://stackoverflow.com/a/38668373/866026
+# TODO: If/when py2 support is dropped change to:
+# class LegacyTestCase(unittest.Testcase, metaclass=LegacyTestMeta)
+
+
+class LegacyTestCase(LegacyTestMeta('LegacyTestCase', (unittest.TestCase,), {'__slots__': ()})):
+ """
+ A `unittest.TestCase` subclass for running Markdown's legacy file-based tests.
+
+ A subclass should define various properties which point to a directory of
+ text-based test files and define various behaviors/defaults for those tests.
+ The following properties are supported:
+
+ location: A path to the directory fo test files. An absolute path is prefered.
+ exclude: A list of tests to exclude. Each test name should comprise the filename
+ without an extension.
+ normalize: A boolean value indicating if the HTML should be normalized.
+ Default: `False`.
+ input_ext: A string containing the file extension of input files. Default: `.txt`.
+ ouput_ext: A string containing the file extension of expected output files.
+ Default: `html`.
+ default_kwargs: A `Kwargs` instance which stores the default set of keyword
+ arguments for all test files in the directory.
+
+ In addition, properties can be defined for each individual set of test files within
+ the directory. The property should be given the name of the file wihtout the file
+ extension. Any spaces and dashes in the filename should be replaced with
+ underscores. The value of the property should be a `Kwargs` instance which
+ contains the keyword arguments that should be passed to `Markdown` for that
+ test file. The keyword arguments will "update" the `default_kwargs`.
+
+ When the class instance is created, it will walk the given directory and create
+ a seperate unitttest for each set of test files using the naming scheme:
+ `test_filename`. One unittest will be run for each set of input and output files.
+ """
+ pass