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()
42 os
.path
.walk(join_path(datadir
, 'tests'), self
.walker
, None)
43 assert self
.added
, 'No functional tests found.'
45 def clear_output_directory(self
):
46 files
= os
.listdir(os
.path
.join('functional', 'output'))
48 if f
in ('README.txt', '.svn', 'CVS'):
49 continue # don't touch the infrastructure
50 path
= os
.path
.join('functional', 'output', f
)
51 if os
.path
.isdir(path
):
56 def walker(self
, dummy
, dirname
, names
):
58 Process all config files among `names` in `dirname`.
60 This is a helper function for os.path.walk. A config file is
61 a Python file (*.py) which sets several variables.
64 if name
.endswith('.py') and not name
.startswith('_'):
65 config_file_full_path
= join_path(dirname
, name
)
66 self
.addTestCase(FunctionalTestCase
, 'test', None, None,
67 id=config_file_full_path
,
68 configfile
=config_file_full_path
)
72 class FunctionalTestCase(DocutilsTestSupport
.CustomTestCase
):
74 """Test case for one config file."""
76 def __init__(self
, *args
, **kwargs
):
77 """Set self.configfile, pass arguments to parent __init__."""
78 self
.configfile
= kwargs
['configfile']
79 del kwargs
['configfile']
80 DocutilsTestSupport
.CustomTestCase
.__init
__(self
, *args
, **kwargs
)
82 def shortDescription(self
):
83 return 'test_functional.py: ' + self
.configfile
86 """Process self.configfile."""
87 os
.chdir(DocutilsTestSupport
.testroot
)
88 # Keyword parameters for publish_file:
90 # Initialize 'settings_overrides' for test settings scripts,
91 # and disable configuration files:
92 namespace
['settings_overrides'] = {'_disable_config': 1}
93 # Read the variables set in the default config file and in
94 # the current config file into namespace:
95 defaultpy
= open(join_path(datadir
, 'tests', '_default.py')).read()
96 exec(defaultpy
, namespace
)
97 exec(open(self
.configfile
).read(), namespace
)
98 # Check for required settings:
99 assert 'test_source' in namespace
,\
100 "No 'test_source' supplied in " + self
.configfile
101 assert 'test_destination' in namespace
,\
102 "No 'test_destination' supplied in " + self
.configfile
103 # Set source_path and destination_path if not given:
104 namespace
.setdefault('source_path',
105 join_path(datadir
, 'input',
106 namespace
['test_source']))
107 # Path for actual output:
108 namespace
.setdefault('destination_path',
109 join_path(datadir
, 'output',
110 namespace
['test_destination']))
111 # Path for expected output:
112 expected_path
= join_path(datadir
, 'expected',
113 namespace
['test_destination'])
114 # shallow copy of namespace to minimize:
115 params
= namespace
.copy()
116 # remove unneeded parameters:
117 del params
['test_source']
118 del params
['test_destination']
119 # Delete private stuff like params['__builtins__']:
120 for key
in params
.keys():
121 if key
.startswith('_'):
123 # Get output (automatically written to the output/ directory
125 output
= docutils
.core
.publish_file(**params
)
126 # Get the expected output *after* writing the actual output.
127 self
.assert_(os
.access(expected_path
, os
.R_OK
),\
128 'Cannot find expected output at\n' + expected_path
)
129 f
= open(expected_path
, 'rU')
132 diff
= ('The expected and actual output differs.\n'
133 'Please compare the expected and actual output files:\n'
135 'If the actual output is correct, please replace the\n'
136 'expected output and check it in to Subversion:\n'
138 ' svn commit -m "<comment>" %s'
139 % (expected_path
, params
['destination_path'],
140 params
['destination_path'], expected_path
, expected_path
))
142 self
.assertEquals(output
, expected
, diff
)
143 except AssertionError:
144 if hasattr(difflib
, 'unified_diff'):
145 # Generate diff if unified_diff available:
147 difflib
.unified_diff(expected
.splitlines(1),
148 output
.splitlines(1),
150 params
['destination_path']))
151 print >>sys
.stderr
, '\n%s:' % (self
,)
152 print >>sys
.stderr
, diff
154 # Execute optional function containing extra tests:
155 if '_test_more' in namespace
:
156 namespace
['_test_more'](join_path(datadir
, 'expected'),
157 join_path(datadir
, 'output'),
162 return FunctionalTestSuite()
165 if __name__
== '__main__':
166 unittest
.main(defaultTest
='suite')