aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in3
-rw-r--r--makefile8
-rw-r--r--markdown/test_tools.py125
-rwxr-xr-xrun-tests.py23
-rw-r--r--setup.cfg2
-rw-r--r--test-requirements.txt1
-rw-r--r--tests/__init__.py189
-rw-r--r--tests/basic/benchmark.dat20
-rw-r--r--tests/extensions/extra/test.cfg36
-rw-r--r--tests/extensions/test.cfg73
-rw-r--r--tests/options/test.cfg11
-rw-r--r--tests/php/extra/test.cfg7
-rw-r--r--tests/php/test.cfg50
-rw-r--r--tests/pl/Tests_2004/test.cfg10
-rw-r--r--tests/pl/Tests_2007/test.cfg25
-rw-r--r--tests/plugins.py127
-rw-r--r--tests/safe_mode/test.cfg8
-rw-r--r--tests/test_legacy.py213
-rw-r--r--tox.ini4
19 files changed, 342 insertions, 593 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index c3d529d..a14d4ea 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,9 +1,8 @@
recursive-include markdown *.py
recursive-include docs *
-recursive-include tests *.txt *.html *.cfg *.py
+recursive-include tests *.txt *.html *.py
include setup.py
include setup.cfg
-include run-tests.py
include tox.ini
include makefile
include LICENSE.md
diff --git a/makefile b/makefile
index 8cfd0ea..3eb7d48 100644
--- a/makefile
+++ b/makefile
@@ -11,7 +11,6 @@ help:
@echo ' build-win Build a Windows exe distribution'
@echo ' docs Build documentation'
@echo ' test Run all tests'
- @echo ' update-tests Generate html files for updated text files in tests'
@echo ' clean Clean up the source directories'
.PHONY : install
@@ -38,11 +37,8 @@ docs:
.PHONY : test
test:
- tox
-
-.PHONY : update-tests
-update-tests:
- python run-tests.py update
+ coverage run --source=markdown -m unittest discover tests
+ coverage report --show-missing
.PHONY : clean
clean:
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
diff --git a/run-tests.py b/run-tests.py
deleted file mode 100755
index 5748953..0000000
--- a/run-tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-
-import tests
-import os
-import sys
-
-if len(sys.argv) > 1 and sys.argv[1] == "update":
- if len(sys.argv) > 2:
- config = tests.get_config(os.path.dirname(sys.argv[2]))
- root, ext = os.path.splitext(sys.argv[2])
- if ext == config.get(
- config.get_section(os.path.basename(root)), 'input_ext'
- ):
- tests.generate(root, config)
- else:
- print(
- sys.argv[2],
- 'does not have a valid file extension. Check config.'
- )
- else:
- tests.generate_all()
-else:
- tests.run()
diff --git a/setup.cfg b/setup.cfg
index 81482a9..5e17c83 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,3 @@
-[nosetests]
-
[bdist_wheel]
universal=1
diff --git a/test-requirements.txt b/test-requirements.txt
index 65bfae0..12244ab 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,4 +1,3 @@
-nose
coverage<4.0
pyyaml
pytidylib
diff --git a/tests/__init__.py b/tests/__init__.py
index 6826ff3..e69de29 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,189 +0,0 @@
-import os
-import markdown
-import codecs
-import difflib
-import warnings
-try:
- import nose
-except ImportError as e:
- msg = e.args[0]
- msg = msg + ". The nose testing framework is required to run the Python-" \
- "Markdown tests. Run `pip install nose` to install the latest version."
- e.args = (msg,) + e.args[1:]
- raise
-from .plugins import HtmlOutput, Markdown, MarkdownSyntaxError
-try:
- import tidylib
-except ImportError:
- tidylib = None
-try:
- import yaml
-except ImportError as e:
- msg = e.args[0]
- msg = msg + ". A YAML library is required to run the Python-Markdown " \
- "tests. Run `pip install pyyaml` to install the latest version."
- e.args = (msg,) + e.args[1:]
- raise
-
-test_dir = os.path.abspath(os.path.dirname(__file__))
-
-
-class YamlConfig():
- def __init__(self, defaults, filename):
- """ Set defaults and load config file if it exists. """
- self.DEFAULT_SECTION = 'DEFAULT'
- self._defaults = defaults
- self._config = {}
- if os.path.exists(filename):
- with codecs.open(filename, encoding="utf-8") as f:
- self._config = yaml.load(f)
-
- def get(self, section, option):
- """ Get config value for given section and option key. """
- if section in self._config and option in self._config[section]:
- return self._config[section][option]
- return self._defaults[option]
-
- def get_section(self, file):
- """ Get name of config section for given file. """
- filename = os.path.basename(file)
- if filename in self._config:
- return filename
- else:
- return self.DEFAULT_SECTION
-
- def get_args(self, file):
- """ Get args to pass to markdown from config for a given file. """
- args = {}
- section = self.get_section(file)
- if section in self._config:
- for key in self._config[section].keys():
- # Filter out args unique to testing framework
- if key not in self._defaults.keys():
- args[key] = self.get(section, key)
- return args
-
-
-def get_config(dir_name):
- """ Get config for given directory name. """
- defaults = {
- 'normalize': False,
- 'skip': False,
- 'input_ext': '.txt',
- 'output_ext': '.html'
- }
- config = YamlConfig(defaults, os.path.join(dir_name, 'test.cfg'))
- return config
-
-
-def normalize(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 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 = config.get_section(file)
- if config.get(cfg_section, 'skip'):
- raise nose.plugins.skip.SkipTest('Test skipped per config.')
- input_file = file + config.get(cfg_section, 'input_ext')
- with codecs.open(input_file, encoding="utf-8") as f:
- input = f.read()
- output_file = file + config.get(cfg_section, 'output_ext')
- with codecs.open(output_file, encoding="utf-8") as f:
- # Normalize line endings
- # (on windows, git may have altered line endings).
- expected_output = f.read().replace("\r\n", "\n")
- output = markdown.markdown(input, **config.get_args(file))
- if tidylib and config.get(cfg_section, 'normalize'):
- # Normalize whitespace with tidylib before comparing.
- expected_output = normalize(expected_output)
- output = normalize(output)
- elif config.get(cfg_section, 'normalize'):
- # Tidylib is not available. Skip this test.
- raise nose.plugins.skip.SkipTest(
- 'Test skipped. Tidylib not available on 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 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 = get_config(dir_name)
- # Loop through files and generate tests.
- for file in files:
- root, ext = os.path.splitext(file)
- if ext == config.get(config.get_section(file), 'input_ext'):
- path = os.path.join(dir_name, root)
- check_syntax = CheckSyntax(
- description=os.path.relpath(path, test_dir)
- )
- yield check_syntax, path, config
-
-
-def generate(file, config):
- """ Write expected output file for given input. """
- cfg_section = config.get_section(file)
- if config.get(cfg_section, 'skip') or config.get(cfg_section, 'normalize'):
- print('Skipping:', file)
- return None
- input_file = file + config.get(cfg_section, 'input_ext')
- output_file = file + config.get(cfg_section, 'output_ext')
- if not os.path.isfile(output_file) or \
- os.path.getmtime(output_file) < os.path.getmtime(input_file):
- print('Generating:', file)
- markdown.markdownFromFile(input=input_file, output=output_file,
- encoding='utf-8', **config.get_args(file))
- else:
- print('Already up-to-date:', file)
-
-
-def generate_all():
- """ Generate expected output for all outdated tests. """
- for dir_name, sub_dirs, files in os.walk(test_dir):
- # Get dir specific config settings.
- config = get_config(dir_name)
- # Loop through files and generate tests.
- for file in files:
- root, ext = os.path.splitext(file)
- if ext == config.get(config.get_section(file), 'input_ext'):
- generate(os.path.join(dir_name, root), config)
-
-
-def run():
- # Warnings should cause tests to fail...
- warnings.simplefilter('error')
- # Except for the warnings that shouldn't
- warnings.filterwarnings('default', category=PendingDeprecationWarning)
- warnings.filterwarnings('default', category=DeprecationWarning, module='markdown')
-
- nose.main(addplugins=[HtmlOutput(), Markdown()])
diff --git a/tests/basic/benchmark.dat b/tests/basic/benchmark.dat
deleted file mode 100644
index 3d549dd..0000000
--- a/tests/basic/benchmark.dat
+++ /dev/null
@@ -1,20 +0,0 @@
-construction:0.000000:0.000000
-amps-and-angle-encoding:0.070000:131072.000000
-auto-links:0.080000:397312.000000
-backlash-escapes:0.270000:884736.000000
-blockquotes-with-dode-blocks:0.020000:0.000000
-hard-wrapped:0.020000:0.000000
-horizontal-rules:0.180000:135168.000000
-inline-html-advanced:0.070000:0.000000
-inline-html-comments:0.080000:0.000000
-inline-html-simple:0.210000:0.000000
-links-inline:0.140000:0.000000
-links-reference:0.170000:0.000000
-literal-quotes:0.090000:0.000000
-markdown-documentation-basics:0.690000:1806336.000000
-markdown-syntax:3.310000:6696960.000000
-nested-blockquotes:0.200000:0.000000
-ordered-and-unordered-list:0.530000:0.000000
-strong-and-em-together:0.200000:0.000000
-tabs:0.200000:0.000000
-tidyness:0.200000:0.000000
diff --git a/tests/extensions/extra/test.cfg b/tests/extensions/extra/test.cfg
deleted file mode 100644
index d956e2a..0000000
--- a/tests/extensions/extra/test.cfg
+++ /dev/null
@@ -1,36 +0,0 @@
-DEFAULT:
- extensions:
- - markdown.extensions.extra
-
-loose_def_list:
- extensions:
- - markdown.extensions.def_list
-
-simple_def-lists:
- extensions:
- - markdown.extensions.def_list
-
-abbr:
- extensions:
- - markdown.extensions.abbr
-
-footnotes:
- extensions:
- - markdown.extensions.footnotes
-
-tables:
- extensions:
- - markdown.extensions.tables
-
-tables_and_attr_list:
- extensions:
- - markdown.extensions.tables
- - markdown.extensions.attr_list
-
-extra_config:
- extensions:
- - markdown.extensions.extra
- extension_configs:
- markdown.extensions.extra:
- markdown.extensions.footnotes:
- PLACE_MARKER: ~~~placemarker~~~
diff --git a/tests/extensions/test.cfg b/tests/extensions/test.cfg
deleted file mode 100644
index ce66cfc..0000000
--- a/tests/extensions/test.cfg
+++ /dev/null
@@ -1,73 +0,0 @@
-attr_list:
- extensions:
- - markdown.extensions.attr_list
- - markdown.extensions.def_list
- - markdown.extensions.smarty
-
-codehilite:
- extensions:
- - markdown.extensions.codehilite
- # This passes or not based on version of pygments.
- skip: True
-
-toc:
- extensions:
- - markdown.extensions.toc
-
-toc_invalid:
- extensions:
- - markdown.extensions.toc
-
-toc_out_of_order:
- extensions:
- - markdown.extensions.toc
-
-toc_nested:
- extensions:
- - markdown.extensions.toc
- extension_configs:
- markdown.extensions.toc:
- permalink: True
-
-toc_nested2:
- extensions:
- - markdown.extensions.toc
- extension_configs:
- markdown.extensions.toc:
- permalink: "[link]"
-
-toc_nested_list:
- extensions:
- - markdown.extensions.toc
-
-wikilinks:
- extensions:
- - markdown.extensions.wikilinks
-
-fenced_code:
- extensions:
- - markdown.extensions.fenced_code
-
-github_flavored:
- extensions:
- - markdown.extensions.fenced_code
-
-sane_lists:
- extensions:
- - markdown.extensions.sane_lists
-
-nl2br_w_attr_list:
- extensions:
- - markdown.extensions.nl2br
- - markdown.extensions.attr_list
-
-admonition:
- extensions:
- - markdown.extensions.admonition
-
-smarty:
- extensions:
- - markdown.extensions.smarty
- extension_configs:
- markdown.extensions.smarty:
- smart_angled_quotes: True \ No newline at end of file
diff --git a/tests/options/test.cfg b/tests/options/test.cfg
deleted file mode 100644
index 2e14f1f..0000000
--- a/tests/options/test.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-lazy_ol_off:
- lazy_ol: False
-
-html4:
- output_format: html4
-
-no-attributes:
- enable_attributes: False
-
-no-smart-emphasis:
- smart_emphasis: False \ No newline at end of file
diff --git a/tests/php/extra/test.cfg b/tests/php/extra/test.cfg
deleted file mode 100644
index c6011d6..0000000
--- a/tests/php/extra/test.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-DEFAULT:
- extensions:
- - extra
- normalize: True
- input_ext: .text
- output_ext: .xhtml
- skip: True
diff --git a/tests/php/test.cfg b/tests/php/test.cfg
deleted file mode 100644
index 70c2601..0000000
--- a/tests/php/test.cfg
+++ /dev/null
@@ -1,50 +0,0 @@
-DEFAULT:
- normalize: True
- input_ext: .text
- output_ext: .xhtml
- #skip: True
-
-Quotes in attributes:
- # attributes get output in differant order
- skip: True
-
-Inline HTML (Span):
- # Backtick in raw HTML attribute TODO: fixme
- skip: True
-
-Backslash escapes:
- # Weird whitespace issue in output
- skip: True
-
-Ins & del:
- # Our behavior follows markdown.pl I think PHP is wrong here
- skip: True
-
-Auto Links:
- # TODO: fix raw HTML so is doesn't match <hr@example.com> as a <hr>.
- skip: True
-
-Empty List Item:
- # We match markdown.pl here. Maybe someday we'll support this
- skip: True
-
-Headers:
- # TODO: fix headers to not require blank line before
- skip: True
-
-Mixed OLs and ULs:
- # We match markdown.pl here. I think PHP is wrong here
- skip: True
-
-Emphasis:
- # We have various minor differances in combined & incorrect em markup.
- # Maybe fix a few of them - but most aren't too important
- skip: True
-
-Code block in a list item:
- # We match markdown.pl - not sure how php gets that output??
- skip: True
-
-PHP-Specific Bugs:
- # Not sure what to make of the escaping stuff here. Why is PHP not removing a blackslash?
- skip: True
diff --git a/tests/pl/Tests_2004/test.cfg b/tests/pl/Tests_2004/test.cfg
deleted file mode 100644
index 80f48e5..0000000
--- a/tests/pl/Tests_2004/test.cfg
+++ /dev/null
@@ -1,10 +0,0 @@
-DEFAULT:
- input_ext: .text
- normalize: True
- # comment out next line to run these tests
- #skip: True
-
-Yuri-Footnotes:
- extensions: footnotes
- skip: True
-
diff --git a/tests/pl/Tests_2007/test.cfg b/tests/pl/Tests_2007/test.cfg
deleted file mode 100644
index 097aa0d..0000000
--- a/tests/pl/Tests_2007/test.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-DEFAULT:
- input_ext: .text
- normalize: True
- # comment out next line to run these tests
- #skip: True
-
-Images:
- # the attributes don't get ordered the same so we skip this
- skip: True
-
-Code Blocks:
- # some weird whitespace issue
- skip: True
-
-Links, reference style:
- # weird issue with nested brackets TODO: fixme
- skip: True
-
-Backslash escapes:
- # backticks in raw html attributes TODO: fixme
- skip: True
-
-Code Spans:
- # more backticks in raw html attributes TODO: fixme
- skip: True
diff --git a/tests/plugins.py b/tests/plugins.py
deleted file mode 100644
index 4e7af97..0000000
--- a/tests/plugins.py
+++ /dev/null
@@ -1,127 +0,0 @@
-import traceback
-from nose.plugins import Plugin
-from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin
-
-
-class MarkdownSyntaxError(Exception):
- pass
-
-
-class Markdown(ErrorClassPlugin):
- """ Add MarkdownSyntaxError and ensure proper formatting. """
- mdsyntax = ErrorClass(
- MarkdownSyntaxError,
- label='MarkdownSyntaxError',
- 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__ == 'MarkdownSyntaxError':
- 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 list(result.errorClasses.keys()):
- storage, label, isfail = result.errorClasses[cls]
- if len(storage):
- 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('test-output.html', 'w')
- for l in self.html:
- f.write(l)
- f.close()
-
- def formatErr(self, err):
- exctype, value, tb = err
- if not isinstance(value, exctype):
- value = exctype(value)
- 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
deleted file mode 100644
index 4e1720e..0000000
--- a/tests/safe_mode/test.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-DEFAULT:
- safe_mode: escape
-
-remove:
- safe_mode: remove
-
-replace:
- safe_mode: replace
diff --git a/tests/test_legacy.py b/tests/test_legacy.py
new file mode 100644
index 0000000..17c4282
--- /dev/null
+++ b/tests/test_legacy.py
@@ -0,0 +1,213 @@
+from markdown.test_tools import LegacyTestCase, Kwargs
+import os
+import warnings
+
+# Warnings should cause tests to fail...
+warnings.simplefilter('error')
+# Except for the warnings that shouldn't
+warnings.filterwarnings('default', category=PendingDeprecationWarning)
+warnings.filterwarnings('default', category=DeprecationWarning, module='markdown')
+
+parent_test_dir = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestBasic(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'basic')
+
+
+class TestMisc(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'misc')
+
+
+class TestOptions(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'options')
+
+ lazy_ol_off = Kwargs(lazy_ol=False)
+
+ html4 = Kwargs(output_format='html4')
+
+ no_attributes = Kwargs(enable_attributes=False)
+
+ no_smart_emphasis = Kwargs(smart_emphasis=False)
+
+
+class TestSafeMode(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'safe_mode')
+ default_kwargs = Kwargs(safe_mode='escape')
+
+ remove = Kwargs(safe_mode='remove')
+
+ replace = Kwargs(safe_mode='replace')
+
+
+class TestPhp(LegacyTestCase):
+ """
+ Notes on "excluded" tests:
+
+ Quotes in attributes: attributes get output in differant order
+
+ Inline HTML (Span): Backtick in raw HTML attribute TODO: fixme
+
+ Backslash escapes: Weird whitespace issue in output
+
+ Ins & del: Our behavior follows markdown.pl I think PHP is wrong here
+
+ Auto Links: TODO: fix raw HTML so is doesn't match <hr@example.com> as a <hr>.
+
+ Empty List Item: We match markdown.pl here. Maybe someday we'll support this
+
+ Headers: TODO: fix headers to not require blank line before
+
+ Mixed OLs and ULs: We match markdown.pl here. I think PHP is wrong here
+
+ Emphasis: We have various minor differances in combined & incorrect em markup.
+ Maybe fix a few of them - but most aren't too important
+
+ Code block in a list item: We match markdown.pl - not sure how php gets that output??
+
+ PHP-Specific Bugs: Not sure what to make of the escaping stuff here.
+ Why is PHP not removing a blackslash?
+ """
+ location = os.path.join(parent_test_dir, 'php')
+ normalize = True
+ input_ext = '.text'
+ output_ext = '.xhtml'
+ exclude = [
+ 'Quotes_in_attributes',
+ 'Inline_HTML_(Span)',
+ 'Backslash_escapes',
+ 'Ins_&_del',
+ 'Auto_Links',
+ 'Empty_List_Item',
+ 'Headers',
+ 'Mixed_OLs_and_ULs',
+ 'Emphasis',
+ 'Code_block_in_a_list_item',
+ 'PHP_Specific_Bugs'
+ ]
+
+
+# class TestPhpExtra(LegacyTestCase):
+# location = os.path.join(parent_test_dir, 'php/extra')
+# normalize = True
+# input_ext = '.text'
+# output_ext = '.xhtml'
+# default_kwargs = Kwargs(extensions=['extra'])
+
+
+class TestPl2004(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'pl/Tests_2004')
+ normalize = True
+ input_ext = '.text'
+ exclude = ['Yuri_Footnotes']
+
+
+class TestPl2007(LegacyTestCase):
+ """
+ Notes on "excluded" tests:
+
+ Images: the attributes don't get ordered the same so we skip this
+
+ Code Blocks: some weird whitespace issue
+
+ Links, reference style: weird issue with nested brackets TODO: fixme
+
+ Backslash escapes: backticks in raw html attributes TODO: fixme
+
+ Code Spans: more backticks in raw html attributes TODO: fixme
+ """
+ location = os.path.join(parent_test_dir, 'pl/Tests_2007')
+ normalize = True
+ input_ext = '.text'
+ exclude = [
+ 'Images',
+ 'Code_Blocks',
+ 'Links,_reference_style',
+ 'Backslash_escapes',
+ 'Code_Spans'
+ ]
+
+
+class TestExtensions(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'extensions')
+ exclude = ['codehilite']
+
+ attr_list = Kwargs(
+ extensions=[
+ 'markdown.extensions.attr_list',
+ 'markdown.extensions.def_list',
+ 'markdown.extensions.smarty'
+ ]
+ )
+
+ codehilite = Kwargs(extensions=['markdown.extensions.codehilite'])
+
+ toc = Kwargs(extensions=['markdown.extensions.toc'])
+
+ toc_invalid = Kwargs(extensions=['markdown.extensions.toc'])
+
+ toc_out_of_order = Kwargs(extensions=['markdown.extensions.toc'])
+
+ toc_nested = Kwargs(
+ extensions=['markdown.extensions.toc'],
+ extension_configs={'markdown.extensions.toc': {'permalink': True}}
+ )
+
+ toc_nested2 = Kwargs(
+ extensions=['markdown.extensions.toc'],
+ extension_configs={'markdown.extensions.toc': {'permalink': "[link]"}}
+ )
+
+ toc_nested_list = Kwargs(extensions=['markdown.extensions.toc'])
+
+ wikilinks = Kwargs(extensions=['markdown.extensions.wikilinks'])
+
+ fenced_code = Kwargs(extensions=['markdown.extensions.fenced_code'])
+
+ github_flavored = Kwargs(extensions=['markdown.extensions.fenced_code'])
+
+ sane_lists = Kwargs(extensions=['markdown.extensions.sane_lists'])
+
+ nl2br_w_attr_list = Kwargs(
+ extensions=[
+ 'markdown.extensions.nl2br',
+ 'markdown.extensions.attr_list'
+ ]
+ )
+
+ admonition = Kwargs(extensions=['markdown.extensions.admonition'])
+
+ smarty = Kwargs(
+ extensions=['markdown.extensions.smarty'],
+ extension_configs={'markdown.extensions.smarty': {'smart_angled_quotes': True}}
+ )
+
+
+class TestExtensionsExtra(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'extensions/extra')
+ default_kwargs = Kwargs(extensions=['markdown.extensions.extra'])
+
+ loose_def_list = Kwargs(extensions=['markdown.extensions.def_list'])
+
+ simple_def_lists = Kwargs(extensions=['markdown.extensions.def_list'])
+
+ abbr = Kwargs(extensions=['markdown.extensions.abbr'])
+
+ footnotes = Kwargs(extensions=['markdown.extensions.footnotes'])
+
+ tables = Kwargs(extensions=['markdown.extensions.tables'])
+
+ tables_and_attr_list = Kwargs(
+ extensions=['markdown.extensions.tables', 'markdown.extensions.attr_list']
+ )
+
+ extra_config = Kwargs(
+ extensions=['markdown.extensions.extra'],
+ extension_configs={
+ 'markdown.extensions.extra': {
+ 'markdown.extensions.footnotes': {
+ 'PLACE_MARKER': '~~~placemarker~~~'
+ }
+ }
+ }
+ )
diff --git a/tox.ini b/tox.ini
index 89cc397..7a415bf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,12 +3,12 @@ envlist = py27, py32, py33, py34, py35, py36, pypy, flake8, checkspelling
[testenv]
deps = -rtest-requirements.txt
-commands = coverage run --source=markdown {toxinidir}/run-tests.py {posargs}
+commands = coverage run --source=markdown -m unittest discover {toxinidir}/tests
coverage report --show-missing
[testenv:flake8]
deps = flake8
-commands = flake8 {toxinidir}/markdown {toxinidir}/tests {toxinidir}/setup.py {toxinidir}/run-tests.py
+commands = flake8 {toxinidir}/markdown {toxinidir}/tests {toxinidir}/setup.py
[testenv:checkspelling]
deps =