Embed SVG images as ``<svg>`` instead of data-URI.
[docutils.git] / docutils / test / test_functional.py
blob382cc2b65880948d5d80d8a19c72e43ef2ade0de
1 #!/usr/bin/env python3
2 # $Id$
3 # Author: Lea Wiemann <LeWiemann@gmail.com>
4 # Copyright: This module has been placed in the public domain.
6 """
7 Perform tests with the data in the functional/ directory.
9 Please see the documentation on `functional testing`__ for details.
11 __ ../../docs/dev/testing.html#functional
12 """
14 import difflib
15 from pathlib import Path
16 import shutil
17 import sys
18 import unittest
20 if __name__ == '__main__':
21 # prepend the "docutils root" to the Python library path
22 # so we import the local `docutils` package.
23 sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
25 from docutils import core, SettingsSpec
27 FUNCTIONAL = Path('functional')
28 EXPECTED = FUNCTIONAL / 'expected'
29 INPUT = FUNCTIONAL / 'input'
30 OUTPUT = FUNCTIONAL / 'output'
31 TESTS = FUNCTIONAL / 'tests'
33 NO_EXPECTED_TEMPLATE = """\
34 Cannot find expected output at {exp}
35 If the output in {out}
36 is correct, move it to the expected/ dir and check it in:
38 mv {out} {exp}
39 svn add {exp}
40 svn commit -m "<comment>" {exp}
41 """
43 EXPECTED_OUTPUT_DIFFERS_TEMPLATE = """\
44 Expected and actual output differ.
46 {diff}
48 If the actual output is correct, please replace the
49 expected output and check it in:
51 mv {out} {exp}
52 svn add {exp}
53 svn commit -m "<comment>" {exp}
54 """
56 # Default settings for functional tests.
57 # Override "factory defaults",
58 # overridden by `settings_overrides` in the individual tests.
59 # cf. docs/api/runtime-settings.html#settings-priority
60 functional_tests_settings_spec = SettingsSpec()
61 functional_tests_settings_spec.settings_default_overrides = {
62 '_disable_config': True,
63 'halt_level': 5,
64 'warning_stream': '',
65 'input_encoding': 'utf-8', # skip auto-detection
66 'embed_stylesheet': False,
67 'syntax_highlight': 'none' # avoid "Pygments not found" warning
71 class FunctionalTests(unittest.TestCase):
73 """Test case for one config file."""
75 def setUp(self):
76 """Clear output directory."""
77 for entry in OUTPUT.rglob('*'):
78 if entry.is_dir():
79 shutil.rmtree(entry)
80 elif entry.name != 'README.txt':
81 entry.unlink()
83 def test_functional(self):
84 """Process test file."""
85 for test_file in TESTS.glob("*.py"):
86 with self.subTest(test_file=test_file.as_posix()):
87 namespace = {}
88 # Load variables from the current test file into the namespace
89 exec(test_file.read_text(encoding='utf-8'), namespace)
90 del namespace['__builtins__'] # clean-up
92 # Full source, generated output, and expected output paths
93 source_path = INPUT / namespace.pop('test_source')
94 destination_path = OUTPUT / namespace['test_destination']
95 expected_path = EXPECTED / namespace.pop('test_destination')
97 # Get output (automatically written to the output/ directory
98 # by publish_file):
99 output = core.publish_file(
100 **namespace,
101 source_path=source_path.as_posix(),
102 destination_path=destination_path.as_posix(),
103 settings_spec=functional_tests_settings_spec,
106 # Get the expected output *after* writing the actual output.
107 try:
108 expected = expected_path.read_text(encoding='utf-8')
109 except OSError as err:
110 raise OSError(NO_EXPECTED_TEMPLATE.format(
111 exp=expected_path, out=destination_path)
112 ) from err
114 if output != expected:
115 diff = ''.join(difflib.unified_diff(
116 expected.splitlines(True), output.splitlines(True),
117 expected_path.as_posix(), destination_path.as_posix()))
118 raise AssertionError(
119 EXPECTED_OUTPUT_DIFFERS_TEMPLATE.format(
120 diff=diff, exp=expected_path, out=destination_path)
124 if __name__ == '__main__':
125 unittest.main()