support for new python.org and pep2pyramid.py
[docutils.git] / test / test_functional.py
blobdcec9cf4503eb0a1d32cdf42665fa485e2e6ccae
1 #!/usr/bin/env python
3 # Author: Felix Wiemann
4 # Contact: Felix_Wiemann@ososo.de
5 # Revision: $Revision$
6 # Date: $Date$
7 # Copyright: This module has been placed in the public domain.
9 """
10 Perform tests with the data in the functional/ directory.
12 Read README.txt for details on how this is done.
13 """
15 import sys
16 import os
17 import os.path
18 import shutil
19 import unittest
20 import difflib
21 import DocutilsTestSupport # must be imported before docutils
22 import docutils
23 import docutils.core
26 datadir = 'functional'
27 """The directory to store the data needed for the functional tests."""
30 def join_path(*args):
31 return '/'.join(args) or '.'
34 class FunctionalTestSuite(DocutilsTestSupport.CustomTestSuite):
36 """Test suite containing test cases for all config files."""
38 def __init__(self):
39 """Process all config files in functional/tests/."""
40 DocutilsTestSupport.CustomTestSuite.__init__(self)
41 os.chdir(DocutilsTestSupport.testroot)
42 self.clear_output_directory()
43 self.added = 0
44 os.path.walk(join_path(datadir, 'tests'), self.walker, None)
45 assert self.added, 'No functional tests found.'
47 def clear_output_directory(self):
48 files = os.listdir(os.path.join('functional', 'output'))
49 for f in files:
50 if f in ('README.txt', '.svn', 'CVS'):
51 continue # don't touch the infrastructure
52 path = os.path.join('functional', 'output', f)
53 if os.path.isdir(path):
54 shutil.rmtree(path)
55 else:
56 os.remove(path)
58 def walker(self, dummy, dirname, names):
59 """
60 Process all config files among `names` in `dirname`.
62 This is a helper function for os.path.walk. A config file is
63 a Python file (*.py) which sets several variables.
64 """
65 for name in names:
66 if name.endswith('.py') and not name.startswith('_'):
67 config_file_full_path = join_path(dirname, name)
68 self.addTestCase(FunctionalTestCase, 'test', None, None,
69 id=config_file_full_path,
70 configfile=config_file_full_path)
71 self.added += 1
74 class FunctionalTestCase(DocutilsTestSupport.CustomTestCase):
76 """Test case for one config file."""
78 def __init__(self, *args, **kwargs):
79 """Set self.configfile, pass arguments to parent __init__."""
80 self.configfile = kwargs['configfile']
81 del kwargs['configfile']
82 DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
84 def shortDescription(self):
85 return 'test_functional.py: ' + self.configfile
87 def test(self):
88 """Process self.configfile."""
89 os.chdir(DocutilsTestSupport.testroot)
90 # Keyword parameters for publish_file:
91 namespace = {}
92 # Initialize 'settings_overrides' for test settings scripts,
93 # and disable configuration files:
94 namespace['settings_overrides'] = {'_disable_config': 1}
95 # Read the variables set in the default config file and in
96 # the current config file into namespace:
97 execfile(join_path(datadir, 'tests', '_default.py'), namespace)
98 execfile(self.configfile, namespace)
99 # Check for required settings:
100 assert namespace.has_key('test_source'),\
101 "No 'test_source' supplied in " + self.configfile
102 assert namespace.has_key('test_destination'),\
103 "No 'test_destination' supplied in " + self.configfile
104 # Set source_path and destination_path if not given:
105 namespace.setdefault('source_path',
106 join_path(datadir, 'input',
107 namespace['test_source']))
108 # Path for actual output:
109 namespace.setdefault('destination_path',
110 join_path(datadir, 'output',
111 namespace['test_destination']))
112 # Path for expected output:
113 expected_path = join_path(datadir, 'expected',
114 namespace['test_destination'])
115 # shallow copy of namespace to minimize:
116 params = namespace.copy()
117 # remove unneeded parameters:
118 del params['test_source']
119 del params['test_destination']
120 # Delete private stuff like params['__builtins__']:
121 for key in params.keys():
122 if key.startswith('_'):
123 del params[key]
124 # Get output (automatically written to the output/ directory
125 # by publish_file):
126 output = docutils.core.publish_file(**params)
127 # Get the expected output *after* writing the actual output.
128 self.assert_(os.access(expected_path, os.R_OK),\
129 'Cannot find expected output at\n' + expected_path)
130 f = open(expected_path, 'rU')
131 expected = f.read()
132 f.close()
133 diff = ('The expected and actual output differs.\n'
134 'Please compare the expected and actual output files:\n'
135 ' diff %s %s\n'
136 'If the actual output is correct, please replace the\n'
137 'expected output and check it in to Subversion:\n'
138 ' mv %s %s\n'
139 ' svn commit -m "<comment>" %s'
140 % (expected_path, params['destination_path'],
141 params['destination_path'], expected_path, expected_path))
142 try:
143 self.assertEquals(output, expected, diff)
144 except AssertionError:
145 if hasattr(difflib, 'unified_diff'):
146 # Generate diff if unified_diff available:
147 diff = ''.join(
148 difflib.unified_diff(expected.splitlines(1),
149 output.splitlines(1),
150 expected_path,
151 params['destination_path']))
152 print >>sys.stderr, '\n%s:' % (self,)
153 print >>sys.stderr, diff
154 raise
155 # Execute optional function containing extra tests:
156 if namespace.has_key('_test_more'):
157 namespace['_test_more'](join_path(datadir, 'expected'),
158 join_path(datadir, 'output'),
159 self, namespace)
162 def suite():
163 return FunctionalTestSuite()
166 if __name__ == '__main__':
167 unittest.main(defaultTest='suite')