78
89
def write(self, string):
96
class StandardTestCase(unittest.TestCase):
99
Helper class, providing the same interface as unittest.TestCase,
100
but with useful setUp and comparison methods.
106
def failUnlessEqual(self, first, second, msg=None):
107
"""Fail if the two objects are unequal as determined by the '=='
110
if not first == second:
111
raise self.failureException, \
112
(msg or '%s != %s' % _format_str(first, second))
114
def failIfEqual(self, first, second, msg=None):
115
"""Fail if the two objects are equal as determined by the '=='
119
raise self.failureException, \
120
(msg or '%s == %s' % _format_str(first, second))
122
# Synonyms for assertion methods
124
assertEqual = assertEquals = failUnlessEqual
126
assertNotEqual = assertNotEquals = failIfEqual
129
class CustomTestCase(StandardTestCase):
132
Helper class, providing extended functionality over unittest.TestCase.
134
The methods failUnlessEqual and failIfEqual have been overwritten
135
to provide better support for multi-line strings. Furthermore,
136
see the compare_output method and the parameter list of __init__.
139
compare = docutils_difflib.Differ().compare
140
"""Comparison method shared by all subclasses."""
142
def __init__(self, method_name, input, expected, id, run_in_debugger=0,
143
suite_settings=None):
145
Initialise the CustomTestCase.
149
method_name -- name of test method to run.
150
input -- input to the parser.
151
expected -- expected output from the parser.
152
id -- unique test identifier, used by the test framework.
153
run_in_debugger -- if true, run this test under the pdb debugger.
154
suite_settings -- settings overrides for this test suite.
158
self.expected = expected
159
self.run_in_debugger = run_in_debugger
160
self.suite_settings = suite_settings or {}
163
unittest.TestCase.__init__(self, method_name)
167
Return string conversion. Overridden to give test id, in addition to
170
return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
173
return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
175
def clear_roles(self):
176
# Language-specific roles and roles added by the
177
# "default-role" and "role" directives are currently stored
178
# globally in the roles._roles dictionary. This workaround
179
# empties that dictionary.
183
StandardTestCase.setUp(self)
186
def compare_output(self, input, output, expected):
187
"""`input`, `output`, and `expected` should all be strings."""
188
if isinstance(input, UnicodeType):
189
input = input.encode('raw_unicode_escape')
190
if isinstance(output, UnicodeType):
191
output = output.encode('raw_unicode_escape')
192
if isinstance(expected, UnicodeType):
193
expected = expected.encode('raw_unicode_escape')
195
self.assertEquals(output, expected)
196
except AssertionError, error:
197
print >>sys.stderr, '\n%s\ninput:' % (self,)
198
print >>sys.stderr, input
200
comparison = ''.join(self.compare(expected.splitlines(1),
201
output.splitlines(1)))
202
print >>sys.stderr, '-: expected\n+: output'
203
print >>sys.stderr, comparison
204
except AttributeError: # expected or output not a string
205
# alternative output for non-strings:
206
print >>sys.stderr, 'expected: %r' % expected
207
print >>sys.stderr, 'output: %r' % output
82
211
class CustomTestSuite(unittest.TestSuite):
85
A collection of custom TestCases.
214
A collection of CustomTestCases.
216
Provides test suite ID generation and a method for adding test cases.
127
259
def addTestCase(self, test_case_class, method_name, input, expected,
128
id=None, run_in_debugger=0, short_description=None,
260
id=None, run_in_debugger=0, **kwargs):
131
Create a custom TestCase in the CustomTestSuite.
262
Create a CustomTestCase in the CustomTestSuite.
132
263
Also return it, just in case.
267
test_case_class -- the CustomTestCase to add
268
method_name -- a string; CustomTestCase.method_name is the test
138
269
input -- input to the parser.
139
270
expected -- expected output from the parser.
140
271
id -- unique test identifier, used by the test framework.
141
272
run_in_debugger -- if true, run this test under the pdb debugger.
142
short_description -- override to default test description.
144
274
if id is None: # generate id if required
145
275
id = self.next_test_case_id
146
276
self.next_test_case_id += 1
147
277
# test identifier will become suiteid.testid
148
278
tcid = '%s: %s' % (self.id, id)
279
# suite_settings may be passed as a parameter;
280
# if not, set from attribute:
281
kwargs.setdefault('suite_settings', self.suite_settings)
149
282
# generate and add test case
150
283
tc = test_case_class(method_name, input, expected, tcid,
151
run_in_debugger=run_in_debugger,
152
short_description=short_description,
284
run_in_debugger=run_in_debugger, **kwargs)
161
class CustomTestCase(unittest.TestCase):
163
compare = difflib.Differ().compare
164
"""Comparison method shared by all subclasses."""
166
def __init__(self, method_name, input, expected, id,
167
run_in_debugger=0, short_description=None):
169
Initialise the CustomTestCase.
173
method_name -- name of test method to run.
174
input -- input to the parser.
175
expected -- expected output from the parser.
176
id -- unique test identifier, used by the test framework.
177
run_in_debugger -- if true, run this test under the pdb debugger.
178
short_description -- override to default test description.
182
self.expected = expected
183
self.run_in_debugger = run_in_debugger
185
unittest.TestCase.__init__(self, method_name)
189
Return string conversion. Overridden to give test id, in addition to
192
return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
195
return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
197
def compare_output(self, input, output, expected):
198
"""`input`, `output`, and `expected` should all be strings."""
199
if type(input) == UnicodeType:
200
input = input.encode('raw_unicode_escape')
201
if type(output) == UnicodeType:
202
output = output.encode('raw_unicode_escape')
203
if type(expected) == UnicodeType:
204
expected = expected.encode('raw_unicode_escape')
206
self.assertEquals('\n' + output, '\n' + expected)
207
except AssertionError:
208
print >>sys.stderr, '\n%s\ninput:' % (self,)
209
print >>sys.stderr, input
210
print >>sys.stderr, '-: expected\n+: output'
211
print >>sys.stderr, ''.join(self.compare(expected.splitlines(1),
212
output.splitlines(1)))
216
print >>sys.stderr, '%s: Test skipped' % self
219
class TransformTestSuite(CustomTestSuite):
222
A collection of TransformTestCases.
224
A TransformTestSuite instance manufactures TransformTestCases,
225
keeps track of them, and provides a shared test fixture (a-la
229
def __init__(self, parser):
231
"""Parser shared by all test cases."""
233
CustomTestSuite.__init__(self)
235
def generateTests(self, dict, dictname='totest',
236
testmethod='test_transforms'):
238
Stock the suite with test cases generated from a test data dictionary.
240
Each dictionary key (test type's name) maps to a list of transform
241
classes and list of tests. Each test is a list: input, expected
242
output, optional modifier. The optional third entry, a behavior
243
modifier, can be 0 (temporarily disable this test) or 1 (run this test
244
under the pdb debugger). Tests should be self-documenting and not
245
require external comments.
247
for name, (transforms, cases) in dict.items():
248
for casenum in range(len(cases)):
249
case = cases[casenum]
257
TransformTestCase, testmethod,
258
transforms=transforms, parser=self.parser,
259
input=case[0], expected=case[1],
260
id='%s[%r][%s]' % (dictname, name, casenum),
261
run_in_debugger=run_in_debugger)
264
292
class TransformTestCase(CustomTestCase):
324
356
self.compare_output(self.input, output, self.expected)
359
class TransformTestSuite(CustomTestSuite):
362
A collection of TransformTestCases.
364
A TransformTestSuite instance manufactures TransformTestCases,
365
keeps track of them, and provides a shared test fixture (a-la
369
def __init__(self, parser, suite_settings=None):
371
"""Parser shared by all test cases."""
373
CustomTestSuite.__init__(self, suite_settings=suite_settings)
375
def generateTests(self, dict, dictname='totest',
376
testmethod='test_transforms'):
378
Stock the suite with test cases generated from a test data dictionary.
380
Each dictionary key (test type's name) maps to a tuple, whose
381
first item is a list of transform classes and whose second
382
item is a list of tests. Each test is a list: input, expected
383
output, optional modifier. The optional third entry, a
384
behavior modifier, can be 0 (temporarily disable this test) or
385
1 (run this test under the pdb debugger). Tests should be
386
self-documenting and not require external comments.
388
for name, (transforms, cases) in dict.items():
389
for casenum in range(len(cases)):
390
case = cases[casenum]
393
# TODO: (maybe) change the 3rd argument to a dict, so it
394
# can handle more cases by keyword ('disable', 'debug',
395
# 'settings'), here and in other generateTests methods.
396
# But there's also the method that
397
# HtmlPublishPartsTestSuite uses <DJG>
403
TransformTestCase, testmethod,
404
transforms=transforms, parser=self.parser,
405
input=case[0], expected=case[1],
406
id='%s[%r][%s]' % (dictname, name, casenum),
407
run_in_debugger=run_in_debugger)
327
410
class ParserTestCase(CustomTestCase):
597
687
reader_name='standalone',
598
688
parser_name='restructuredtext',
599
689
writer_name=self.writer_name,
691
settings_overrides=self.suite_settings)
601
692
self.compare_output(self.input, output, self.expected)
604
class LatexWriterPublishTestCase(WriterPublishTestCase):
607
Test case for Latex writer.
610
writer_name = 'latex'
613
class PseudoXMLWriterPublishTestCase(WriterPublishTestCase):
616
Test case for pseudo-XML writer.
619
writer_name = 'pseudoxml'
622
695
class PublishTestSuite(CustomTestSuite):
625
'latex': LatexWriterPublishTestCase,
626
'pseudoxml': PseudoXMLWriterPublishTestCase,
629
def __init__(self, writer_name):
631
`writer_name` is the name of the writer
632
to use. It must be a key in `TEST_CLASSES`.
634
CustomTestSuite.__init__(self)
635
self.test_class = self.TEST_CLASSES[writer_name]
697
def __init__(self, writer_name, suite_settings=None):
699
`writer_name` is the name of the writer to use.
701
CustomTestSuite.__init__(self, suite_settings=suite_settings)
702
self.test_class = WriterPublishTestCase
703
self.writer_name = writer_name
637
705
def generateTests(self, dict, dictname='totest'):
638
706
for name, cases in dict.items():
648
716
self.test_class, 'test_publish',
649
717
input=case[0], expected=case[1],
650
718
id='%s[%r][%s]' % (dictname, name, casenum),
651
run_in_debugger=run_in_debugger)
719
run_in_debugger=run_in_debugger,
720
# Passed to constructor of self.test_class:
721
writer_name=self.writer_name)
654
724
class HtmlPublishPartsTestSuite(CustomTestSuite):
656
726
def generateTests(self, dict, dictname='totest'):
657
727
for name, (settings_overrides, cases) in dict.items():
728
settings = self.suite_settings.copy()
729
settings.update(settings_overrides)
658
730
for casenum in range(len(cases)):
659
731
case = cases[casenum]
660
732
run_in_debugger = 0
695
764
parser_name='restructuredtext',
696
765
writer_name=self.writer_name,
697
766
settings_spec=self,
698
settings_overrides=self.settings_overrides)
767
settings_overrides=self.suite_settings)
699
768
output = self.format_output(parts)
700
769
# interpolate standard variables:
701
770
expected = self.expected % {'version': docutils.__version__}
702
771
self.compare_output(self.input, output, expected)
704
standard_meta_value = """\
705
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
706
<meta name="generator" content="Docutils %s: http://docutils.sourceforge.net/" />
707
""" % docutils.__version__
708
standard_stylesheet_value = ('<link rel="stylesheet" href="default.css" '
709
'type="text/css" />\n')
774
standard_content_type_template = ('<meta http-equiv="Content-Type"'
775
' content="text/html; charset=%s" />\n')
776
standard_generator_template = (
777
'<meta name="generator"'
778
' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
779
standard_html_meta_value = (
780
standard_content_type_template
781
+ standard_generator_template % docutils.__version__)
782
standard_meta_value = standard_html_meta_value % 'utf-8'
783
standard_html_prolog = """\
784
<?xml version="1.0" encoding="%s" ?>
785
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
711
788
def format_output(self, parts):
712
789
"""Minimize & standardize the output."""
713
# remove redundant bits:
790
# remove redundant parts:
714
791
del parts['whole']
792
assert parts['body'] == parts['fragment']
715
793
del parts['body']
716
# remove standard bits:
794
# remove standard portions:
717
795
parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
718
if parts['stylesheet'] == self.standard_stylesheet_value:
719
del parts['stylesheet']
796
parts['html_head'] = parts['html_head'].replace(
797
self.standard_html_meta_value, '...')
798
parts['html_prolog'] = parts['html_prolog'].replace(
799
self.standard_html_prolog, '')
720
800
# remove empty values:
721
801
for key in parts.keys():
722
802
if not parts[key]:
743
823
except Exception, detail:
744
824
return (detail, detail.args,
745
825
'%s: %s' % (detail.__class__.__name__, detail))
828
def _format_str(*args):
830
Return a tuple containing representations of all args.
832
Same as map(repr, args) except that it returns multi-line
833
representations for strings containing newlines, e.g.::
845
This is a helper function for CustomTestCase.
851
if ( (isinstance(i, StringType) or isinstance(i, UnicodeType))
854
if isinstance(i, UnicodeType):
855
# stripped = 'u' or 'U'
858
# quote_char = "'" or '"'
860
assert quote_char in ("'", '"')
863
r = (stripped + 3 * quote_char + '\\\n' +
864
re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
866
r = re.sub(r' \n', r' \\n\\\n', r)
867
return_tuple.append(r)
868
return tuple(return_tuple)