4 # Author: Lea Wiemann <LeWiemann@gmail.com>
5 # Copyright: This module has been placed in the public domain.
8 Perform tests with the data in the functional/ directory.
10 Read README.txt for details on how this is done.
19 import DocutilsTestSupport
# must be imported before docutils
24 datadir
= 'functional'
25 """The directory to store the data needed for the functional tests."""
29 return '/'.join(args
) or '.'
32 class FunctionalTestSuite(DocutilsTestSupport
.CustomTestSuite
):
34 """Test suite containing test cases for all config files."""
37 """Process all config files in functional/tests/."""
38 DocutilsTestSupport
.CustomTestSuite
.__init
__(self
)
39 os
.chdir(DocutilsTestSupport
.testroot
)
40 self
.clear_output_directory()
43 for root
, dirs
, files
in os
.walk(join_path(datadir
, 'tests')):
44 # Process all config files among `names` in `dirname`. A config
45 # file is a Python file (*.py) which sets several variables.
47 if name
.endswith('.py') and not name
.startswith('_'):
48 config_file_full_path
= join_path(root
, name
)
49 self
.addTestCase(FunctionalTestCase
, 'test', None, None,
50 id=config_file_full_path
,
51 configfile
=config_file_full_path
)
53 except (AttributeError): # python2.2 does not have os.walk
54 os
.path
.walk(join_path(datadir
, 'tests'), self
.walker
, None)
55 assert self
.added
, 'No functional tests found.'
57 def clear_output_directory(self
):
58 files
= os
.listdir(os
.path
.join('functional', 'output'))
60 if f
in ('README.txt', '.svn', 'CVS'):
61 continue # don't touch the infrastructure
62 path
= os
.path
.join('functional', 'output', f
)
63 if os
.path
.isdir(path
):
68 def walker(self
, dummy
, dirname
, names
):
70 Process all config files among `names` in `dirname`.
72 This is a helper function for os.path.walk. A config file is
73 a Python file (*.py) which sets several variables.
76 if name
.endswith('.py') and not name
.startswith('_'):
77 config_file_full_path
= join_path(dirname
, name
)
78 self
.addTestCase(FunctionalTestCase
, 'test', None, None,
79 id=config_file_full_path
,
80 configfile
=config_file_full_path
)
84 class FunctionalTestCase(DocutilsTestSupport
.CustomTestCase
):
86 """Test case for one config file."""
88 def __init__(self
, *args
, **kwargs
):
89 """Set self.configfile, pass arguments to parent __init__."""
90 self
.configfile
= kwargs
['configfile']
91 del kwargs
['configfile']
92 DocutilsTestSupport
.CustomTestCase
.__init
__(self
, *args
, **kwargs
)
94 def shortDescription(self
):
95 return 'test_functional.py: ' + self
.configfile
98 """Process self.configfile."""
99 os
.chdir(DocutilsTestSupport
.testroot
)
100 # Keyword parameters for publish_file:
102 # Initialize 'settings_overrides' for test settings scripts,
103 # and disable configuration files:
104 namespace
['settings_overrides'] = {'_disable_config': 1}
105 # Read the variables set in the default config file and in
106 # the current config file into namespace:
107 defaultpy
= open(join_path(datadir
, 'tests', '_default.py')).read()
108 exec(defaultpy
, namespace
)
109 exec(open(self
.configfile
).read(), namespace
)
110 # Check for required settings:
111 assert 'test_source' in namespace
,\
112 "No 'test_source' supplied in " + self
.configfile
113 assert 'test_destination' in namespace
,\
114 "No 'test_destination' supplied in " + self
.configfile
115 # Set source_path and destination_path if not given:
116 namespace
.setdefault('source_path',
117 join_path(datadir
, 'input',
118 namespace
['test_source']))
119 # Path for actual output:
120 namespace
.setdefault('destination_path',
121 join_path(datadir
, 'output',
122 namespace
['test_destination']))
123 # Path for expected output:
124 expected_path
= join_path(datadir
, 'expected',
125 namespace
['test_destination'])
126 # shallow copy of namespace to minimize:
127 params
= namespace
.copy()
128 # remove unneeded parameters:
129 del params
['test_source']
130 del params
['test_destination']
131 # Delete private stuff like params['__builtins__']:
132 for key
in params
.keys():
133 if key
.startswith('_'):
135 # Get output (automatically written to the output/ directory
137 output
= docutils
.core
.publish_file(**params
)
138 # Get the expected output *after* writing the actual output.
139 self
.assert_(os
.access(expected_path
, os
.R_OK
),\
140 'Cannot find expected output at\n' + expected_path
)
141 f
= open(expected_path
, 'rU')
144 diff
= ('The expected and actual output differs.\n'
145 'Please compare the expected and actual output files:\n'
147 'If the actual output is correct, please replace the\n'
148 'expected output and check it in to Subversion:\n'
150 ' svn commit -m "<comment>" %s'
151 % (expected_path
, params
['destination_path'],
152 params
['destination_path'], expected_path
, expected_path
))
154 self
.assertEquals(output
, expected
, diff
)
155 except AssertionError:
156 if hasattr(difflib
, 'unified_diff'):
157 # Generate diff if unified_diff available:
159 difflib
.unified_diff(expected
.splitlines(1),
160 output
.splitlines(1),
162 params
['destination_path']))
163 print >>sys
.stderr
, '\n%s:' % (self
,)
164 print >>sys
.stderr
, diff
166 # Execute optional function containing extra tests:
167 if '_test_more' in namespace
:
168 namespace
['_test_more'](join_path(datadir
, 'expected'),
169 join_path(datadir
, 'output'),
174 return FunctionalTestSuite()
177 if __name__
== '__main__':
178 unittest
.main(defaultTest
='suite')