~ubuntu-branches/ubuntu/hardy/python-docutils/hardy

« back to all changes in this revision

Viewing changes to test/DocutilsTestSupport.py

  • Committer: Bazaar Package Importer
  • Author(s): martin f. krafft
  • Date: 2006-07-10 11:45:05 UTC
  • mfrom: (2.1.4 edgy)
  • Revision ID: james.westby@ubuntu.com-20060710114505-otkhqcslevewxmz5
Tags: 0.4-3
Added build dependency on python-central (closes: #377580).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Authors:  David Goodger; Garth Kidd
2
2
# Contact: goodger@users.sourceforge.net
3
 
# Revision: $Revision: 1.38 $
4
 
# Date: $Date: 2004/05/09 02:14:33 $
 
3
# Revision: $Revision: 4258 $
 
4
# Date: $Date: 2006-01-09 04:29:23 +0100 (Mon, 09 Jan 2006) $
5
5
# Copyright: This module has been placed in the public domain.
6
6
 
7
7
"""
17
17
    - `tableparser` is 'docutils.parsers.rst.tableparser'
18
18
 
19
19
:Classes:
 
20
    - `StandardTestCase`
 
21
    - `CustomTestCase`
20
22
    - `CustomTestSuite`
21
 
    - `CustomTestCase`
 
23
    - `TransformTestCase`
22
24
    - `TransformTestSuite`
23
 
    - `TransformTestCase`
 
25
    - `ParserTestCase`
24
26
    - `ParserTestSuite`
25
 
    - `ParserTestCase`
 
27
    - `ParserTransformTestCase`
 
28
    - `PEPParserTestCase`
26
29
    - `PEPParserTestSuite`
27
 
    - `PEPParserTestCase`
 
30
    - `GridTableParserTestCase`
28
31
    - `GridTableParserTestSuite`
29
 
    - `GridTableParserTestCase`
 
32
    - `SimpleTableParserTestCase`
30
33
    - `SimpleTableParserTestSuite`
31
 
    - `SimpleTableParserTestCase`
32
34
    - `WriterPublishTestCase`
33
35
    - `LatexWriterPublishTestCase`
34
36
    - `PseudoXMLWriterPublishTestCase`
41
43
 
42
44
import sys
43
45
import os
 
46
 
 
47
testroot = os.path.abspath(os.path.dirname(__file__) or os.curdir)
 
48
os.chdir(testroot)
 
49
sys.path.insert(0, os.path.normpath(os.path.join(testroot, '..')))
 
50
sys.path.insert(0, testroot)
 
51
sys.path.append(os.path.normpath(os.path.join(testroot, '..', 'extras')))
 
52
 
44
53
import unittest
45
 
import difflib
 
54
import docutils_difflib
46
55
import inspect
47
56
from pprint import pformat
48
 
from types import UnicodeType
 
57
from types import UnicodeType, StringType
49
58
import package_unittest
50
59
import docutils
51
60
import docutils.core
56
65
from docutils.readers import standalone, pep
57
66
from docutils.statemachine import StringList, string2lines
58
67
 
59
 
if sys.hexversion >= 0x02020000:    # Python 2.2
 
68
try:
60
69
    from docutils.readers.python import moduleparser
61
 
else:
 
70
    from tokenize import generate_tokens
 
71
    del generate_tokens
 
72
except ImportError:      # moduleparser depends on modules added in Python 2.2
62
73
    moduleparser = None
63
74
 
64
75
try:
78
89
    def write(self, string):
79
90
        pass
80
91
 
 
92
    def close(self):
 
93
        pass
 
94
 
 
95
 
 
96
class StandardTestCase(unittest.TestCase):
 
97
 
 
98
    """
 
99
    Helper class, providing the same interface as unittest.TestCase,
 
100
    but with useful setUp and comparison methods.
 
101
    """
 
102
 
 
103
    def setUp(self):
 
104
        os.chdir(testroot)
 
105
 
 
106
    def failUnlessEqual(self, first, second, msg=None):
 
107
        """Fail if the two objects are unequal as determined by the '=='
 
108
           operator.
 
109
        """
 
110
        if not first == second:
 
111
            raise self.failureException, \
 
112
                  (msg or '%s != %s' % _format_str(first, second))
 
113
 
 
114
    def failIfEqual(self, first, second, msg=None):
 
115
        """Fail if the two objects are equal as determined by the '=='
 
116
           operator.
 
117
        """
 
118
        if first == second:
 
119
            raise self.failureException, \
 
120
                  (msg or '%s == %s' % _format_str(first, second))
 
121
 
 
122
    # Synonyms for assertion methods
 
123
 
 
124
    assertEqual = assertEquals = failUnlessEqual
 
125
 
 
126
    assertNotEqual = assertNotEquals = failIfEqual
 
127
 
 
128
 
 
129
class CustomTestCase(StandardTestCase):
 
130
    
 
131
    """
 
132
    Helper class, providing extended functionality over unittest.TestCase.
 
133
 
 
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__.
 
137
    """
 
138
 
 
139
    compare = docutils_difflib.Differ().compare
 
140
    """Comparison method shared by all subclasses."""
 
141
 
 
142
    def __init__(self, method_name, input, expected, id, run_in_debugger=0,
 
143
                 suite_settings=None):
 
144
        """
 
145
        Initialise the CustomTestCase.
 
146
 
 
147
        Arguments:
 
148
 
 
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.
 
155
        """
 
156
        self.id = id
 
157
        self.input = input
 
158
        self.expected = expected
 
159
        self.run_in_debugger = run_in_debugger
 
160
        self.suite_settings = suite_settings or {}
 
161
        
 
162
        # Ring your mother.
 
163
        unittest.TestCase.__init__(self, method_name)
 
164
 
 
165
    def __str__(self):
 
166
        """
 
167
        Return string conversion. Overridden to give test id, in addition to
 
168
        method name.
 
169
        """
 
170
        return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
 
171
 
 
172
    def __repr__(self):
 
173
        return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
 
174
 
 
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.
 
180
        roles._roles = {}
 
181
 
 
182
    def setUp(self):
 
183
        StandardTestCase.setUp(self)
 
184
        self.clear_roles()
 
185
 
 
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')
 
194
        try:
 
195
            self.assertEquals(output, expected)
 
196
        except AssertionError, error:
 
197
            print >>sys.stderr, '\n%s\ninput:' % (self,)
 
198
            print >>sys.stderr, input
 
199
            try:
 
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
 
208
            raise error
 
209
 
81
210
 
82
211
class CustomTestSuite(unittest.TestSuite):
83
212
 
84
213
    """
85
 
    A collection of custom TestCases.
 
214
    A collection of CustomTestCases.
86
215
 
 
216
    Provides test suite ID generation and a method for adding test cases.
87
217
    """
88
218
 
89
219
    id = ''
93
223
    next_test_case_id = 0
94
224
    """The next identifier to use for non-identified test cases."""
95
225
 
96
 
    def __init__(self, tests=(), id=None):
 
226
    def __init__(self, tests=(), id=None, suite_settings=None):
97
227
        """
98
228
        Initialize the CustomTestSuite.
99
229
 
100
230
        Arguments:
101
231
 
102
232
        id -- identifier for the suite, prepended to test cases.
 
233
        suite_settings -- settings overrides for this test suite.
103
234
        """
104
235
        unittest.TestSuite.__init__(self, tests)
 
236
        self.suite_settings = suite_settings or {}
105
237
        if id is None:
106
238
            mypath = os.path.abspath(
107
239
                sys.modules[CustomTestSuite.__module__].__file__)
125
257
            self.id = id
126
258
 
127
259
    def addTestCase(self, test_case_class, method_name, input, expected,
128
 
                    id=None, run_in_debugger=0, short_description=None,
129
 
                    **kwargs):
 
260
                    id=None, run_in_debugger=0, **kwargs):
130
261
        """
131
 
        Create a custom TestCase in the CustomTestSuite.
 
262
        Create a CustomTestCase in the CustomTestSuite.
132
263
        Also return it, just in case.
133
264
 
134
265
        Arguments:
135
266
 
136
 
        test_case_class --
137
 
        method_name --
 
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.
143
273
        """
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,
153
 
                             **kwargs)
 
284
                             run_in_debugger=run_in_debugger, **kwargs)
154
285
        self.addTest(tc)
155
286
        return tc
156
287
 
158
289
        pass
159
290
 
160
291
 
161
 
class CustomTestCase(unittest.TestCase):
162
 
 
163
 
    compare = difflib.Differ().compare
164
 
    """Comparison method shared by all subclasses."""
165
 
 
166
 
    def __init__(self, method_name, input, expected, id,
167
 
                 run_in_debugger=0, short_description=None):
168
 
        """
169
 
        Initialise the CustomTestCase.
170
 
 
171
 
        Arguments:
172
 
 
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.
179
 
        """
180
 
        self.id = id
181
 
        self.input = input
182
 
        self.expected = expected
183
 
        self.run_in_debugger = run_in_debugger
184
 
        # Ring your mother.
185
 
        unittest.TestCase.__init__(self, method_name)
186
 
 
187
 
    def __str__(self):
188
 
        """
189
 
        Return string conversion. Overridden to give test id, in addition to
190
 
        method name.
191
 
        """
192
 
        return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
193
 
 
194
 
    def __repr__(self):
195
 
        return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
196
 
 
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')
205
 
        try:
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)))
213
 
            raise
214
 
 
215
 
    def skip_test(self):
216
 
        print >>sys.stderr, '%s: Test skipped' % self
217
 
 
218
 
 
219
 
class TransformTestSuite(CustomTestSuite):
220
 
 
221
 
    """
222
 
    A collection of TransformTestCases.
223
 
 
224
 
    A TransformTestSuite instance manufactures TransformTestCases,
225
 
    keeps track of them, and provides a shared test fixture (a-la
226
 
    setUp and tearDown).
227
 
    """
228
 
 
229
 
    def __init__(self, parser):
230
 
        self.parser = parser
231
 
        """Parser shared by all test cases."""
232
 
 
233
 
        CustomTestSuite.__init__(self)
234
 
 
235
 
    def generateTests(self, dict, dictname='totest',
236
 
                      testmethod='test_transforms'):
237
 
        """
238
 
        Stock the suite with test cases generated from a test data dictionary.
239
 
 
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.
246
 
        """
247
 
        for name, (transforms, cases) in dict.items():
248
 
            for casenum in range(len(cases)):
249
 
                case = cases[casenum]
250
 
                run_in_debugger = 0
251
 
                if len(case)==3:
252
 
                    if case[2]:
253
 
                        run_in_debugger = 1
254
 
                    else:
255
 
                        continue
256
 
                self.addTestCase(
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)
262
 
 
263
 
 
264
292
class TransformTestCase(CustomTestCase):
265
293
 
266
294
    """
295
323
    def test_transforms(self):
296
324
        if self.run_in_debugger:
297
325
            pdb.set_trace()
298
 
        document = utils.new_document('test data', self.settings)
 
326
        settings = self.settings.copy()
 
327
        settings.__dict__.update(self.suite_settings)
 
328
        document = utils.new_document('test data', settings)
299
329
        self.parser.parse(self.input, document)
300
330
        # Don't do a ``populate_from_components()`` because that would
301
331
        # enable the Transformer's default transforms.
312
342
        print '\n', self.id
313
343
        print '-' * 70
314
344
        print self.input
315
 
        document = utils.new_document('test data', self.settings)
 
345
        settings = self.settings.copy()
 
346
        settings.__dict__.update(self.suite_settings)
 
347
        document = utils.new_document('test data', settings)
316
348
        self.parser.parse(self.input, document)
317
349
        print '-' * 70
318
350
        print document.pformat()
324
356
        self.compare_output(self.input, output, self.expected)
325
357
 
326
358
 
 
359
class TransformTestSuite(CustomTestSuite):
 
360
 
 
361
    """
 
362
    A collection of TransformTestCases.
 
363
 
 
364
    A TransformTestSuite instance manufactures TransformTestCases,
 
365
    keeps track of them, and provides a shared test fixture (a-la
 
366
    setUp and tearDown).
 
367
    """
 
368
 
 
369
    def __init__(self, parser, suite_settings=None):
 
370
        self.parser = parser
 
371
        """Parser shared by all test cases."""
 
372
 
 
373
        CustomTestSuite.__init__(self, suite_settings=suite_settings)
 
374
 
 
375
    def generateTests(self, dict, dictname='totest',
 
376
                      testmethod='test_transforms'):
 
377
        """
 
378
        Stock the suite with test cases generated from a test data dictionary.
 
379
 
 
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.
 
387
        """
 
388
        for name, (transforms, cases) in dict.items():
 
389
            for casenum in range(len(cases)):
 
390
                case = cases[casenum]
 
391
                run_in_debugger = 0
 
392
                if len(case)==3:
 
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>
 
398
                    if case[2]:
 
399
                        run_in_debugger = 1
 
400
                    else:
 
401
                        continue
 
402
                self.addTestCase(
 
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)
 
408
 
 
409
 
327
410
class ParserTestCase(CustomTestCase):
328
411
 
329
412
    """
346
429
    def test_parser(self):
347
430
        if self.run_in_debugger:
348
431
            pdb.set_trace()
349
 
        document = utils.new_document('test data', self.settings)
350
 
        # Remove any additions made by "role" directives:
351
 
        roles._roles = {}
 
432
        settings = self.settings.copy()
 
433
        settings.__dict__.update(self.suite_settings)
 
434
        document = utils.new_document('test data', settings)
352
435
        self.parser.parse(self.input, document)
353
436
        output = document.pformat()
354
437
        self.compare_output(self.input, output, self.expected)
396
479
 
397
480
    """PEP-specific parser test case."""
398
481
 
399
 
    parser = rst.Parser(rfc2822=1, inliner=pep.Inliner())
 
482
    parser = rst.Parser(rfc2822=1, inliner=rst.states.Inliner())
400
483
    """Parser shared by all PEPParserTestCases."""
401
484
 
402
485
    option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
586
669
    Test case for publish.
587
670
    """
588
671
 
589
 
    settings_default_overrides = {'_disable_config': 1}
590
 
    writer_name = '' # override in subclasses
 
672
    settings_default_overrides = {'_disable_config': 1,
 
673
                                  'strict_visitor': 1}
 
674
    writer_name = '' # set in subclasses or constructor
 
675
 
 
676
    def __init__(self, *args, **kwargs):
 
677
        if kwargs.has_key('writer_name'):
 
678
            self.writer_name = kwargs['writer_name']
 
679
            del kwargs['writer_name']
 
680
        CustomTestCase.__init__(self, *args, **kwargs)
591
681
 
592
682
    def test_publish(self):
593
683
        if self.run_in_debugger:
597
687
              reader_name='standalone',
598
688
              parser_name='restructuredtext',
599
689
              writer_name=self.writer_name,
600
 
              settings_spec=self)
 
690
              settings_spec=self,
 
691
              settings_overrides=self.suite_settings)
601
692
        self.compare_output(self.input, output, self.expected)
602
693
 
603
694
 
604
 
class LatexWriterPublishTestCase(WriterPublishTestCase):
605
 
 
606
 
    """
607
 
    Test case for Latex writer.
608
 
    """
609
 
 
610
 
    writer_name = 'latex'
611
 
 
612
 
 
613
 
class PseudoXMLWriterPublishTestCase(WriterPublishTestCase):
614
 
 
615
 
    """
616
 
    Test case for pseudo-XML writer.
617
 
    """
618
 
 
619
 
    writer_name = 'pseudoxml'
620
 
 
621
 
 
622
695
class PublishTestSuite(CustomTestSuite):
623
696
 
624
 
    TEST_CLASSES = {
625
 
        'latex': LatexWriterPublishTestCase,
626
 
        'pseudoxml': PseudoXMLWriterPublishTestCase,
627
 
    }
628
 
 
629
 
    def __init__(self, writer_name):
630
 
        """
631
 
        `writer_name` is the name of the writer
632
 
        to use.  It must be a key in `TEST_CLASSES`.
633
 
        """
634
 
        CustomTestSuite.__init__(self)
635
 
        self.test_class = self.TEST_CLASSES[writer_name]
 
697
    def __init__(self, writer_name, suite_settings=None):
 
698
        """
 
699
        `writer_name` is the name of the writer to use.
 
700
        """
 
701
        CustomTestSuite.__init__(self, suite_settings=suite_settings)
 
702
        self.test_class = WriterPublishTestCase
 
703
        self.writer_name = writer_name
636
704
 
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)
652
722
 
653
723
 
654
724
class HtmlPublishPartsTestSuite(CustomTestSuite):
655
725
 
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
665
737
                        continue
666
738
                self.addTestCase(
667
739
                      HtmlWriterPublishPartsTestCase, 'test_publish',
668
 
                      settings_overrides=settings_overrides,
669
740
                      input=case[0], expected=case[1],
670
741
                      id='%s[%r][%s]' % (dictname, name, casenum),
671
 
                      run_in_debugger=run_in_debugger)
 
742
                      run_in_debugger=run_in_debugger,
 
743
                      suite_settings=settings)
672
744
 
673
745
 
674
746
class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
679
751
 
680
752
    writer_name = 'html'
681
753
 
682
 
    def __init__(self, *args, **kwargs):
683
 
        self.settings_overrides = kwargs['settings_overrides']
684
 
        """Settings overrides to use for this test case."""
685
 
 
686
 
        del kwargs['settings_overrides'] # only wanted here
687
 
        CustomTestCase.__init__(self, *args, **kwargs)
 
754
    settings_default_overrides = \
 
755
        WriterPublishTestCase.settings_default_overrides.copy()
 
756
    settings_default_overrides['stylesheet'] = ''
688
757
 
689
758
    def test_publish(self):
690
759
        if self.run_in_debugger:
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)
703
772
 
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')
 
773
    
 
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">
 
786
"""
710
787
 
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))
 
826
 
 
827
 
 
828
def _format_str(*args):
 
829
    r"""
 
830
    Return a tuple containing representations of all args.
 
831
 
 
832
    Same as map(repr, args) except that it returns multi-line
 
833
    representations for strings containing newlines, e.g.::
 
834
 
 
835
        '''\
 
836
        foo  \n\
 
837
        bar
 
838
 
 
839
        baz'''
 
840
 
 
841
    instead of::
 
842
 
 
843
        'foo  \nbar\n\nbaz'
 
844
 
 
845
    This is a helper function for CustomTestCase.
 
846
    """
 
847
    import re
 
848
    return_tuple = []
 
849
    for i in args:
 
850
        r = repr(i)
 
851
        if ( (isinstance(i, StringType) or isinstance(i, UnicodeType))
 
852
             and '\n' in i):
 
853
            stripped = ''
 
854
            if isinstance(i, UnicodeType):
 
855
                # stripped = 'u' or 'U'
 
856
                stripped = r[0]
 
857
                r = r[1:]
 
858
            # quote_char = "'" or '"'
 
859
            quote_char = r[0]
 
860
            assert quote_char in ("'", '"')
 
861
            assert r[0] == r[-1]
 
862
            r = r[1:-1]
 
863
            r = (stripped + 3 * quote_char + '\\\n' +
 
864
                 re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
 
865
                 3 * quote_char)
 
866
            r = re.sub(r' \n', r' \\n\\\n', r)
 
867
        return_tuple.append(r)
 
868
    return tuple(return_tuple)