python 2.3 alias unittest.TestCase.assertTrue (possibly reverted on next release)
[docutils/kirr.git] / docutils / test / DocutilsTestSupport.py
blobbbe01a80778470c1bcaac90f6e190ca10d7086c6
1 # $Id$
2 # Authors: David Goodger <goodger@python.org>;
3 # Garth Kidd <garth@deadlybloodyserious.com>
4 # Copyright: This module has been placed in the public domain.
6 """
7 Exports the following:
9 :Modules:
10 - `statemachine` is 'docutils.statemachine'
11 - `nodes` is 'docutils.nodes'
12 - `urischemes` is 'docutils.urischemes'
13 - `utils` is 'docutils.utils'
14 - `transforms` is 'docutils.transforms'
15 - `states` is 'docutils.parsers.rst.states'
16 - `tableparser` is 'docutils.parsers.rst.tableparser'
18 :Classes:
19 - `StandardTestCase`
20 - `CustomTestCase`
21 - `CustomTestSuite`
22 - `TransformTestCase`
23 - `TransformTestSuite`
24 - `ParserTestCase`
25 - `ParserTestSuite`
26 - `ParserTransformTestCase`
27 - `PEPParserTestCase`
28 - `PEPParserTestSuite`
29 - `GridTableParserTestCase`
30 - `GridTableParserTestSuite`
31 - `SimpleTableParserTestCase`
32 - `SimpleTableParserTestSuite`
33 - `WriterPublishTestCase`
34 - `LatexWriterPublishTestCase`
35 - `PseudoXMLWriterPublishTestCase`
36 - `HtmlWriterPublishTestCase`
37 - `PublishTestSuite`
38 - `HtmlFragmentTestSuite`
39 - `DevNull` (output sink)
40 """
41 __docformat__ = 'reStructuredText'
43 import sys
44 import os
45 import unittest
46 import re
47 import inspect
48 import traceback
49 from pprint import pformat
51 testroot = os.path.abspath(os.path.dirname(__file__) or os.curdir)
52 os.chdir(testroot)
53 sys.path.insert(0, os.path.normpath(os.path.join(testroot, '..')))
54 sys.path.insert(0, testroot)
55 sys.path.append(os.path.normpath(os.path.join(testroot, '..', 'extras')))
57 try:
58 import difflib
59 import package_unittest
60 import docutils
61 import docutils.core
62 from docutils import frontend, nodes, statemachine, urischemes, utils
63 from docutils.transforms import universal
64 from docutils.parsers import rst
65 from docutils.parsers.rst import states, tableparser, roles, languages
66 from docutils.readers import standalone, pep
67 from docutils.statemachine import StringList, string2lines
68 from docutils._compat import bytes
69 except ImportError:
70 # The importing module (usually __init__.py in one of the
71 # subdirectories) may catch ImportErrors in order to detect the
72 # absence of DocutilsTestSupport in sys.path. Thus, ImportErrors
73 # resulting from problems with importing Docutils modules must
74 # caught here.
75 traceback.print_exc()
76 sys.exit(1)
79 try:
80 import mypdb as pdb
81 except:
82 import pdb
85 # Hack to make repr(StringList) look like repr(list):
86 StringList.__repr__ = StringList.__str__
89 class DevNull:
91 """Output sink."""
93 def write(self, string):
94 pass
96 def close(self):
97 pass
100 class StandardTestCase(unittest.TestCase):
103 Helper class, providing the same interface as unittest.TestCase,
104 but with useful setUp and comparison methods.
107 def setUp(self):
108 os.chdir(testroot)
110 def assertEqual(self, first, second, msg=None):
111 """Fail if the two objects are unequal as determined by the '=='
112 operator.
114 if not first == second:
115 raise self.failureException, \
116 (msg or '%s != %s' % _format_str(first, second))
118 def assertNotEqual(self, first, second, msg=None):
119 """Fail if the two objects are equal as determined by the '=='
120 operator.
122 if first == second:
123 raise self.failureException, \
124 (msg or '%s == %s' % _format_str(first, second))
126 # python 2.3
127 if not hasattr(unittest.TestCase, "assertTrue"):
128 assertTrue = unittest.TestCase.failUnless
130 # aliases for assertion methods, deprecated since Python 2.7
132 failUnlessEqual = assertEquals = assertEqual
134 assertNotEquals = failIfEqual = assertNotEqual
137 class CustomTestCase(StandardTestCase):
140 Helper class, providing extended functionality over unittest.TestCase.
142 The methods assertEqual and assertNotEqual have been overwritten
143 to provide better support for multi-line strings. Furthermore,
144 see the compare_output method and the parameter list of __init__.
147 compare = difflib.Differ().compare
148 """Comparison method shared by all subclasses."""
150 def __init__(self, method_name, input, expected, id,
151 run_in_debugger=True, suite_settings=None):
153 Initialise the CustomTestCase.
155 Arguments:
157 method_name -- name of test method to run.
158 input -- input to the parser.
159 expected -- expected output from the parser.
160 id -- unique test identifier, used by the test framework.
161 run_in_debugger -- if true, run this test under the pdb debugger.
162 suite_settings -- settings overrides for this test suite.
164 self.id = id
165 self.input = input
166 self.expected = expected
167 self.run_in_debugger = run_in_debugger
168 self.suite_settings = suite_settings.copy() or {}
170 # Ring your mother.
171 unittest.TestCase.__init__(self, method_name)
173 def __str__(self):
175 Return string conversion. Overridden to give test id, in addition to
176 method name.
178 return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
180 def __repr__(self):
181 return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
183 def clear_roles(self):
184 # Language-specific roles and roles added by the
185 # "default-role" and "role" directives are currently stored
186 # globally in the roles._roles dictionary. This workaround
187 # empties that dictionary.
188 roles._roles = {}
190 def setUp(self):
191 StandardTestCase.setUp(self)
192 self.clear_roles()
194 def compare_output(self, input, output, expected):
195 """`input`, `output`, and `expected` should all be strings."""
196 if isinstance(input, unicode):
197 input = input.encode('raw_unicode_escape')
198 if sys.version_info > (3,):
199 # API difference: Python 3's node.__str__ doesn't escape
200 #assert expected is None or isinstance(expected, unicode)
201 if isinstance(expected, bytes):
202 expected = expected.decode('utf-8')
203 if isinstance(output, bytes):
204 output = output.decode('utf-8')
205 else:
206 if isinstance(expected, unicode):
207 expected = expected.encode('raw_unicode_escape')
208 if isinstance(output, unicode):
209 output = output.encode('raw_unicode_escape')
210 # Normalize line endings:
211 if expected:
212 expected = '\n'.join(expected.splitlines())
213 if output:
214 output = '\n'.join(output.splitlines())
215 try:
216 self.assertEqual(output, expected)
217 except AssertionError, error:
218 print >>sys.stderr, '\n%s\ninput:' % (self,)
219 print >>sys.stderr, input
220 try:
221 comparison = ''.join(self.compare(expected.splitlines(1),
222 output.splitlines(1)))
223 print >>sys.stderr, '-: expected\n+: output'
224 print >>sys.stderr, comparison
225 except AttributeError: # expected or output not a string
226 # alternative output for non-strings:
227 print >>sys.stderr, 'expected: %r' % expected
228 print >>sys.stderr, 'output: %r' % output
229 raise error
232 class CustomTestSuite(unittest.TestSuite):
235 A collection of CustomTestCases.
237 Provides test suite ID generation and a method for adding test cases.
240 id = ''
241 """Identifier for the TestSuite. Prepended to the
242 TestCase identifiers to make identification easier."""
244 next_test_case_id = 0
245 """The next identifier to use for non-identified test cases."""
247 def __init__(self, tests=(), id=None, suite_settings=None):
249 Initialize the CustomTestSuite.
251 Arguments:
253 id -- identifier for the suite, prepended to test cases.
254 suite_settings -- settings overrides for this test suite.
256 unittest.TestSuite.__init__(self, tests)
257 self.suite_settings = suite_settings or {}
258 if id is None:
259 mypath = os.path.abspath(
260 sys.modules[CustomTestSuite.__module__].__file__)
261 outerframes = inspect.getouterframes(inspect.currentframe())
262 for outerframe in outerframes[1:]:
263 if outerframe[3] != '__init__':
264 callerpath = outerframe[1]
265 if callerpath is None:
266 # It happens sometimes. Why is a mystery.
267 callerpath = os.getcwd()
268 callerpath = os.path.abspath(callerpath)
269 break
270 mydir, myname = os.path.split(mypath)
271 if not mydir:
272 mydir = os.curdir
273 if callerpath.startswith(mydir):
274 self.id = callerpath[len(mydir) + 1:] # caller's module
275 else:
276 self.id = callerpath
277 else:
278 self.id = id
280 def addTestCase(self, test_case_class, method_name, input, expected,
281 id=None, run_in_debugger=False, **kwargs):
283 Create a CustomTestCase in the CustomTestSuite.
284 Also return it, just in case.
286 Arguments:
288 test_case_class -- the CustomTestCase to add
289 method_name -- a string; CustomTestCase.method_name is the test
290 input -- input to the parser.
291 expected -- expected output from the parser.
292 id -- unique test identifier, used by the test framework.
293 run_in_debugger -- if true, run this test under the pdb debugger.
295 if id is None: # generate id if required
296 id = self.next_test_case_id
297 self.next_test_case_id += 1
298 # test identifier will become suiteid.testid
299 tcid = '%s: %s' % (self.id, id)
300 # suite_settings may be passed as a parameter;
301 # if not, set from attribute:
302 kwargs.setdefault('suite_settings', self.suite_settings)
303 # generate and add test case
304 tc = test_case_class(method_name, input, expected, tcid,
305 run_in_debugger=run_in_debugger, **kwargs)
306 self.addTest(tc)
307 return tc
309 def generate_no_tests(self, *args, **kwargs):
310 pass
313 class TransformTestCase(CustomTestCase):
316 Output checker for the transform.
318 Should probably be called TransformOutputChecker, but I can deal with
319 that later when/if someone comes up with a category of transform test
320 cases that have nothing to do with the input and output of the transform.
323 option_parser = frontend.OptionParser(components=(rst.Parser,))
324 settings = option_parser.get_default_values()
325 settings.report_level = 1
326 settings.halt_level = 5
327 settings.debug = package_unittest.debug
328 settings.warning_stream = DevNull()
329 unknown_reference_resolvers = ()
331 def __init__(self, *args, **kwargs):
332 self.transforms = kwargs['transforms']
333 """List of transforms to perform for this test case."""
335 self.parser = kwargs['parser']
336 """Input parser for this test case."""
338 del kwargs['transforms'], kwargs['parser'] # only wanted here
339 CustomTestCase.__init__(self, *args, **kwargs)
341 def supports(self, format):
342 return 1
344 def test_transforms(self):
345 if self.run_in_debugger:
346 pdb.set_trace()
347 settings = self.settings.copy()
348 settings.__dict__.update(self.suite_settings)
349 document = utils.new_document('test data', settings)
350 self.parser.parse(self.input, document)
351 # Don't do a ``populate_from_components()`` because that would
352 # enable the Transformer's default transforms.
353 document.transformer.add_transforms(self.transforms)
354 document.transformer.add_transform(universal.TestMessages)
355 document.transformer.components['writer'] = self
356 document.transformer.apply_transforms()
357 output = document.pformat()
358 self.compare_output(self.input, output, self.expected)
360 def test_transforms_verbosely(self):
361 if self.run_in_debugger:
362 pdb.set_trace()
363 print '\n', self.id
364 print '-' * 70
365 print self.input
366 settings = self.settings.copy()
367 settings.__dict__.update(self.suite_settings)
368 document = utils.new_document('test data', settings)
369 self.parser.parse(self.input, document)
370 print '-' * 70
371 print document.pformat()
372 for transformClass in self.transforms:
373 transformClass(document).apply()
374 output = document.pformat()
375 print '-' * 70
376 print output
377 self.compare_output(self.input, output, self.expected)
380 class TransformTestSuite(CustomTestSuite):
383 A collection of TransformTestCases.
385 A TransformTestSuite instance manufactures TransformTestCases,
386 keeps track of them, and provides a shared test fixture (a-la
387 setUp and tearDown).
390 def __init__(self, parser, suite_settings=None):
391 self.parser = parser
392 """Parser shared by all test cases."""
394 CustomTestSuite.__init__(self, suite_settings=suite_settings)
396 def generateTests(self, dict, dictname='totest',
397 testmethod='test_transforms'):
399 Stock the suite with test cases generated from a test data dictionary.
401 Each dictionary key (test type's name) maps to a tuple, whose
402 first item is a list of transform classes and whose second
403 item is a list of tests. Each test is a list: input, expected
404 output, optional modifier. The optional third entry, a
405 behavior modifier, can be 0 (temporarily disable this test) or
406 1 (run this test under the pdb debugger). Tests should be
407 self-documenting and not require external comments.
409 for name, (transforms, cases) in dict.items():
410 for casenum in range(len(cases)):
411 case = cases[casenum]
412 run_in_debugger = False
413 if len(case)==3:
414 # TODO: (maybe) change the 3rd argument to a dict, so it
415 # can handle more cases by keyword ('disable', 'debug',
416 # 'settings'), here and in other generateTests methods.
417 # But there's also the method that
418 # HtmlPublishPartsTestSuite uses <DJG>
419 if case[2]:
420 run_in_debugger = True
421 else:
422 continue
423 self.addTestCase(
424 TransformTestCase, testmethod,
425 transforms=transforms, parser=self.parser,
426 input=case[0], expected=case[1],
427 id='%s[%r][%s]' % (dictname, name, casenum),
428 run_in_debugger=run_in_debugger)
431 class ParserTestCase(CustomTestCase):
434 Output checker for the parser.
436 Should probably be called ParserOutputChecker, but I can deal with
437 that later when/if someone comes up with a category of parser test
438 cases that have nothing to do with the input and output of the parser.
441 parser = rst.Parser()
442 """Parser shared by all ParserTestCases."""
444 option_parser = frontend.OptionParser(components=(rst.Parser,))
445 settings = option_parser.get_default_values()
446 settings.report_level = 5
447 settings.halt_level = 5
448 settings.debug = package_unittest.debug
450 def test_parser(self):
451 if self.run_in_debugger:
452 pdb.set_trace()
453 settings = self.settings.copy()
454 settings.__dict__.update(self.suite_settings)
455 document = utils.new_document('test data', settings)
456 self.parser.parse(self.input, document)
457 output = document.pformat()
458 self.compare_output(self.input, output, self.expected)
461 class ParserTestSuite(CustomTestSuite):
464 A collection of ParserTestCases.
466 A ParserTestSuite instance manufactures ParserTestCases,
467 keeps track of them, and provides a shared test fixture (a-la
468 setUp and tearDown).
471 test_case_class = ParserTestCase
473 def generateTests(self, dict, dictname='totest'):
475 Stock the suite with test cases generated from a test data dictionary.
477 Each dictionary key (test type name) maps to a list of tests. Each
478 test is a list: input, expected output, optional modifier. The
479 optional third entry, a behavior modifier, can be 0 (temporarily
480 disable this test) or 1 (run this test under the pdb debugger). Tests
481 should be self-documenting and not require external comments.
483 for name, cases in dict.items():
484 for casenum in range(len(cases)):
485 case = cases[casenum]
486 run_in_debugger = False
487 if len(case)==3:
488 if case[2]:
489 run_in_debugger = True
490 else:
491 continue
492 self.addTestCase(
493 self.test_case_class, 'test_parser',
494 input=case[0], expected=case[1],
495 id='%s[%r][%s]' % (dictname, name, casenum),
496 run_in_debugger=run_in_debugger)
499 class PEPParserTestCase(ParserTestCase):
501 """PEP-specific parser test case."""
503 parser = rst.Parser(rfc2822=True, inliner=rst.states.Inliner())
504 """Parser shared by all PEPParserTestCases."""
506 option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
507 settings = option_parser.get_default_values()
508 settings.report_level = 5
509 settings.halt_level = 5
510 settings.debug = package_unittest.debug
513 class PEPParserTestSuite(ParserTestSuite):
515 """A collection of PEPParserTestCases."""
517 test_case_class = PEPParserTestCase
520 class GridTableParserTestCase(CustomTestCase):
522 parser = tableparser.GridTableParser()
524 def test_parse_table(self):
525 self.parser.setup(StringList(string2lines(self.input), 'test data'))
526 try:
527 self.parser.find_head_body_sep()
528 self.parser.parse_table()
529 output = self.parser.cells
530 except Exception, details:
531 output = '%s: %s' % (details.__class__.__name__, details)
532 self.compare_output(self.input, pformat(output) + '\n',
533 pformat(self.expected) + '\n')
535 def test_parse(self):
536 try:
537 output = self.parser.parse(StringList(string2lines(self.input),
538 'test data'))
539 except Exception, details:
540 output = '%s: %s' % (details.__class__.__name__, details)
541 self.compare_output(self.input, pformat(output) + '\n',
542 pformat(self.expected) + '\n')
545 class GridTableParserTestSuite(CustomTestSuite):
548 A collection of GridTableParserTestCases.
550 A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
551 keeps track of them, and provides a shared test fixture (a-la setUp and
552 tearDown).
555 test_case_class = GridTableParserTestCase
557 def generateTests(self, dict, dictname='totest'):
559 Stock the suite with test cases generated from a test data dictionary.
561 Each dictionary key (test type name) maps to a list of tests. Each
562 test is a list: an input table, expected output from parse_table(),
563 expected output from parse(), optional modifier. The optional fourth
564 entry, a behavior modifier, can be 0 (temporarily disable this test)
565 or 1 (run this test under the pdb debugger). Tests should be
566 self-documenting and not require external comments.
568 for name, cases in dict.items():
569 for casenum in range(len(cases)):
570 case = cases[casenum]
571 run_in_debugger = False
572 if len(case) == 4:
573 if case[-1]:
574 run_in_debugger = True
575 else:
576 continue
577 self.addTestCase(self.test_case_class, 'test_parse_table',
578 input=case[0], expected=case[1],
579 id='%s[%r][%s]' % (dictname, name, casenum),
580 run_in_debugger=run_in_debugger)
581 self.addTestCase(self.test_case_class, 'test_parse',
582 input=case[0], expected=case[2],
583 id='%s[%r][%s]' % (dictname, name, casenum),
584 run_in_debugger=run_in_debugger)
587 class SimpleTableParserTestCase(GridTableParserTestCase):
589 parser = tableparser.SimpleTableParser()
592 class SimpleTableParserTestSuite(CustomTestSuite):
595 A collection of SimpleTableParserTestCases.
598 test_case_class = SimpleTableParserTestCase
600 def generateTests(self, dict, dictname='totest'):
602 Stock the suite with test cases generated from a test data dictionary.
604 Each dictionary key (test type name) maps to a list of tests. Each
605 test is a list: an input table, expected output from parse(), optional
606 modifier. The optional third entry, a behavior modifier, can be 0
607 (temporarily disable this test) or 1 (run this test under the pdb
608 debugger). Tests should be self-documenting and not require external
609 comments.
611 for name, cases in dict.items():
612 for casenum in range(len(cases)):
613 case = cases[casenum]
614 run_in_debugger = False
615 if len(case) == 3:
616 if case[-1]:
617 run_in_debugger = True
618 else:
619 continue
620 self.addTestCase(self.test_case_class, 'test_parse',
621 input=case[0], expected=case[1],
622 id='%s[%r][%s]' % (dictname, name, casenum),
623 run_in_debugger=run_in_debugger)
626 class PythonModuleParserTestCase(CustomTestCase):
628 def test_parser(self):
629 if self.run_in_debugger:
630 pdb.set_trace()
631 try:
632 import compiler
633 except ImportError:
634 # skip on Python 3
635 return
636 from docutils.readers.python import moduleparser
637 module = moduleparser.parse_module(self.input, 'test data').pformat()
638 output = str(module)
639 self.compare_output(self.input, output, self.expected)
641 def test_token_parser_rhs(self):
642 if self.run_in_debugger:
643 pdb.set_trace()
644 try:
645 import compiler
646 except ImportError:
647 # skip on Python 3
648 return
649 from docutils.readers.python import moduleparser
650 tr = moduleparser.TokenParser(self.input)
651 output = tr.rhs(1)
652 self.compare_output(self.input, output, self.expected)
655 class PythonModuleParserTestSuite(CustomTestSuite):
658 A collection of PythonModuleParserTestCase.
661 def generateTests(self, dict, dictname='totest',
662 testmethod='test_parser'):
664 Stock the suite with test cases generated from a test data dictionary.
666 Each dictionary key (test type's name) maps to a list of tests. Each
667 test is a list: input, expected output, optional modifier. The
668 optional third entry, a behavior modifier, can be 0 (temporarily
669 disable this test) or 1 (run this test under the pdb debugger). Tests
670 should be self-documenting and not require external comments.
672 for name, cases in dict.items():
673 for casenum in range(len(cases)):
674 case = cases[casenum]
675 run_in_debugger = False
676 if len(case)==3:
677 if case[2]:
678 run_in_debugger = True
679 else:
680 continue
681 self.addTestCase(
682 PythonModuleParserTestCase, testmethod,
683 input=case[0], expected=case[1],
684 id='%s[%r][%s]' % (dictname, name, casenum),
685 run_in_debugger=run_in_debugger)
688 class WriterPublishTestCase(CustomTestCase, docutils.SettingsSpec):
691 Test case for publish.
694 settings_default_overrides = {'_disable_config': 1,
695 'strict_visitor': 1}
696 writer_name = '' # set in subclasses or constructor
698 def __init__(self, *args, **kwargs):
699 if 'writer_name' in kwargs:
700 self.writer_name = kwargs['writer_name']
701 del kwargs['writer_name']
702 CustomTestCase.__init__(self, *args, **kwargs)
704 def test_publish(self):
705 if self.run_in_debugger:
706 pdb.set_trace()
707 output = docutils.core.publish_string(
708 source=self.input,
709 reader_name='standalone',
710 parser_name='restructuredtext',
711 writer_name=self.writer_name,
712 settings_spec=self,
713 settings_overrides=self.suite_settings)
714 self.compare_output(self.input, output, self.expected)
717 class PublishTestSuite(CustomTestSuite):
719 def __init__(self, writer_name, suite_settings=None):
721 `writer_name` is the name of the writer to use.
723 CustomTestSuite.__init__(self, suite_settings=suite_settings)
724 self.test_class = WriterPublishTestCase
725 self.writer_name = writer_name
727 def generateTests(self, dict, dictname='totest'):
728 for name, cases in dict.items():
729 for casenum in range(len(cases)):
730 case = cases[casenum]
731 run_in_debugger = False
732 if len(case)==3:
733 if case[2]:
734 run_in_debugger = True
735 else:
736 continue
737 self.addTestCase(
738 self.test_class, 'test_publish',
739 input=case[0], expected=case[1],
740 id='%s[%r][%s]' % (dictname, name, casenum),
741 run_in_debugger=run_in_debugger,
742 # Passed to constructor of self.test_class:
743 writer_name=self.writer_name)
746 class HtmlPublishPartsTestSuite(CustomTestSuite):
748 def generateTests(self, dict, dictname='totest'):
749 for name, (settings_overrides, cases) in dict.items():
750 settings = self.suite_settings.copy()
751 settings.update(settings_overrides)
752 for casenum in range(len(cases)):
753 case = cases[casenum]
754 run_in_debugger = False
755 if len(case)==3:
756 if case[2]:
757 run_in_debugger = True
758 else:
759 continue
760 self.addTestCase(
761 HtmlWriterPublishPartsTestCase, 'test_publish',
762 input=case[0], expected=case[1],
763 id='%s[%r][%s]' % (dictname, name, casenum),
764 run_in_debugger=run_in_debugger,
765 suite_settings=settings)
768 class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
771 Test case for HTML writer via the publish_parts interface.
774 writer_name = 'html'
776 settings_default_overrides = \
777 WriterPublishTestCase.settings_default_overrides.copy()
778 settings_default_overrides['stylesheet'] = ''
780 def test_publish(self):
781 if self.run_in_debugger:
782 pdb.set_trace()
783 parts = docutils.core.publish_parts(
784 source=self.input,
785 reader_name='standalone',
786 parser_name='restructuredtext',
787 writer_name=self.writer_name,
788 settings_spec=self,
789 settings_overrides=self.suite_settings)
790 output = self.format_output(parts)
791 # interpolate standard variables:
792 expected = self.expected % {'version': docutils.__version__}
793 self.compare_output(self.input, output, expected)
795 standard_content_type_template = ('<meta http-equiv="Content-Type"'
796 ' content="text/html; charset=%s" />\n')
797 standard_generator_template = (
798 '<meta name="generator"'
799 ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
800 standard_html_meta_value = (
801 standard_content_type_template
802 + standard_generator_template % docutils.__version__)
803 standard_meta_value = standard_html_meta_value % 'utf-8'
804 standard_html_prolog = """\
805 <?xml version="1.0" encoding="%s" ?>
806 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
809 def format_output(self, parts):
810 """Minimize & standardize the output."""
811 # remove redundant parts & uninteresting parts:
812 del parts['whole']
813 assert parts['body'] == parts['fragment']
814 del parts['body']
815 del parts['body_pre_docinfo']
816 del parts['body_prefix']
817 del parts['body_suffix']
818 del parts['head']
819 del parts['head_prefix']
820 del parts['encoding']
821 del parts['version']
822 # remove standard portions:
823 parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
824 parts['html_head'] = parts['html_head'].replace(
825 self.standard_html_meta_value, '...')
826 parts['html_prolog'] = parts['html_prolog'].replace(
827 self.standard_html_prolog, '')
828 # remove empty values:
829 for key in parts.keys():
830 if not parts[key]:
831 del parts[key]
832 # standard output format:
833 keys = parts.keys()
834 keys.sort()
835 output = []
836 for key in keys:
837 output.append("%r: '''%s'''"
838 % (key, parts[key]))
839 if output[-1].endswith("\n'''"):
840 output[-1] = output[-1][:-4] + "\\n'''"
841 return '{' + ',\n '.join(output) + '}\n'
844 def exception_data(func, *args, **kwds):
846 Execute `func(*args, **kwds)` and return the resulting exception, the
847 exception arguments, and the formatted exception string.
849 try:
850 func(*args, **kwds)
851 except Exception, detail:
852 return (detail, detail.args,
853 '%s: %s' % (detail.__class__.__name__, detail))
856 def _format_str(*args):
857 r"""
858 Return a tuple containing representations of all args.
860 Same as map(repr, args) except that it returns multi-line
861 representations for strings containing newlines, e.g.::
863 '''\
864 foo \n\
867 baz'''
869 instead of::
871 'foo \nbar\n\nbaz'
873 This is a helper function for CustomTestCase.
875 return_tuple = []
876 for i in args:
877 r = repr(i)
878 if ( (isinstance(i, str) or isinstance(i, unicode))
879 and '\n' in i):
880 stripped = ''
881 if isinstance(i, unicode) and r.startswith('u'):
882 stripped = r[0]
883 r = r[1:]
884 elif isinstance(i, bytes) and r.startswith('b'):
885 stripped = r[0]
886 r = r[1:]
887 # quote_char = "'" or '"'
888 quote_char = r[0]
889 assert quote_char in ("'", '"'), quote_char
890 assert r[0] == r[-1]
891 r = r[1:-1]
892 r = (stripped + 3 * quote_char + '\\\n' +
893 re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
894 3 * quote_char)
895 r = re.sub(r' \n', r' \\n\\\n', r)
896 return_tuple.append(r)
897 return tuple(return_tuple)