summaryrefslogtreecommitdiff
path: root/docutils/test
diff options
context:
space:
mode:
authoraa-turner <aa-turner@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2022-10-27 18:06:49 +0000
committeraa-turner <aa-turner@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2022-10-27 18:06:49 +0000
commit08fdfd19615e3713260816c8c72e781f29a9a390 (patch)
tree09d9ceef7134603c6721eba33e54371df99286f9 /docutils/test
parent2bbda825ef1d276e5cef415ae17ee4b984da0a7e (diff)
downloaddocutils-08fdfd19615e3713260816c8c72e781f29a9a390.tar.gz
Use subtests for the functional tests
git-svn-id: https://svn.code.sf.net/p/docutils/code/trunk@9181 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'docutils/test')
-rwxr-xr-xdocutils/test/test_functional.py223
1 files changed, 78 insertions, 145 deletions
diff --git a/docutils/test/test_functional.py b/docutils/test/test_functional.py
index 30a1e5584..a32206222 100755
--- a/docutils/test/test_functional.py
+++ b/docutils/test/test_functional.py
@@ -11,168 +11,101 @@ Please see the documentation on `functional testing`__ for details.
__ ../../docs/dev/testing.html#functional
"""
-import sys
-import os
-import os.path
+from pathlib import Path
import shutil
import unittest
-import difflib
-import DocutilsTestSupport # must be imported before docutils
-import docutils
-import docutils.core
-
-
-datadir = 'functional'
-"""The directory to store the data needed for the functional tests."""
-
-
-def join_path(*args):
- return '/'.join(args) or '.'
-
-
-class FunctionalTestSuite(DocutilsTestSupport.CustomTestSuite):
-
- """Test suite containing test cases for all config files."""
-
- def __init__(self):
- """Process all config files in functional/tests/."""
- super().__init__()
- self.clear_output_directory()
- self.added = 0
- for root, dirs, files in os.walk(join_path(datadir, 'tests')):
- # Process all config files among `names` in `dirname`. A config
- # file is a Python file (*.py) which sets several variables.
- for name in files:
- if name.endswith('.py') and not name.startswith('_'):
- config_file_full_path = join_path(root, name)
- self.addTestCase(FunctionalTestCase, 'test', None, None,
- id=config_file_full_path,
- configfile=config_file_full_path)
- self.added += 1
- assert self.added, 'No functional tests found.'
-
- def clear_output_directory(self):
- files = os.listdir(os.path.join('functional', 'output'))
- for f in files:
- if f in ('README.txt', '.svn', 'CVS'):
- continue # don't touch the infrastructure
- path = os.path.join('functional', 'output', f)
- if os.path.isdir(path):
- shutil.rmtree(path)
- else:
- os.remove(path)
-
-class FunctionalTestCase(DocutilsTestSupport.CustomTestCase):
+import docutils.core
- """Test case for one config file."""
+FUNCTIONAL = Path('functional')
+EXPECTED = FUNCTIONAL / 'expected'
+INPUT = FUNCTIONAL / 'input'
+OUTPUT = FUNCTIONAL / 'output'
+TESTS = FUNCTIONAL / 'tests'
- no_expected_template = """\
-Cannot find expected output at %(exp)s
-If the output in %(out)s
+NO_EXPECTED_TEMPLATE = """\
+Cannot find expected output at {exp}
+If the output in {out}
is correct, move it to the expected/ dir and check it in:
- mv %(out)s %(exp)s
- svn add %(exp)s
- svn commit -m "<comment>" %(exp)s"""
+ mv {out} {exp}
+ svn add {exp}
+ svn commit -m "<comment>" {exp}
+"""
- expected_output_differs_template = """\
+EXPECTED_OUTPUT_DIFFERS_TEMPLATE = """\
The expected and actual output differs.
Please compare the expected and actual output files:
- diff %(exp)s %(out)s\n'
+ diff {exp} {out}
If the actual output is correct, please replace the
expected output and check it in:
- mv %(out)s %(exp)s
- svn add %(exp)s
- svn commit -m "<comment>" %(exp)s"""
-
- def __init__(self, *args, configfile=None, **kwargs):
- """
- Set self.configfile, pass remaining arguments to parent.
-
- Requires keyword argument `configfile`.
-
- Note: the modified signature is incompatible with
- the "pytest" and "nose" frameworks.
- """ # cf. feature-request #81
-
- assert configfile is not None, 'required argument'
- self.configfile = configfile
- super().__init__(*args, **kwargs)
-
- def shortDescription(self):
- return 'test_functional.py: ' + self.configfile
-
- def test(self):
- """Process self.configfile."""
- # Keyword parameters for publish_file:
- namespace = {}
- with open(self.configfile, encoding='utf-8') as f:
- exec(f.read(), namespace)
- # Check for required settings:
- assert 'test_source' in namespace,\
- "No 'test_source' supplied in " + self.configfile
- assert 'test_destination' in namespace,\
- "No 'test_destination' supplied in " + self.configfile
- # Set source_path and destination_path if not given:
- namespace.setdefault('source_path',
- join_path(datadir, 'input',
- namespace['test_source']))
- # Path for actual output:
- namespace.setdefault('destination_path',
- join_path(datadir, 'output',
- namespace['test_destination']))
- # Path for expected output:
- expected_path = join_path(datadir, 'expected',
- namespace['test_destination'])
- # shallow copy of namespace to minimize:
- params = namespace.copy()
- # remove unneeded parameters:
- del params['test_source']
- del params['test_destination']
- # Delete private stuff like params['__builtins__']:
- for key in list(params.keys()):
- if key.startswith('_'):
- del params[key]
- # Get output (automatically written to the output/ directory
- # by publish_file):
- output = docutils.core.publish_file(**params)
- # Normalize line endings:
- output = '\n'.join(output.splitlines())
- # Get the expected output *after* writing the actual output.
- no_expected = self.no_expected_template % {
- 'exp': expected_path, 'out': params['destination_path']}
- self.assertTrue(os.access(expected_path, os.R_OK), no_expected)
- # samples are UTF-8 encoded. 'rb' leads to errors with Python 3!
- f = open(expected_path, 'r', encoding='utf-8')
- # Normalize line endings:
- expected = '\n'.join(f.read().splitlines())
- f.close()
-
- diff = self.expected_output_differs_template % {
- 'exp': expected_path, 'out': params['destination_path']}
- try:
- self.assertEqual(output, expected, diff)
- except AssertionError:
- diff = ''.join(difflib.unified_diff(
- expected.splitlines(True), output.splitlines(True),
- expected_path, params['destination_path']))
- print('\n%s:' % (self,), file=sys.stderr)
- print(diff, file=sys.stderr)
- raise
- # Execute optional function containing extra tests:
- if '_test_more' in namespace:
- namespace['_test_more'](join_path(datadir, 'expected'),
- join_path(datadir, 'output'),
- self, namespace)
+ mv {out} {exp}
+ svn add {exp}
+ svn commit -m "<comment>" {exp}
+"""
+
+class FunctionalTests(unittest.TestCase):
-def suite():
- return FunctionalTestSuite()
+ """Test case for one config file."""
+ maxDiff = None
+
+ def setUp(self):
+ """Clear output directory."""
+ for entry in OUTPUT.rglob('*'):
+ if entry.is_dir():
+ shutil.rmtree(entry)
+ elif entry.name != 'README.txt':
+ entry.unlink()
+
+ def test_functional(self):
+ """Process test file."""
+ for test_file in TESTS.glob("*.py"):
+ with self.subTest(test_file=test_file.as_posix()):
+ namespace = {}
+ # Load variables from the current test file into the namespace
+ exec(test_file.read_text(encoding='utf-8'), namespace)
+
+ # Full source, actual output, and expected output paths
+ source_path = INPUT / namespace['test_source']
+ destination_path = OUTPUT / namespace['test_destination']
+ expected_path = EXPECTED / namespace['test_destination']
+
+ # remove unneeded keys:
+ for key in 'test_source', 'test_destination', '__builtins__':
+ del namespace[key]
+ namespace = {k: v for k, v in namespace.items()
+ if not k.startswith('_')}
+
+ # Get output (automatically written to the output/ directory
+ # by publish_file):
+ output = docutils.core.publish_file(
+ **namespace,
+ source_path=source_path.as_posix(),
+ destination_path=destination_path.as_posix(),
+ )
+
+ # Get the expected output *after* writing the actual output.
+ try:
+ expected = expected_path.read_text(encoding='utf-8')
+ except OSError as err:
+ raise OSError(NO_EXPECTED_TEMPLATE.format(
+ exp=expected_path, out=destination_path)
+ ) from err
+
+ self.assertEqual(
+ output,
+ expected,
+ EXPECTED_OUTPUT_DIFFERS_TEMPLATE.format(
+ exp=expected_path, out=destination_path)
+ )
+ # Execute optional function containing extra tests:
+ if '_test_more' in namespace:
+ namespace['_test_more'](EXPECTED, OUTPUT, self, namespace)
if __name__ == '__main__':
- unittest.main(defaultTest='suite')
+ unittest.main()