summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
committerwiemann <wiemann@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2006-01-09 20:44:25 +0000
commitd77fdfef70e08114f57cbef5d91707df8717ea9f (patch)
tree49444e3486c0c333cb7b33dfa721296c08ee4ece /test
parent53cd16ca6ca5f638cbe5956988e88f9339e355cf (diff)
parent3993c4097756e9885bcfbd07cb1cc1e4e95e50e4 (diff)
downloaddocutils-0.4.tar.gz
Release 0.4: tagging released revisiondocutils-0.4
git-svn-id: http://svn.code.sf.net/p/docutils/code/tags/docutils-0.4@4268 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'test')
-rw-r--r--test/DocutilsTestSupport.py868
-rwxr-xr-xtest/alltests.py98
-rwxr-xr-xtest/coverage.sh45
-rw-r--r--test/data/config_1.txt26
-rw-r--r--test/data/config_2.txt11
-rw-r--r--test/data/config_error_handler.txt2
-rw-r--r--test/data/config_list.txt8
-rw-r--r--test/data/config_list_2.txt2
-rw-r--r--test/data/config_old.txt14
-rw-r--r--test/data/csv_data.txt1
-rw-r--r--test/data/csv_dep.txt2
-rw-r--r--test/data/dependencies.txt8
-rw-r--r--test/data/include.txt1
-rw-r--r--test/data/raw.txt0
-rw-r--r--test/data/stylesheet.txt0
-rw-r--r--test/docutils.conf11
-rw-r--r--test/docutils_difflib.py1089
-rw-r--r--test/functional/README.txt5
-rw-r--r--test/functional/expected/compact_lists.html47
-rw-r--r--test/functional/expected/dangerous.html66
-rw-r--r--test/functional/expected/field_name_limit.html28
-rw-r--r--test/functional/expected/latex_docinfo.tex85
-rw-r--r--test/functional/expected/misc_rst_html4css1.html15
-rw-r--r--test/functional/expected/pep_html.html93
-rw-r--r--test/functional/expected/standalone_rst_html4css1.html1001
-rw-r--r--test/functional/expected/standalone_rst_latex.tex1556
-rw-r--r--test/functional/expected/standalone_rst_pseudoxml.txt1841
-rw-r--r--test/functional/expected/standalone_rst_s5_html_1.html152
-rw-r--r--test/functional/expected/standalone_rst_s5_html_2.html148
-rw-r--r--test/functional/expected/ui/default/blank.gifbin0 -> 49 bytes
-rw-r--r--test/functional/expected/ui/default/framing.css25
-rw-r--r--test/functional/expected/ui/default/iepngfix.htc42
-rw-r--r--test/functional/expected/ui/default/opera.css8
-rw-r--r--test/functional/expected/ui/default/outline.css16
-rw-r--r--test/functional/expected/ui/default/pretty.css120
-rw-r--r--test/functional/expected/ui/default/print.css24
-rw-r--r--test/functional/expected/ui/default/s5-core.css11
-rw-r--r--test/functional/expected/ui/default/slides.css10
-rw-r--r--test/functional/expected/ui/default/slides.js558
-rw-r--r--test/functional/expected/ui/small-black/blank.gifbin0 -> 49 bytes
-rw-r--r--test/functional/expected/ui/small-black/framing.css24
-rw-r--r--test/functional/expected/ui/small-black/iepngfix.htc42
-rw-r--r--test/functional/expected/ui/small-black/opera.css8
-rw-r--r--test/functional/expected/ui/small-black/outline.css16
-rw-r--r--test/functional/expected/ui/small-black/pretty.css116
-rw-r--r--test/functional/expected/ui/small-black/print.css24
-rw-r--r--test/functional/expected/ui/small-black/s5-core.css11
-rw-r--r--test/functional/expected/ui/small-black/slides.css10
-rw-r--r--test/functional/expected/ui/small-black/slides.js558
-rw-r--r--test/functional/input/compact_lists.txt39
-rw-r--r--test/functional/input/dangerous.txt16
-rw-r--r--test/functional/input/data/custom_roles.txt6
-rw-r--r--test/functional/input/data/errors.txt9
-rw-r--r--test/functional/input/data/header_footer.txt2
-rw-r--r--test/functional/input/data/latex.txt201
-rw-r--r--test/functional/input/data/list_table.txt24
-rw-r--r--test/functional/input/data/nonalphanumeric.txt13
-rw-r--r--test/functional/input/data/standard.txt753
-rw-r--r--test/functional/input/data/table_colspan.txt15
-rw-r--r--test/functional/input/data/table_complex.txt21
-rw-r--r--test/functional/input/data/table_rowspan.txt15
-rw-r--r--test/functional/input/data/unicode.txt27
-rw-r--r--test/functional/input/field_list.txt5
-rw-r--r--test/functional/input/latex_docinfo.txt10
-rw-r--r--test/functional/input/pep_html.txt32
-rw-r--r--test/functional/input/simple.txt1
-rw-r--r--test/functional/input/standalone_rst_html4css1.txt8
-rw-r--r--test/functional/input/standalone_rst_latex.txt12
-rw-r--r--test/functional/input/standalone_rst_newlatex.txt12
-rw-r--r--test/functional/input/standalone_rst_pseudoxml.txt7
-rw-r--r--test/functional/input/standalone_rst_s5_html.txt126
-rw-r--r--test/functional/output/README.txt3
-rw-r--r--test/functional/tests/_default.py7
-rw-r--r--test/functional/tests/_standalone_rst_defaults.py6
-rw-r--r--test/functional/tests/compact_lists.py11
-rw-r--r--test/functional/tests/dangerous.py12
-rw-r--r--test/functional/tests/field_name_limit.py12
-rw-r--r--test/functional/tests/latex_docinfo.py12
-rw-r--r--test/functional/tests/misc_rst_html4css1.py14
-rw-r--r--test/functional/tests/pep_html.py14
-rw-r--r--test/functional/tests/standalone_rst_html4css1.py10
-rw-r--r--test/functional/tests/standalone_rst_latex.py8
-rw-r--r--test/functional/tests/standalone_rst_pseudoxml.py8
-rwxr-xr-xtest/functional/tests/standalone_rst_s5_html_1.py56
-rwxr-xr-xtest/functional/tests/standalone_rst_s5_html_2.py7
-rw-r--r--test/package_unittest.py161
-rwxr-xr-xtest/test_dependencies.py78
-rwxr-xr-xtest/test_functional.py167
-rwxr-xr-xtest/test_io.py32
-rwxr-xr-xtest/test_language.py211
-rwxr-xr-xtest/test_nodes.py338
-rw-r--r--test/test_parsers/__init__.py14
-rw-r--r--test/test_parsers/test_rst/__init__.py14
-rw-r--r--test/test_parsers/test_rst/includes/include9.txt3
-rwxr-xr-xtest/test_parsers/test_rst/test_SimpleTableParser.py123
-rwxr-xr-xtest/test_parsers/test_rst/test_TableParser.py207
-rwxr-xr-xtest/test_parsers/test_rst/test_block_quotes.py273
-rwxr-xr-xtest/test_parsers/test_rst/test_bullet_lists.py181
-rwxr-xr-xtest/test_parsers/test_rst/test_citations.py139
-rwxr-xr-xtest/test_parsers/test_rst/test_comments.py319
-rwxr-xr-xtest/test_parsers/test_rst/test_definition_lists.py395
-rw-r--r--test/test_parsers/test_rst/test_directives/__init__.py14
-rw-r--r--test/test_parsers/test_rst/test_directives/empty.txt0
-rw-r--r--test/test_parsers/test_rst/test_directives/include 11.txt1
-rw-r--r--test/test_parsers/test_rst/test_directives/include1.txt4
-rw-r--r--test/test_parsers/test_rst/test_directives/include10.txt7
-rw-r--r--test/test_parsers/test_rst/test_directives/include2.txt5
-rw-r--r--test/test_parsers/test_rst/test_directives/include3.txt3
-rw-r--r--test/test_parsers/test_rst/test_directives/include8.txt3
-rw-r--r--test/test_parsers/test_rst/test_directives/includes/include4.txt3
-rw-r--r--test/test_parsers/test_rst/test_directives/includes/include5.txt3
-rw-r--r--test/test_parsers/test_rst/test_directives/includes/more/include6.txt3
-rw-r--r--test/test_parsers/test_rst/test_directives/includes/sibling/include7.txt1
-rw-r--r--test/test_parsers/test_rst/test_directives/raw1.txt1
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_admonitions.py184
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_compound.py106
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_container.py76
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_contents.py241
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_date.py53
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_decorations.py93
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_default_role.py84
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_figures.py294
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_images.py413
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_include.py412
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_line_blocks.py81
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_meta.py232
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_raw.py154
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_replace.py135
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_role.py230
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_rubrics.py74
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_sidebars.py73
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_tables.py997
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_target_notes.py64
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_test_directives.py208
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_topics.py240
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_unicode.py172
-rwxr-xr-xtest/test_parsers/test_rst/test_directives/test_unknown.py67
-rw-r--r--test/test_parsers/test_rst/test_directives/utf-16.csvbin0 -> 386 bytes
-rwxr-xr-xtest/test_parsers/test_rst/test_doctest_blocks.py74
-rwxr-xr-xtest/test_parsers/test_rst/test_east_asian_text.py324
-rwxr-xr-xtest/test_parsers/test_rst/test_enumerated_lists.py908
-rwxr-xr-xtest/test_parsers/test_rst/test_field_lists.py551
-rwxr-xr-xtest/test_parsers/test_rst/test_footnotes.py332
-rwxr-xr-xtest/test_parsers/test_rst/test_functions.py38
-rwxr-xr-xtest/test_parsers/test_rst/test_inline_markup.py924
-rwxr-xr-xtest/test_parsers/test_rst/test_interpreted.py305
-rwxr-xr-xtest/test_parsers/test_rst/test_line_blocks.py310
-rwxr-xr-xtest/test_parsers/test_rst/test_literal_blocks.py371
-rwxr-xr-xtest/test_parsers/test_rst/test_option_lists.py756
-rwxr-xr-xtest/test_parsers/test_rst/test_outdenting.py90
-rwxr-xr-xtest/test_parsers/test_rst/test_paragraphs.py89
-rwxr-xr-xtest/test_parsers/test_rst/test_section_headers.py897
-rwxr-xr-xtest/test_parsers/test_rst/test_substitutions.py298
-rwxr-xr-xtest/test_parsers/test_rst/test_tables.py1261
-rwxr-xr-xtest/test_parsers/test_rst/test_targets.py440
-rwxr-xr-xtest/test_parsers/test_rst/test_transitions.py309
-rwxr-xr-xtest/test_publisher.py143
-rw-r--r--test/test_readers/__init__.py14
-rw-r--r--test/test_readers/test_pep/__init__.py14
-rwxr-xr-xtest/test_readers/test_pep/test_inline_markup.py140
-rwxr-xr-xtest/test_readers/test_pep/test_rfc2822.py291
-rw-r--r--test/test_readers/test_python/__init__.py14
-rwxr-xr-xtest/test_readers/test_python/showast57
-rwxr-xr-xtest/test_readers/test_python/showdoc33
-rwxr-xr-xtest/test_readers/test_python/showparse48
-rwxr-xr-xtest/test_readers/test_python/showtok40
-rwxr-xr-xtest/test_readers/test_python/test_functions.py56
-rwxr-xr-xtest/test_readers/test_python/test_parser.py989
-rwxr-xr-xtest/test_readers/test_python/test_token_parser.py46
-rwxr-xr-xtest/test_settings.py167
-rwxr-xr-xtest/test_statemachine.py283
-rw-r--r--test/test_transforms/__init__.py14
-rwxr-xr-xtest/test_transforms/test___init__.py43
-rwxr-xr-xtest/test_transforms/test_class.py191
-rwxr-xr-xtest/test_transforms/test_contents.py434
-rwxr-xr-xtest/test_transforms/test_docinfo.py334
-rwxr-xr-xtest/test_transforms/test_doctitle.py231
-rwxr-xr-xtest/test_transforms/test_expose_internals.py42
-rwxr-xr-xtest/test_transforms/test_filter.py41
-rwxr-xr-xtest/test_transforms/test_footnotes.py545
-rwxr-xr-xtest/test_transforms/test_hyperlinks.py845
-rwxr-xr-xtest/test_transforms/test_messages.py66
-rwxr-xr-xtest/test_transforms/test_peps.py68
-rwxr-xr-xtest/test_transforms/test_sectnum.py381
-rwxr-xr-xtest/test_transforms/test_strip_comments.py49
-rwxr-xr-xtest/test_transforms/test_substitutions.py353
-rwxr-xr-xtest/test_transforms/test_target_notes.py84
-rwxr-xr-xtest/test_transforms/test_transitions.py308
-rwxr-xr-xtest/test_transforms/test_writer_aux.py57
-rwxr-xr-xtest/test_utils.py213
-rwxr-xr-xtest/test_viewlist.py166
-rw-r--r--test/test_writers/__init__.py14
-rwxr-xr-xtest/test_writers/test_docutils_xml.py86
-rwxr-xr-xtest/test_writers/test_html4css1.py373
-rwxr-xr-xtest/test_writers/test_html4css1_misc.py36
-rwxr-xr-xtest/test_writers/test_latex2e.py377
-rwxr-xr-xtest/test_writers/test_null.py31
-rwxr-xr-xtest/test_writers/test_pseudoxml.py54
198 files changed, 33814 insertions, 0 deletions
diff --git a/test/DocutilsTestSupport.py b/test/DocutilsTestSupport.py
new file mode 100644
index 000000000..c30b263d6
--- /dev/null
+++ b/test/DocutilsTestSupport.py
@@ -0,0 +1,868 @@
+# Authors: David Goodger; Garth Kidd
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Exports the following:
+
+:Modules:
+ - `statemachine` is 'docutils.statemachine'
+ - `nodes` is 'docutils.nodes'
+ - `urischemes` is 'docutils.urischemes'
+ - `utils` is 'docutils.utils'
+ - `transforms` is 'docutils.transforms'
+ - `states` is 'docutils.parsers.rst.states'
+ - `tableparser` is 'docutils.parsers.rst.tableparser'
+
+:Classes:
+ - `StandardTestCase`
+ - `CustomTestCase`
+ - `CustomTestSuite`
+ - `TransformTestCase`
+ - `TransformTestSuite`
+ - `ParserTestCase`
+ - `ParserTestSuite`
+ - `ParserTransformTestCase`
+ - `PEPParserTestCase`
+ - `PEPParserTestSuite`
+ - `GridTableParserTestCase`
+ - `GridTableParserTestSuite`
+ - `SimpleTableParserTestCase`
+ - `SimpleTableParserTestSuite`
+ - `WriterPublishTestCase`
+ - `LatexWriterPublishTestCase`
+ - `PseudoXMLWriterPublishTestCase`
+ - `HtmlWriterPublishTestCase`
+ - `PublishTestSuite`
+ - `HtmlFragmentTestSuite`
+ - `DevNull` (output sink)
+"""
+__docformat__ = 'reStructuredText'
+
+import sys
+import os
+
+testroot = os.path.abspath(os.path.dirname(__file__) or os.curdir)
+os.chdir(testroot)
+sys.path.insert(0, os.path.normpath(os.path.join(testroot, '..')))
+sys.path.insert(0, testroot)
+sys.path.append(os.path.normpath(os.path.join(testroot, '..', 'extras')))
+
+import unittest
+import docutils_difflib
+import inspect
+from pprint import pformat
+from types import UnicodeType, StringType
+import package_unittest
+import docutils
+import docutils.core
+from docutils import frontend, nodes, statemachine, urischemes, utils
+from docutils.transforms import universal
+from docutils.parsers import rst
+from docutils.parsers.rst import states, tableparser, roles, languages
+from docutils.readers import standalone, pep
+from docutils.statemachine import StringList, string2lines
+
+try:
+ from docutils.readers.python import moduleparser
+ from tokenize import generate_tokens
+ del generate_tokens
+except ImportError: # moduleparser depends on modules added in Python 2.2
+ moduleparser = None
+
+try:
+ import mypdb as pdb
+except:
+ import pdb
+
+
+# Hack to make repr(StringList) look like repr(list):
+StringList.__repr__ = StringList.__str__
+
+
+class DevNull:
+
+ """Output sink."""
+
+ def write(self, string):
+ pass
+
+ def close(self):
+ pass
+
+
+class StandardTestCase(unittest.TestCase):
+
+ """
+ Helper class, providing the same interface as unittest.TestCase,
+ but with useful setUp and comparison methods.
+ """
+
+ def setUp(self):
+ os.chdir(testroot)
+
+ def failUnlessEqual(self, first, second, msg=None):
+ """Fail if the two objects are unequal as determined by the '=='
+ operator.
+ """
+ if not first == second:
+ raise self.failureException, \
+ (msg or '%s != %s' % _format_str(first, second))
+
+ def failIfEqual(self, first, second, msg=None):
+ """Fail if the two objects are equal as determined by the '=='
+ operator.
+ """
+ if first == second:
+ raise self.failureException, \
+ (msg or '%s == %s' % _format_str(first, second))
+
+ # Synonyms for assertion methods
+
+ assertEqual = assertEquals = failUnlessEqual
+
+ assertNotEqual = assertNotEquals = failIfEqual
+
+
+class CustomTestCase(StandardTestCase):
+
+ """
+ Helper class, providing extended functionality over unittest.TestCase.
+
+ The methods failUnlessEqual and failIfEqual have been overwritten
+ to provide better support for multi-line strings. Furthermore,
+ see the compare_output method and the parameter list of __init__.
+ """
+
+ compare = docutils_difflib.Differ().compare
+ """Comparison method shared by all subclasses."""
+
+ def __init__(self, method_name, input, expected, id, run_in_debugger=0,
+ suite_settings=None):
+ """
+ Initialise the CustomTestCase.
+
+ Arguments:
+
+ method_name -- name of test method to run.
+ input -- input to the parser.
+ expected -- expected output from the parser.
+ id -- unique test identifier, used by the test framework.
+ run_in_debugger -- if true, run this test under the pdb debugger.
+ suite_settings -- settings overrides for this test suite.
+ """
+ self.id = id
+ self.input = input
+ self.expected = expected
+ self.run_in_debugger = run_in_debugger
+ self.suite_settings = suite_settings or {}
+
+ # Ring your mother.
+ unittest.TestCase.__init__(self, method_name)
+
+ def __str__(self):
+ """
+ Return string conversion. Overridden to give test id, in addition to
+ method name.
+ """
+ return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
+
+ def __repr__(self):
+ return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
+
+ def clear_roles(self):
+ # Language-specific roles and roles added by the
+ # "default-role" and "role" directives are currently stored
+ # globally in the roles._roles dictionary. This workaround
+ # empties that dictionary.
+ roles._roles = {}
+
+ def setUp(self):
+ StandardTestCase.setUp(self)
+ self.clear_roles()
+
+ def compare_output(self, input, output, expected):
+ """`input`, `output`, and `expected` should all be strings."""
+ if isinstance(input, UnicodeType):
+ input = input.encode('raw_unicode_escape')
+ if isinstance(output, UnicodeType):
+ output = output.encode('raw_unicode_escape')
+ if isinstance(expected, UnicodeType):
+ expected = expected.encode('raw_unicode_escape')
+ try:
+ self.assertEquals(output, expected)
+ except AssertionError, error:
+ print >>sys.stderr, '\n%s\ninput:' % (self,)
+ print >>sys.stderr, input
+ try:
+ comparison = ''.join(self.compare(expected.splitlines(1),
+ output.splitlines(1)))
+ print >>sys.stderr, '-: expected\n+: output'
+ print >>sys.stderr, comparison
+ except AttributeError: # expected or output not a string
+ # alternative output for non-strings:
+ print >>sys.stderr, 'expected: %r' % expected
+ print >>sys.stderr, 'output: %r' % output
+ raise error
+
+
+class CustomTestSuite(unittest.TestSuite):
+
+ """
+ A collection of CustomTestCases.
+
+ Provides test suite ID generation and a method for adding test cases.
+ """
+
+ id = ''
+ """Identifier for the TestSuite. Prepended to the
+ TestCase identifiers to make identification easier."""
+
+ next_test_case_id = 0
+ """The next identifier to use for non-identified test cases."""
+
+ def __init__(self, tests=(), id=None, suite_settings=None):
+ """
+ Initialize the CustomTestSuite.
+
+ Arguments:
+
+ id -- identifier for the suite, prepended to test cases.
+ suite_settings -- settings overrides for this test suite.
+ """
+ unittest.TestSuite.__init__(self, tests)
+ self.suite_settings = suite_settings or {}
+ if id is None:
+ mypath = os.path.abspath(
+ sys.modules[CustomTestSuite.__module__].__file__)
+ outerframes = inspect.getouterframes(inspect.currentframe())
+ for outerframe in outerframes[1:]:
+ if outerframe[3] != '__init__':
+ callerpath = outerframe[1]
+ if callerpath is None:
+ # It happens sometimes. Why is a mystery.
+ callerpath = os.getcwd()
+ callerpath = os.path.abspath(callerpath)
+ break
+ mydir, myname = os.path.split(mypath)
+ if not mydir:
+ mydir = os.curdir
+ if callerpath.startswith(mydir):
+ self.id = callerpath[len(mydir) + 1:] # caller's module
+ else:
+ self.id = callerpath
+ else:
+ self.id = id
+
+ def addTestCase(self, test_case_class, method_name, input, expected,
+ id=None, run_in_debugger=0, **kwargs):
+ """
+ Create a CustomTestCase in the CustomTestSuite.
+ Also return it, just in case.
+
+ Arguments:
+
+ test_case_class -- the CustomTestCase to add
+ method_name -- a string; CustomTestCase.method_name is the test
+ input -- input to the parser.
+ expected -- expected output from the parser.
+ id -- unique test identifier, used by the test framework.
+ run_in_debugger -- if true, run this test under the pdb debugger.
+ """
+ if id is None: # generate id if required
+ id = self.next_test_case_id
+ self.next_test_case_id += 1
+ # test identifier will become suiteid.testid
+ tcid = '%s: %s' % (self.id, id)
+ # suite_settings may be passed as a parameter;
+ # if not, set from attribute:
+ kwargs.setdefault('suite_settings', self.suite_settings)
+ # generate and add test case
+ tc = test_case_class(method_name, input, expected, tcid,
+ run_in_debugger=run_in_debugger, **kwargs)
+ self.addTest(tc)
+ return tc
+
+ def generate_no_tests(self, *args, **kwargs):
+ pass
+
+
+class TransformTestCase(CustomTestCase):
+
+ """
+ Output checker for the transform.
+
+ Should probably be called TransformOutputChecker, but I can deal with
+ that later when/if someone comes up with a category of transform test
+ cases that have nothing to do with the input and output of the transform.
+ """
+
+ option_parser = frontend.OptionParser(components=(rst.Parser,))
+ settings = option_parser.get_default_values()
+ settings.report_level = 1
+ settings.halt_level = 5
+ settings.debug = package_unittest.debug
+ settings.warning_stream = DevNull()
+ unknown_reference_resolvers = ()
+
+ def __init__(self, *args, **kwargs):
+ self.transforms = kwargs['transforms']
+ """List of transforms to perform for this test case."""
+
+ self.parser = kwargs['parser']
+ """Input parser for this test case."""
+
+ del kwargs['transforms'], kwargs['parser'] # only wanted here
+ CustomTestCase.__init__(self, *args, **kwargs)
+
+ def supports(self, format):
+ return 1
+
+ def test_transforms(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ settings = self.settings.copy()
+ settings.__dict__.update(self.suite_settings)
+ document = utils.new_document('test data', settings)
+ self.parser.parse(self.input, document)
+ # Don't do a ``populate_from_components()`` because that would
+ # enable the Transformer's default transforms.
+ document.transformer.add_transforms(self.transforms)
+ document.transformer.add_transform(universal.TestMessages)
+ document.transformer.components['writer'] = self
+ document.transformer.apply_transforms()
+ output = document.pformat()
+ self.compare_output(self.input, output, self.expected)
+
+ def test_transforms_verbosely(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ print '\n', self.id
+ print '-' * 70
+ print self.input
+ settings = self.settings.copy()
+ settings.__dict__.update(self.suite_settings)
+ document = utils.new_document('test data', settings)
+ self.parser.parse(self.input, document)
+ print '-' * 70
+ print document.pformat()
+ for transformClass in self.transforms:
+ transformClass(document).apply()
+ output = document.pformat()
+ print '-' * 70
+ print output
+ self.compare_output(self.input, output, self.expected)
+
+
+class TransformTestSuite(CustomTestSuite):
+
+ """
+ A collection of TransformTestCases.
+
+ A TransformTestSuite instance manufactures TransformTestCases,
+ keeps track of them, and provides a shared test fixture (a-la
+ setUp and tearDown).
+ """
+
+ def __init__(self, parser, suite_settings=None):
+ self.parser = parser
+ """Parser shared by all test cases."""
+
+ CustomTestSuite.__init__(self, suite_settings=suite_settings)
+
+ def generateTests(self, dict, dictname='totest',
+ testmethod='test_transforms'):
+ """
+ Stock the suite with test cases generated from a test data dictionary.
+
+ Each dictionary key (test type's name) maps to a tuple, whose
+ first item is a list of transform classes and whose second
+ item is a list of tests. Each test is a list: input, expected
+ output, optional modifier. The optional third entry, a
+ behavior modifier, can be 0 (temporarily disable this test) or
+ 1 (run this test under the pdb debugger). Tests should be
+ self-documenting and not require external comments.
+ """
+ for name, (transforms, cases) in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case)==3:
+ # TODO: (maybe) change the 3rd argument to a dict, so it
+ # can handle more cases by keyword ('disable', 'debug',
+ # 'settings'), here and in other generateTests methods.
+ # But there's also the method that
+ # HtmlPublishPartsTestSuite uses <DJG>
+ if case[2]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(
+ TransformTestCase, testmethod,
+ transforms=transforms, parser=self.parser,
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+
+
+class ParserTestCase(CustomTestCase):
+
+ """
+ Output checker for the parser.
+
+ Should probably be called ParserOutputChecker, but I can deal with
+ that later when/if someone comes up with a category of parser test
+ cases that have nothing to do with the input and output of the parser.
+ """
+
+ parser = rst.Parser()
+ """Parser shared by all ParserTestCases."""
+
+ option_parser = frontend.OptionParser(components=(rst.Parser,))
+ settings = option_parser.get_default_values()
+ settings.report_level = 5
+ settings.halt_level = 5
+ settings.debug = package_unittest.debug
+
+ def test_parser(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ settings = self.settings.copy()
+ settings.__dict__.update(self.suite_settings)
+ document = utils.new_document('test data', settings)
+ self.parser.parse(self.input, document)
+ output = document.pformat()
+ self.compare_output(self.input, output, self.expected)
+
+
+class ParserTestSuite(CustomTestSuite):
+
+ """
+ A collection of ParserTestCases.
+
+ A ParserTestSuite instance manufactures ParserTestCases,
+ keeps track of them, and provides a shared test fixture (a-la
+ setUp and tearDown).
+ """
+
+ test_case_class = ParserTestCase
+
+ def generateTests(self, dict, dictname='totest'):
+ """
+ Stock the suite with test cases generated from a test data dictionary.
+
+ Each dictionary key (test type name) maps to a list of tests. Each
+ test is a list: input, expected output, optional modifier. The
+ optional third entry, a behavior modifier, can be 0 (temporarily
+ disable this test) or 1 (run this test under the pdb debugger). Tests
+ should be self-documenting and not require external comments.
+ """
+ for name, cases in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case)==3:
+ if case[2]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(
+ self.test_case_class, 'test_parser',
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+
+
+class PEPParserTestCase(ParserTestCase):
+
+ """PEP-specific parser test case."""
+
+ parser = rst.Parser(rfc2822=1, inliner=rst.states.Inliner())
+ """Parser shared by all PEPParserTestCases."""
+
+ option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
+ settings = option_parser.get_default_values()
+ settings.report_level = 5
+ settings.halt_level = 5
+ settings.debug = package_unittest.debug
+
+
+class PEPParserTestSuite(ParserTestSuite):
+
+ """A collection of PEPParserTestCases."""
+
+ test_case_class = PEPParserTestCase
+
+
+class GridTableParserTestCase(CustomTestCase):
+
+ parser = tableparser.GridTableParser()
+
+ def test_parse_table(self):
+ self.parser.setup(StringList(string2lines(self.input), 'test data'))
+ try:
+ self.parser.find_head_body_sep()
+ self.parser.parse_table()
+ output = self.parser.cells
+ except Exception, details:
+ output = '%s: %s' % (details.__class__.__name__, details)
+ self.compare_output(self.input, pformat(output) + '\n',
+ pformat(self.expected) + '\n')
+
+ def test_parse(self):
+ try:
+ output = self.parser.parse(StringList(string2lines(self.input),
+ 'test data'))
+ except Exception, details:
+ output = '%s: %s' % (details.__class__.__name__, details)
+ self.compare_output(self.input, pformat(output) + '\n',
+ pformat(self.expected) + '\n')
+
+
+class GridTableParserTestSuite(CustomTestSuite):
+
+ """
+ A collection of GridTableParserTestCases.
+
+ A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
+ keeps track of them, and provides a shared test fixture (a-la setUp and
+ tearDown).
+ """
+
+ test_case_class = GridTableParserTestCase
+
+ def generateTests(self, dict, dictname='totest'):
+ """
+ Stock the suite with test cases generated from a test data dictionary.
+
+ Each dictionary key (test type name) maps to a list of tests. Each
+ test is a list: an input table, expected output from parse_table(),
+ expected output from parse(), optional modifier. The optional fourth
+ entry, a behavior modifier, can be 0 (temporarily disable this test)
+ or 1 (run this test under the pdb debugger). Tests should be
+ self-documenting and not require external comments.
+ """
+ for name, cases in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case) == 4:
+ if case[-1]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(self.test_case_class, 'test_parse_table',
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+ self.addTestCase(self.test_case_class, 'test_parse',
+ input=case[0], expected=case[2],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+
+
+class SimpleTableParserTestCase(GridTableParserTestCase):
+
+ parser = tableparser.SimpleTableParser()
+
+
+class SimpleTableParserTestSuite(CustomTestSuite):
+
+ """
+ A collection of SimpleTableParserTestCases.
+ """
+
+ test_case_class = SimpleTableParserTestCase
+
+ def generateTests(self, dict, dictname='totest'):
+ """
+ Stock the suite with test cases generated from a test data dictionary.
+
+ Each dictionary key (test type name) maps to a list of tests. Each
+ test is a list: an input table, expected output from parse(), optional
+ modifier. The optional third entry, a behavior modifier, can be 0
+ (temporarily disable this test) or 1 (run this test under the pdb
+ debugger). Tests should be self-documenting and not require external
+ comments.
+ """
+ for name, cases in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case) == 3:
+ if case[-1]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(self.test_case_class, 'test_parse',
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+
+
+class PythonModuleParserTestCase(CustomTestCase):
+
+ def test_parser(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ module = moduleparser.parse_module(self.input, 'test data').pformat()
+ output = str(module)
+ self.compare_output(self.input, output, self.expected)
+
+ def test_token_parser_rhs(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ tr = moduleparser.TokenParser(self.input)
+ output = tr.rhs(1)
+ self.compare_output(self.input, output, self.expected)
+
+
+class PythonModuleParserTestSuite(CustomTestSuite):
+
+ """
+ A collection of PythonModuleParserTestCase.
+ """
+
+ notified = None
+
+ def __init__(self, *args, **kwargs):
+ if moduleparser is None:
+ if not self.notified:
+ print ('Tests of docutils.readers.python skipped; '
+ 'Python 2.2 or higher required.')
+ PythonModuleParserTestSuite.notified = 1
+ self.generateTests = self.generate_no_tests
+ CustomTestSuite.__init__(self, *args, **kwargs)
+
+ def generateTests(self, dict, dictname='totest',
+ testmethod='test_parser'):
+ """
+ Stock the suite with test cases generated from a test data dictionary.
+
+ Each dictionary key (test type's name) maps to a list of tests. Each
+ test is a list: input, expected output, optional modifier. The
+ optional third entry, a behavior modifier, can be 0 (temporarily
+ disable this test) or 1 (run this test under the pdb debugger). Tests
+ should be self-documenting and not require external comments.
+ """
+ for name, cases in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case)==3:
+ if case[2]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(
+ PythonModuleParserTestCase, testmethod,
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger)
+
+
+class WriterPublishTestCase(CustomTestCase, docutils.SettingsSpec):
+
+ """
+ Test case for publish.
+ """
+
+ settings_default_overrides = {'_disable_config': 1,
+ 'strict_visitor': 1}
+ writer_name = '' # set in subclasses or constructor
+
+ def __init__(self, *args, **kwargs):
+ if kwargs.has_key('writer_name'):
+ self.writer_name = kwargs['writer_name']
+ del kwargs['writer_name']
+ CustomTestCase.__init__(self, *args, **kwargs)
+
+ def test_publish(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ output = docutils.core.publish_string(
+ source=self.input,
+ reader_name='standalone',
+ parser_name='restructuredtext',
+ writer_name=self.writer_name,
+ settings_spec=self,
+ settings_overrides=self.suite_settings)
+ self.compare_output(self.input, output, self.expected)
+
+
+class PublishTestSuite(CustomTestSuite):
+
+ def __init__(self, writer_name, suite_settings=None):
+ """
+ `writer_name` is the name of the writer to use.
+ """
+ CustomTestSuite.__init__(self, suite_settings=suite_settings)
+ self.test_class = WriterPublishTestCase
+ self.writer_name = writer_name
+
+ def generateTests(self, dict, dictname='totest'):
+ for name, cases in dict.items():
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case)==3:
+ if case[2]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(
+ self.test_class, 'test_publish',
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger,
+ # Passed to constructor of self.test_class:
+ writer_name=self.writer_name)
+
+
+class HtmlPublishPartsTestSuite(CustomTestSuite):
+
+ def generateTests(self, dict, dictname='totest'):
+ for name, (settings_overrides, cases) in dict.items():
+ settings = self.suite_settings.copy()
+ settings.update(settings_overrides)
+ for casenum in range(len(cases)):
+ case = cases[casenum]
+ run_in_debugger = 0
+ if len(case)==3:
+ if case[2]:
+ run_in_debugger = 1
+ else:
+ continue
+ self.addTestCase(
+ HtmlWriterPublishPartsTestCase, 'test_publish',
+ input=case[0], expected=case[1],
+ id='%s[%r][%s]' % (dictname, name, casenum),
+ run_in_debugger=run_in_debugger,
+ suite_settings=settings)
+
+
+class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
+
+ """
+ Test case for HTML writer via the publish_parts interface.
+ """
+
+ writer_name = 'html'
+
+ settings_default_overrides = \
+ WriterPublishTestCase.settings_default_overrides.copy()
+ settings_default_overrides['stylesheet'] = ''
+
+ def test_publish(self):
+ if self.run_in_debugger:
+ pdb.set_trace()
+ parts = docutils.core.publish_parts(
+ source=self.input,
+ reader_name='standalone',
+ parser_name='restructuredtext',
+ writer_name=self.writer_name,
+ settings_spec=self,
+ settings_overrides=self.suite_settings)
+ output = self.format_output(parts)
+ # interpolate standard variables:
+ expected = self.expected % {'version': docutils.__version__}
+ self.compare_output(self.input, output, expected)
+
+
+ standard_content_type_template = ('<meta http-equiv="Content-Type"'
+ ' content="text/html; charset=%s" />\n')
+ standard_generator_template = (
+ '<meta name="generator"'
+ ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
+ standard_html_meta_value = (
+ standard_content_type_template
+ + standard_generator_template % docutils.__version__)
+ standard_meta_value = standard_html_meta_value % 'utf-8'
+ standard_html_prolog = """\
+<?xml version="1.0" encoding="%s" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+"""
+
+ def format_output(self, parts):
+ """Minimize & standardize the output."""
+ # remove redundant parts:
+ del parts['whole']
+ assert parts['body'] == parts['fragment']
+ del parts['body']
+ # remove standard portions:
+ parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
+ parts['html_head'] = parts['html_head'].replace(
+ self.standard_html_meta_value, '...')
+ parts['html_prolog'] = parts['html_prolog'].replace(
+ self.standard_html_prolog, '')
+ # remove empty values:
+ for key in parts.keys():
+ if not parts[key]:
+ del parts[key]
+ # standard output format:
+ keys = parts.keys()
+ keys.sort()
+ output = []
+ for key in keys:
+ output.append("%r: '''%s'''"
+ % (key, parts[key].encode('raw_unicode_escape')))
+ if output[-1].endswith("\n'''"):
+ output[-1] = output[-1][:-4] + "\\n'''"
+ return '{' + ',\n '.join(output) + '}\n'
+
+
+def exception_data(code):
+ """
+ Execute `code` and return the resulting exception, the exception arguments,
+ and the formatted exception string.
+ """
+ try:
+ exec(code)
+ except Exception, detail:
+ return (detail, detail.args,
+ '%s: %s' % (detail.__class__.__name__, detail))
+
+
+def _format_str(*args):
+ r"""
+ Return a tuple containing representations of all args.
+
+ Same as map(repr, args) except that it returns multi-line
+ representations for strings containing newlines, e.g.::
+
+ '''\
+ foo \n\
+ bar
+
+ baz'''
+
+ instead of::
+
+ 'foo \nbar\n\nbaz'
+
+ This is a helper function for CustomTestCase.
+ """
+ import re
+ return_tuple = []
+ for i in args:
+ r = repr(i)
+ if ( (isinstance(i, StringType) or isinstance(i, UnicodeType))
+ and '\n' in i):
+ stripped = ''
+ if isinstance(i, UnicodeType):
+ # stripped = 'u' or 'U'
+ stripped = r[0]
+ r = r[1:]
+ # quote_char = "'" or '"'
+ quote_char = r[0]
+ assert quote_char in ("'", '"')
+ assert r[0] == r[-1]
+ r = r[1:-1]
+ r = (stripped + 3 * quote_char + '\\\n' +
+ re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
+ 3 * quote_char)
+ r = re.sub(r' \n', r' \\n\\\n', r)
+ return_tuple.append(r)
+ return tuple(return_tuple)
diff --git a/test/alltests.py b/test/alltests.py
new file mode 100755
index 000000000..b28541af1
--- /dev/null
+++ b/test/alltests.py
@@ -0,0 +1,98 @@
+#!/bin/sh
+''''exec python -u "$0" "$@" #'''
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+__doc__ = \
+"""
+All modules named 'test_*.py' in the current directory, and recursively in
+subdirectories (packages) called 'test_*', are loaded and test suites within
+are run.
+"""
+
+import time
+# Start point for actual elapsed time, including imports
+# and setup outside of unittest.
+start = time.time()
+
+import sys
+import os
+from types import UnicodeType
+import DocutilsTestSupport # must be imported before docutils
+import docutils
+
+
+def new_exception_str(self):
+ for i in self.args:
+ if isinstance(i, UnicodeType):
+ raise RuntimeError('Error (unicode): %r' % (self.args,))
+ return old_exception_str(self)
+
+old_exception_str = Exception.__str__
+Exception.__str__ = new_exception_str
+
+
+class Tee:
+
+ """Write to a file and a stream (default: stdout) simultaneously."""
+
+ def __init__(self, filename, stream=sys.__stdout__):
+ self.file = open(filename, 'w')
+ self.stream = stream
+
+ def write(self, string):
+ self.stream.write(string)
+ self.file.write(string)
+
+ def flush(self):
+ self.stream.flush()
+ self.file.flush()
+
+
+def pformat(suite):
+ step = 4
+ suitestr = repr(suite).replace('=[<', '=[\n<').replace(', ', ',\n')
+ indent = 0
+ output = []
+ for line in suitestr.splitlines():
+ output.append(' ' * indent + line)
+ if line[-1:] == '[':
+ indent += step
+ else:
+ if line [-5:] == ']>]>,':
+ indent -= step * 2
+ elif line[-3:] == ']>,':
+ indent -= step
+ return '\n'.join(output)
+
+def suite():
+ path, script = os.path.split(sys.argv[0])
+ suite = package_unittest.loadTestModules(DocutilsTestSupport.testroot,
+ 'test_', packages=1)
+ sys.stdout.flush()
+ return suite
+
+# must redirect stderr *before* first import of unittest
+sys.stdout = sys.stderr = Tee('alltests.out')
+
+import package_unittest
+
+
+if __name__ == '__main__':
+ suite = suite()
+ print ('Testing Docutils %s [%s] with Python %s on %s at %s'
+ % (docutils.__version__, docutils.__version_details__,
+ sys.version.split()[0],
+ time.strftime('%Y-%m-%d'), time.strftime('%H:%M:%S')))
+ print 'Working directory: %s' % os.getcwd()
+ print 'Docutils package: %s' % os.path.dirname(docutils.__file__)
+ sys.stdout.flush()
+ package_unittest.main(suite)
+ #if package_unittest.verbosity > 1:
+ # print >>sys.stderr, pformat(suite) # check the test suite
+ finish = time.time()
+ print 'Elapsed time: %.3f seconds' % (finish - start)
diff --git a/test/coverage.sh b/test/coverage.sh
new file mode 100755
index 000000000..3edea0e2a
--- /dev/null
+++ b/test/coverage.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This script has been placed in the public domain.
+
+set -e
+proj="${PWD##*/}"
+if test "$proj" == test; then
+ cd ..
+ proj="${PWD##*/}"
+fi
+if test "$1"; then
+ proj="$1"
+fi
+echo "Performing code coverage test for project \"$proj\"..."
+echo
+echo "Please be patient; coverage tracking slows test execution down by more"
+echo "than factor 10."
+echo
+cd test
+rm -rf cover
+mkdir -p cover
+python -u -m trace --count --coverdir=cover --missing alltests.py
+cd ..
+echo
+echo
+echo Uncovered lines
+echo ===============
+echo
+(
+ find "$proj" -name \*.py | while read i; do
+ i="${i%.py}"
+ test -f test/cover/"${i//\//.}".cover -o "${i##*/}" == Template || echo "${i//\//.}" "`cat "$i.py" | wc -l`"
+ done
+ cd test/cover
+ find . \( -name . -o ! -name "$proj".\* -exec rm {} \; \)
+ for i in *.cover; do
+ sed 's/^>>>>>> \(.*"""\)/ \1/' < "$i" > "${i%.cover}"
+ rm "$i"
+ done
+ for i in *; do echo -n "$i "; grep -c '^>>>>>> ' "$i" || true; done
+) | grep -v ' 0$' | sort -nk 2
diff --git a/test/data/config_1.txt b/test/data/config_1.txt
new file mode 100644
index 000000000..b19a213b3
--- /dev/null
+++ b/test/data/config_1.txt
@@ -0,0 +1,26 @@
+# Test config file (new format)
+
+[general]
+
+source-link: on
+datestamp: %Y-%m-%d %H:%M UTC
+generator: true
+
+
+[restructuredtext parser]
+
+trim-footnote-reference-space: 1
+tab-width = 8
+
+
+[html4css1 writer]
+
+stylesheet-path: stylesheets/default.css
+
+
+[pep_html writer]
+
+template: pep-html-template
+stylesheet-path: stylesheets/pep.css
+python-home: http://www.python.org
+no-random: yes
diff --git a/test/data/config_2.txt b/test/data/config_2.txt
new file mode 100644
index 000000000..35c307c6c
--- /dev/null
+++ b/test/data/config_2.txt
@@ -0,0 +1,11 @@
+# Test config file (new format)
+
+[general]
+
+generator: no
+
+
+[html4css1 writer]
+
+footnote-references: superscript
+stylesheet-path: test.css
diff --git a/test/data/config_error_handler.txt b/test/data/config_error_handler.txt
new file mode 100644
index 000000000..82e341649
--- /dev/null
+++ b/test/data/config_error_handler.txt
@@ -0,0 +1,2 @@
+[general]
+error_encoding: ascii:strict
diff --git a/test/data/config_list.txt b/test/data/config_list.txt
new file mode 100644
index 000000000..fde6793c9
--- /dev/null
+++ b/test/data/config_list.txt
@@ -0,0 +1,8 @@
+[general]
+expose_internals: a
+
+[html4css1 writer]
+expose_internals: b:c:d
+
+[pep_html writer]
+expose_internals: e
diff --git a/test/data/config_list_2.txt b/test/data/config_list_2.txt
new file mode 100644
index 000000000..6f8d69f07
--- /dev/null
+++ b/test/data/config_list_2.txt
@@ -0,0 +1,2 @@
+[general]
+expose_internals: f
diff --git a/test/data/config_old.txt b/test/data/config_old.txt
new file mode 100644
index 000000000..fa07d6dab
--- /dev/null
+++ b/test/data/config_old.txt
@@ -0,0 +1,14 @@
+# Test config file (old format)
+
+[options]
+
+source-link: 1
+datestamp: %Y-%m-%d %H:%M UTC
+generator: 1
+
+stylesheet-path: stylesheets/default.css
+
+pep-template: pep-html-template
+pep-stylesheet-path: stylesheets/pep.css
+python-home: http://www.python.org
+no-random: 1
diff --git a/test/data/csv_data.txt b/test/data/csv_data.txt
new file mode 100644
index 000000000..f33f47f7f
--- /dev/null
+++ b/test/data/csv_data.txt
@@ -0,0 +1 @@
+foo, bar
diff --git a/test/data/csv_dep.txt b/test/data/csv_dep.txt
new file mode 100644
index 000000000..14620a926
--- /dev/null
+++ b/test/data/csv_dep.txt
@@ -0,0 +1,2 @@
+.. csv-table::
+ :file: csv_data.txt
diff --git a/test/data/dependencies.txt b/test/data/dependencies.txt
new file mode 100644
index 000000000..cc18c8f0c
--- /dev/null
+++ b/test/data/dependencies.txt
@@ -0,0 +1,8 @@
+.. image:: some_image.png
+
+.. include:: include.txt
+
+.. raw:: HTML
+ :file: raw.txt
+
+.. include:: include.txt
diff --git a/test/data/include.txt b/test/data/include.txt
new file mode 100644
index 000000000..ae2a894bb
--- /dev/null
+++ b/test/data/include.txt
@@ -0,0 +1 @@
+Some include text.
diff --git a/test/data/raw.txt b/test/data/raw.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/data/raw.txt
diff --git a/test/data/stylesheet.txt b/test/data/stylesheet.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/data/stylesheet.txt
diff --git a/test/docutils.conf b/test/docutils.conf
new file mode 100644
index 000000000..df4b1e46a
--- /dev/null
+++ b/test/docutils.conf
@@ -0,0 +1,11 @@
+[general]
+# This tests the test framework; this config file should *not* be read
+# when testing.
+source-link: yes
+datestamp: %Y-%m-%d %H:%M UTC (If you see this in test output, there's a bug in the test code!)
+generator: on
+
+[buildhtml application]
+# This part is not for testing, but to prevent tools/buildhtml.py from
+# processing text files in and below this directory.
+prune: .
diff --git a/test/docutils_difflib.py b/test/docutils_difflib.py
new file mode 100644
index 000000000..a41d4d5ba
--- /dev/null
+++ b/test/docutils_difflib.py
@@ -0,0 +1,1089 @@
+#! /usr/bin/env python
+
+"""
+Module difflib -- helpers for computing deltas between objects.
+
+Function get_close_matches(word, possibilities, n=3, cutoff=0.6):
+ Use SequenceMatcher to return list of the best "good enough" matches.
+
+Function ndiff(a, b):
+ Return a delta: the difference between `a` and `b` (lists of strings).
+
+Function restore(delta, which):
+ Return one of the two sequences that generated an ndiff delta.
+
+Class SequenceMatcher:
+ A flexible class for comparing pairs of sequences of any type.
+
+Class Differ:
+ For producing human-readable deltas from sequences of lines of text.
+"""
+
+__all__ = ['get_close_matches', 'ndiff', 'restore', 'SequenceMatcher',
+ 'Differ']
+
+TRACE = 0
+
+class SequenceMatcher:
+
+ """
+ SequenceMatcher is a flexible class for comparing pairs of sequences of
+ any type, so long as the sequence elements are hashable. The basic
+ algorithm predates, and is a little fancier than, an algorithm
+ published in the late 1980's by Ratcliff and Obershelp under the
+ hyperbolic name "gestalt pattern matching". The basic idea is to find
+ the longest contiguous matching subsequence that contains no "junk"
+ elements (R-O doesn't address junk). The same idea is then applied
+ recursively to the pieces of the sequences to the left and to the right
+ of the matching subsequence. This does not yield minimal edit
+ sequences, but does tend to yield matches that "look right" to people.
+
+ SequenceMatcher tries to compute a "human-friendly diff" between two
+ sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+ longest *contiguous* & junk-free matching subsequence. That's what
+ catches peoples' eyes. The Windows(tm) windiff has another interesting
+ notion, pairing up elements that appear uniquely in each sequence.
+ That, and the method here, appear to yield more intuitive difference
+ reports than does diff. This method appears to be the least vulnerable
+ to synching up on blocks of "junk lines", though (like blank lines in
+ ordinary text files, or maybe "<P>" lines in HTML files). That may be
+ because this is the only method of the 3 that has a *concept* of
+ "junk" <wink>.
+
+ Example, comparing two strings, and considering blanks to be "junk":
+
+ >>> s = SequenceMatcher(lambda x: x == " ",
+ ... "private Thread currentThread;",
+ ... "private volatile Thread currentThread;")
+ >>>
+
+ .ratio() returns a float in [0, 1], measuring the "similarity" of the
+ sequences. As a rule of thumb, a .ratio() value over 0.6 means the
+ sequences are close matches:
+
+ >>> print round(s.ratio(), 3)
+ 0.866
+ >>>
+
+ If you're only interested in where the sequences match,
+ .get_matching_blocks() is handy:
+
+ >>> for block in s.get_matching_blocks():
+ ... print "a[%d] and b[%d] match for %d elements" % block
+ a[0] and b[0] match for 8 elements
+ a[8] and b[17] match for 6 elements
+ a[14] and b[23] match for 15 elements
+ a[29] and b[38] match for 0 elements
+
+ Note that the last tuple returned by .get_matching_blocks() is always a
+ dummy, (len(a), len(b), 0), and this is the only case in which the last
+ tuple element (number of elements matched) is 0.
+
+ If you want to know how to change the first sequence into the second,
+ use .get_opcodes():
+
+ >>> for opcode in s.get_opcodes():
+ ... print "%6s a[%d:%d] b[%d:%d]" % opcode
+ equal a[0:8] b[0:8]
+ insert a[8:8] b[8:17]
+ equal a[8:14] b[17:23]
+ equal a[14:29] b[23:38]
+
+ See the Differ class for a fancy human-friendly file differencer, which
+ uses SequenceMatcher both to compare sequences of lines, and to compare
+ sequences of characters within similar (near-matching) lines.
+
+ See also function get_close_matches() in this module, which shows how
+ simple code building on SequenceMatcher can be used to do useful work.
+
+ Timing: Basic R-O is cubic time worst case and quadratic time expected
+ case. SequenceMatcher is quadratic time for the worst case and has
+ expected-case behavior dependent in a complicated way on how many
+ elements the sequences have in common; best case time is linear.
+
+ Methods:
+
+ __init__(isjunk=None, a='', b='')
+ Construct a SequenceMatcher.
+
+ set_seqs(a, b)
+ Set the two sequences to be compared.
+
+ set_seq1(a)
+ Set the first sequence to be compared.
+
+ set_seq2(b)
+ Set the second sequence to be compared.
+
+ find_longest_match(alo, ahi, blo, bhi)
+ Find longest matching block in a[alo:ahi] and b[blo:bhi].
+
+ get_matching_blocks()
+ Return list of triples describing matching subsequences.
+
+ get_opcodes()
+ Return list of 5-tuples describing how to turn a into b.
+
+ ratio()
+ Return a measure of the sequences' similarity (float in [0,1]).
+
+ quick_ratio()
+ Return an upper bound on .ratio() relatively quickly.
+
+ real_quick_ratio()
+ Return an upper bound on ratio() very quickly.
+ """
+
+ def __init__(self, isjunk=None, a='', b=''):
+ """Construct a SequenceMatcher.
+
+ Optional arg isjunk is None (the default), or a one-argument
+ function that takes a sequence element and returns true iff the
+ element is junk. None is equivalent to passing "lambda x: 0", i.e.
+ no elements are considered to be junk. For example, pass
+ lambda x: x in " \\t"
+ if you're comparing lines as sequences of characters, and don't
+ want to synch up on blanks or hard tabs.
+
+ Optional arg a is the first of two sequences to be compared. By
+ default, an empty string. The elements of a must be hashable. See
+ also .set_seqs() and .set_seq1().
+
+ Optional arg b is the second of two sequences to be compared. By
+ default, an empty string. The elements of b must be hashable. See
+ also .set_seqs() and .set_seq2().
+ """
+
+ # Members:
+ # a
+ # first sequence
+ # b
+ # second sequence; differences are computed as "what do
+ # we need to do to 'a' to change it into 'b'?"
+ # b2j
+ # for x in b, b2j[x] is a list of the indices (into b)
+ # at which x appears; junk elements do not appear
+ # b2jhas
+ # b2j.has_key
+ # fullbcount
+ # for x in b, fullbcount[x] == the number of times x
+ # appears in b; only materialized if really needed (used
+ # only for computing quick_ratio())
+ # matching_blocks
+ # a list of (i, j, k) triples, where a[i:i+k] == b[j:j+k];
+ # ascending & non-overlapping in i and in j; terminated by
+ # a dummy (len(a), len(b), 0) sentinel
+ # opcodes
+ # a list of (tag, i1, i2, j1, j2) tuples, where tag is
+ # one of
+ # 'replace' a[i1:i2] should be replaced by b[j1:j2]
+ # 'delete' a[i1:i2] should be deleted
+ # 'insert' b[j1:j2] should be inserted
+ # 'equal' a[i1:i2] == b[j1:j2]
+ # isjunk
+ # a user-supplied function taking a sequence element and
+ # returning true iff the element is "junk" -- this has
+ # subtle but helpful effects on the algorithm, which I'll
+ # get around to writing up someday <0.9 wink>.
+ # DON'T USE! Only __chain_b uses this. Use isbjunk.
+ # isbjunk
+ # for x in b, isbjunk(x) == isjunk(x) but much faster;
+ # it's really the has_key method of a hidden dict.
+ # DOES NOT WORK for x in a!
+
+ self.isjunk = isjunk
+ self.a = self.b = None
+ self.set_seqs(a, b)
+
+ def set_seqs(self, a, b):
+ """Set the two sequences to be compared.
+
+ >>> s = SequenceMatcher()
+ >>> s.set_seqs("abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ """
+
+ self.set_seq1(a)
+ self.set_seq2(b)
+
+ def set_seq1(self, a):
+ """Set the first sequence to be compared.
+
+ The second sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq1("bcde")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against
+ many sequences, use .set_seq2(S) once and call .set_seq1(x)
+ repeatedly for each of the other sequences.
+
+ See also set_seqs() and set_seq2().
+ """
+
+ if a is self.a:
+ return
+ self.a = a
+ self.matching_blocks = self.opcodes = None
+
+ def set_seq2(self, b):
+ """Set the second sequence to be compared.
+
+ The first sequence to be compared is not changed.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.set_seq2("abcd")
+ >>> s.ratio()
+ 1.0
+ >>>
+
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against
+ many sequences, use .set_seq2(S) once and call .set_seq1(x)
+ repeatedly for each of the other sequences.
+
+ See also set_seqs() and set_seq1().
+ """
+
+ if b is self.b:
+ return
+ self.b = b
+ self.matching_blocks = self.opcodes = None
+ self.fullbcount = None
+ self.__chain_b()
+
+ # For each element x in b, set b2j[x] to a list of the indices in
+ # b where x appears; the indices are in increasing order; note that
+ # the number of times x appears in b is len(b2j[x]) ...
+ # when self.isjunk is defined, junk elements don't show up in this
+ # map at all, which stops the central find_longest_match method
+ # from starting any matching block at a junk element ...
+ # also creates the fast isbjunk function ...
+ # note that this is only called when b changes; so for cross-product
+ # kinds of matches, it's best to call set_seq2 once, then set_seq1
+ # repeatedly
+
+ def __chain_b(self):
+ # Because isjunk is a user-defined (not C) function, and we test
+ # for junk a LOT, it's important to minimize the number of calls.
+ # Before the tricks described here, __chain_b was by far the most
+ # time-consuming routine in the whole module! If anyone sees
+ # Jim Roskind, thank him again for profile.py -- I never would
+ # have guessed that.
+ # The first trick is to build b2j ignoring the possibility
+ # of junk. I.e., we don't call isjunk at all yet. Throwing
+ # out the junk later is much cheaper than building b2j "right"
+ # from the start.
+ b = self.b
+ self.b2j = b2j = {}
+ self.b2jhas = b2jhas = b2j.has_key
+ for i in xrange(len(b)):
+ elt = b[i]
+ if b2jhas(elt):
+ b2j[elt].append(i)
+ else:
+ b2j[elt] = [i]
+
+ # Now b2j.keys() contains elements uniquely, and especially when
+ # the sequence is a string, that's usually a good deal smaller
+ # than len(string). The difference is the number of isjunk calls
+ # saved.
+ isjunk, junkdict = self.isjunk, {}
+ if isjunk:
+ for elt in b2j.keys():
+ if isjunk(elt):
+ junkdict[elt] = 1 # value irrelevant; it's a set
+ del b2j[elt]
+
+ # Now for x in b, isjunk(x) == junkdict.has_key(x), but the
+ # latter is much faster. Note too that while there may be a
+ # lot of junk in the sequence, the number of *unique* junk
+ # elements is probably small. So the memory burden of keeping
+ # this dict alive is likely trivial compared to the size of b2j.
+ self.isbjunk = junkdict.has_key
+
+ def find_longest_match(self, alo, ahi, blo, bhi):
+ """Find longest matching block in a[alo:ahi] and b[blo:bhi].
+
+ If isjunk is not defined:
+
+ Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
+ alo <= i <= i+k <= ahi
+ blo <= j <= j+k <= bhi
+ and for all (i',j',k') meeting those conditions,
+ k >= k'
+ i <= i'
+ and if i == i', j <= j'
+
+ In other words, of all maximal matching blocks, return one that
+ starts earliest in a, and of all those maximal matching blocks that
+ start earliest in a, return the one that starts earliest in b.
+
+ >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (0, 4, 5)
+
+ If isjunk is defined, first the longest matching block is
+ determined as above, but with the additional restriction that no
+ junk element appears in the block. Then that block is extended as
+ far as possible by matching (only) junk elements on both sides. So
+ the resulting block never matches on junk except as identical junk
+ happens to be adjacent to an "interesting" match.
+
+ Here's the same example as before, but considering blanks to be
+ junk. That prevents " abcd" from matching the " abcd" at the tail
+ end of the second sequence directly. Instead only the "abcd" can
+ match, and matches the leftmost "abcd" in the second sequence:
+
+ >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
+ >>> s.find_longest_match(0, 5, 0, 9)
+ (1, 0, 4)
+
+ If no blocks match, return (alo, blo, 0).
+
+ >>> s = SequenceMatcher(None, "ab", "c")
+ >>> s.find_longest_match(0, 2, 0, 1)
+ (0, 0, 0)
+ """
+
+ # CAUTION: stripping common prefix or suffix would be incorrect.
+ # E.g.,
+ # ab
+ # acab
+ # Longest matching block is "ab", but if common prefix is
+ # stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
+ # strip, so ends up claiming that ab is changed to acab by
+ # inserting "ca" in the middle. That's minimal but unintuitive:
+ # "it's obvious" that someone inserted "ac" at the front.
+ # Windiff ends up at the same place as diff, but by pairing up
+ # the unique 'b's and then matching the first two 'a's.
+
+ a, b, b2j, isbjunk = self.a, self.b, self.b2j, self.isbjunk
+ besti, bestj, bestsize = alo, blo, 0
+ # find longest junk-free match
+ # during an iteration of the loop, j2len[j] = length of longest
+ # junk-free match ending with a[i-1] and b[j]
+ j2len = {}
+ nothing = []
+ for i in xrange(alo, ahi):
+ # look at all instances of a[i] in b; note that because
+ # b2j has no junk keys, the loop is skipped if a[i] is junk
+ j2lenget = j2len.get
+ newj2len = {}
+ for j in b2j.get(a[i], nothing):
+ # a[i] matches b[j]
+ if j < blo:
+ continue
+ if j >= bhi:
+ break
+ k = newj2len[j] = j2lenget(j-1, 0) + 1
+ if k > bestsize:
+ besti, bestj, bestsize = i-k+1, j-k+1, k
+ j2len = newj2len
+
+ # Now that we have a wholly interesting match (albeit possibly
+ # empty!), we may as well suck up the matching junk on each
+ # side of it too. Can't think of a good reason not to, and it
+ # saves post-processing the (possibly considerable) expense of
+ # figuring out what to do with it. In the case of an empty
+ # interesting match, this is clearly the right thing to do,
+ # because no other kind of match is possible in the regions.
+ while besti > alo and bestj > blo and \
+ isbjunk(b[bestj-1]) and \
+ a[besti-1] == b[bestj-1]:
+ besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
+ while besti+bestsize < ahi and bestj+bestsize < bhi and \
+ isbjunk(b[bestj+bestsize]) and \
+ a[besti+bestsize] == b[bestj+bestsize]:
+ bestsize = bestsize + 1
+
+ if TRACE:
+ print "get_matching_blocks", alo, ahi, blo, bhi
+ print " returns", besti, bestj, bestsize
+ return besti, bestj, bestsize
+
+ def get_matching_blocks(self):
+ """Return list of triples describing matching subsequences.
+
+ Each triple is of the form (i, j, n), and means that
+ a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
+ i and in j.
+
+ The last triple is a dummy, (len(a), len(b), 0), and is the only
+ triple with n==0.
+
+ >>> s = SequenceMatcher(None, "abxcd", "abcd")
+ >>> s.get_matching_blocks()
+ [(0, 0, 2), (3, 2, 2), (5, 4, 0)]
+ """
+
+ if self.matching_blocks is not None:
+ return self.matching_blocks
+ self.matching_blocks = []
+ la, lb = len(self.a), len(self.b)
+ self.__helper(0, la, 0, lb, self.matching_blocks)
+ self.matching_blocks.append( (la, lb, 0) )
+ if TRACE:
+ print '*** matching blocks', self.matching_blocks
+ return self.matching_blocks
+
+ # builds list of matching blocks covering a[alo:ahi] and
+ # b[blo:bhi], appending them in increasing order to answer
+
+ def __helper(self, alo, ahi, blo, bhi, answer):
+ i, j, k = x = self.find_longest_match(alo, ahi, blo, bhi)
+ # a[alo:i] vs b[blo:j] unknown
+ # a[i:i+k] same as b[j:j+k]
+ # a[i+k:ahi] vs b[j+k:bhi] unknown
+ if k:
+ if alo < i and blo < j:
+ self.__helper(alo, i, blo, j, answer)
+ answer.append(x)
+ if i+k < ahi and j+k < bhi:
+ self.__helper(i+k, ahi, j+k, bhi, answer)
+
+ def get_opcodes(self):
+ """Return list of 5-tuples describing how to turn a into b.
+
+ Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
+ has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
+ tuple preceding it, and likewise for j1 == the previous j2.
+
+ The tags are strings, with these meanings:
+
+ 'replace': a[i1:i2] should be replaced by b[j1:j2]
+ 'delete': a[i1:i2] should be deleted.
+ Note that j1==j2 in this case.
+ 'insert': b[j1:j2] should be inserted at a[i1:i1].
+ Note that i1==i2 in this case.
+ 'equal': a[i1:i2] == b[j1:j2]
+
+ >>> a = "qabxcd"
+ >>> b = "abycdf"
+ >>> s = SequenceMatcher(None, a, b)
+ >>> for tag, i1, i2, j1, j2 in s.get_opcodes():
+ ... print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" %
+ ... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2]))
+ delete a[0:1] (q) b[0:0] ()
+ equal a[1:3] (ab) b[0:2] (ab)
+ replace a[3:4] (x) b[2:3] (y)
+ equal a[4:6] (cd) b[3:5] (cd)
+ insert a[6:6] () b[5:6] (f)
+ """
+
+ if self.opcodes is not None:
+ return self.opcodes
+ i = j = 0
+ self.opcodes = answer = []
+ for ai, bj, size in self.get_matching_blocks():
+ # invariant: we've pumped out correct diffs to change
+ # a[:i] into b[:j], and the next matching block is
+ # a[ai:ai+size] == b[bj:bj+size]. So we need to pump
+ # out a diff to change a[i:ai] into b[j:bj], pump out
+ # the matching block, and move (i,j) beyond the match
+ tag = ''
+ if i < ai and j < bj:
+ tag = 'replace'
+ elif i < ai:
+ tag = 'delete'
+ elif j < bj:
+ tag = 'insert'
+ if tag:
+ answer.append( (tag, i, ai, j, bj) )
+ i, j = ai+size, bj+size
+ # the list of matching blocks is terminated by a
+ # sentinel with size 0
+ if size:
+ answer.append( ('equal', ai, i, bj, j) )
+ return answer
+
+ def ratio(self):
+ """Return a measure of the sequences' similarity (float in [0,1]).
+
+ Where T is the total number of elements in both sequences, and
+ M is the number of matches, this is 2,0*M / T.
+ Note that this is 1 if the sequences are identical, and 0 if
+ they have nothing in common.
+
+ .ratio() is expensive to compute if you haven't already computed
+ .get_matching_blocks() or .get_opcodes(), in which case you may
+ want to try .quick_ratio() or .real_quick_ratio() first to get an
+ upper bound.
+
+ >>> s = SequenceMatcher(None, "abcd", "bcde")
+ >>> s.ratio()
+ 0.75
+ >>> s.quick_ratio()
+ 0.75
+ >>> s.real_quick_ratio()
+ 1.0
+ """
+
+ matches = reduce(lambda sum, triple: sum + triple[-1],
+ self.get_matching_blocks(), 0)
+ return 2.0 * matches / (len(self.a) + len(self.b))
+
+ def quick_ratio(self):
+ """Return an upper bound on ratio() relatively quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute.
+ """
+
+ # viewing a and b as multisets, set matches to the cardinality
+ # of their intersection; this counts the number of matches
+ # without regard to order, so is clearly an upper bound
+ if self.fullbcount is None:
+ self.fullbcount = fullbcount = {}
+ for elt in self.b:
+ fullbcount[elt] = fullbcount.get(elt, 0) + 1
+ fullbcount = self.fullbcount
+ # avail[x] is the number of times x appears in 'b' less the
+ # number of times we've seen it in 'a' so far ... kinda
+ avail = {}
+ availhas, matches = avail.has_key, 0
+ for elt in self.a:
+ if availhas(elt):
+ numb = avail[elt]
+ else:
+ numb = fullbcount.get(elt, 0)
+ avail[elt] = numb - 1
+ if numb > 0:
+ matches = matches + 1
+ return 2.0 * matches / (len(self.a) + len(self.b))
+
+ def real_quick_ratio(self):
+ """Return an upper bound on ratio() very quickly.
+
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute than either .ratio() or .quick_ratio().
+ """
+
+ la, lb = len(self.a), len(self.b)
+ # can't have more matches than the number of elements in the
+ # shorter sequence
+ return 2.0 * min(la, lb) / (la + lb)
+
+def get_close_matches(word, possibilities, n=3, cutoff=0.6):
+ """Use SequenceMatcher to return list of the best "good enough" matches.
+
+ word is a sequence for which close matches are desired (typically a
+ string).
+
+ possibilities is a list of sequences against which to match word
+ (typically a list of strings).
+
+ Optional arg n (default 3) is the maximum number of close matches to
+ return. n must be > 0.
+
+ Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
+ that don't score at least that similar to word are ignored.
+
+ The best (no more than n) matches among the possibilities are returned
+ in a list, sorted by similarity score, most similar first.
+
+ >>> get_close_matches("appel", ["ape", "apple", "peach", "puppy"])
+ ['apple', 'ape']
+ >>> import keyword as _keyword
+ >>> get_close_matches("wheel", _keyword.kwlist)
+ ['while']
+ >>> get_close_matches("apple", _keyword.kwlist)
+ []
+ >>> get_close_matches("accept", _keyword.kwlist)
+ ['except']
+ """
+
+ if not n > 0:
+ raise ValueError("n must be > 0: " + `n`)
+ if not 0.0 <= cutoff <= 1.0:
+ raise ValueError("cutoff must be in [0.0, 1.0]: " + `cutoff`)
+ result = []
+ s = SequenceMatcher()
+ s.set_seq2(word)
+ for x in possibilities:
+ s.set_seq1(x)
+ if s.real_quick_ratio() >= cutoff and \
+ s.quick_ratio() >= cutoff and \
+ s.ratio() >= cutoff:
+ result.append((s.ratio(), x))
+ # Sort by score.
+ result.sort()
+ # Retain only the best n.
+ result = result[-n:]
+ # Move best-scorer to head of list.
+ result.reverse()
+ # Strip scores.
+ return [x for score, x in result]
+
+
+def _count_leading(line, ch):
+ """
+ Return number of `ch` characters at the start of `line`.
+
+ Example:
+
+ >>> _count_leading(' abc', ' ')
+ 3
+ """
+
+ i, n = 0, len(line)
+ while i < n and line[i] == ch:
+ i += 1
+ return i
+
+class Differ:
+ r"""
+ Differ is a class for comparing sequences of lines of text, and
+ producing human-readable differences or deltas. Differ uses
+ SequenceMatcher both to compare sequences of lines, and to compare
+ sequences of characters within similar (near-matching) lines.
+
+ Each line of a Differ delta begins with a two-letter code:
+
+ '- ' line unique to sequence 1
+ '+ ' line unique to sequence 2
+ ' ' line common to both sequences
+ '? ' line not present in either input sequence
+
+ Lines beginning with '? ' attempt to guide the eye to intraline
+ differences, and were not present in either input sequence. These lines
+ can be confusing if the sequences contain tab characters.
+
+ Note that Differ makes no claim to produce a *minimal* diff. To the
+ contrary, minimal diffs are often counter-intuitive, because they synch
+ up anywhere possible, sometimes accidental matches 100 pages apart.
+ Restricting synch points to contiguous matches preserves some notion of
+ locality, at the occasional cost of producing a longer diff.
+
+ Example: Comparing two texts.
+
+ First we set up the texts, sequences of individual single-line strings
+ ending with newlines (such sequences can also be obtained from the
+ `readlines()` method of file-like objects):
+
+ >>> text1 = ''' 1. Beautiful is better than ugly.
+ ... 2. Explicit is better than implicit.
+ ... 3. Simple is better than complex.
+ ... 4. Complex is better than complicated.
+ ... '''.splitlines(1)
+ >>> len(text1)
+ 4
+ >>> text1[0][-1]
+ '\n'
+ >>> text2 = ''' 1. Beautiful is better than ugly.
+ ... 3. Simple is better than complex.
+ ... 4. Complicated is better than complex.
+ ... 5. Flat is better than nested.
+ ... '''.splitlines(1)
+
+ Next we instantiate a Differ object:
+
+ >>> d = Differ()
+
+ Note that when instantiating a Differ object we may pass functions to
+ filter out line and character 'junk'. See Differ.__init__ for details.
+
+ Finally, we compare the two:
+
+ >>> result = d.compare(text1, text2)
+
+ 'result' is a list of strings, so let's pretty-print it:
+
+ >>> from pprint import pprint as _pprint
+ >>> _pprint(result)
+ [' 1. Beautiful is better than ugly.\n',
+ '- 2. Explicit is better than implicit.\n',
+ '- 3. Simple is better than complex.\n',
+ '+ 3. Simple is better than complex.\n',
+ '? ++\n',
+ '- 4. Complex is better than complicated.\n',
+ '? ^ ---- ^\n',
+ '+ 4. Complicated is better than complex.\n',
+ '? ++++ ^ ^\n',
+ '+ 5. Flat is better than nested.\n']
+
+ As a single multi-line string it looks like this:
+
+ >>> print ''.join(result),
+ 1. Beautiful is better than ugly.
+ - 2. Explicit is better than implicit.
+ - 3. Simple is better than complex.
+ + 3. Simple is better than complex.
+ ? ++
+ - 4. Complex is better than complicated.
+ ? ^ ---- ^
+ + 4. Complicated is better than complex.
+ ? ++++ ^ ^
+ + 5. Flat is better than nested.
+
+ Methods:
+
+ __init__(linejunk=None, charjunk=None)
+ Construct a text differencer, with optional filters.
+
+ compare(a, b)
+ Compare two sequences of lines; return the resulting delta (list).
+ """
+
+ def __init__(self, linejunk=None, charjunk=None):
+ """
+ Construct a text differencer, with optional filters.
+
+ The two optional keyword parameters are for filter functions:
+
+ - `linejunk`: A function that should accept a single string argument,
+ and return true iff the string is junk. The module-level function
+ `IS_LINE_JUNK` may be used to filter out lines without visible
+ characters, except for at most one splat ('#').
+
+ - `charjunk`: A function that should accept a string of length 1. The
+ module-level function `IS_CHARACTER_JUNK` may be used to filter out
+ whitespace characters (a blank or tab; **note**: bad idea to include
+ newline in this!).
+ """
+
+ self.linejunk = linejunk
+ self.charjunk = charjunk
+ self.results = []
+
+ def compare(self, a, b):
+ r"""
+ Compare two sequences of lines; return the resulting delta (list).
+
+ Each sequence must contain individual single-line strings ending with
+ newlines. Such sequences can be obtained from the `readlines()` method
+ of file-like objects. The list returned is also made up of
+ newline-terminated strings, ready to be used with the `writelines()`
+ method of a file-like object.
+
+ Example:
+
+ >>> print ''.join(Differ().compare('one\ntwo\nthree\n'.splitlines(1),
+ ... 'ore\ntree\nemu\n'.splitlines(1))),
+ - one
+ ? ^
+ + ore
+ ? ^
+ - two
+ - three
+ ? -
+ + tree
+ + emu
+ """
+
+ cruncher = SequenceMatcher(self.linejunk, a, b)
+ for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
+ if tag == 'replace':
+ self._fancy_replace(a, alo, ahi, b, blo, bhi)
+ elif tag == 'delete':
+ self._dump('-', a, alo, ahi)
+ elif tag == 'insert':
+ self._dump('+', b, blo, bhi)
+ elif tag == 'equal':
+ self._dump(' ', a, alo, ahi)
+ else:
+ raise ValueError, 'unknown tag ' + `tag`
+ results = self.results
+ self.results = []
+ return results
+
+ def _dump(self, tag, x, lo, hi):
+ """Store comparison results for a same-tagged range."""
+ for i in xrange(lo, hi):
+ self.results.append('%s %s' % (tag, x[i]))
+
+ def _plain_replace(self, a, alo, ahi, b, blo, bhi):
+ assert alo < ahi and blo < bhi
+ # dump the shorter block first -- reduces the burden on short-term
+ # memory if the blocks are of very different sizes
+ if bhi - blo < ahi - alo:
+ self._dump('+', b, blo, bhi)
+ self._dump('-', a, alo, ahi)
+ else:
+ self._dump('-', a, alo, ahi)
+ self._dump('+', b, blo, bhi)
+
+ def _fancy_replace(self, a, alo, ahi, b, blo, bhi):
+ r"""
+ When replacing one block of lines with another, search the blocks
+ for *similar* lines; the best-matching pair (if any) is used as a
+ synch point, and intraline difference marking is done on the
+ similar pair. Lots of work, but often worth it.
+
+ Example:
+
+ >>> d = Differ()
+ >>> d._fancy_replace(['abcDefghiJkl\n'], 0, 1, ['abcdefGhijkl\n'], 0, 1)
+ >>> print ''.join(d.results),
+ - abcDefghiJkl
+ ? ^ ^ ^
+ + abcdefGhijkl
+ ? ^ ^ ^
+ """
+
+ if TRACE:
+ self.results.append('*** _fancy_replace %s %s %s %s\n'
+ % (alo, ahi, blo, bhi))
+ self._dump('>', a, alo, ahi)
+ self._dump('<', b, blo, bhi)
+
+ # don't synch up unless the lines have a similarity score of at
+ # least cutoff; best_ratio tracks the best score seen so far
+ best_ratio, cutoff = 0.74, 0.75
+ cruncher = SequenceMatcher(self.charjunk)
+ eqi, eqj = None, None # 1st indices of equal lines (if any)
+
+ # search for the pair that matches best without being identical
+ # (identical lines must be junk lines, & we don't want to synch up
+ # on junk -- unless we have to)
+ for j in xrange(blo, bhi):
+ bj = b[j]
+ cruncher.set_seq2(bj)
+ for i in xrange(alo, ahi):
+ ai = a[i]
+ if ai == bj:
+ if eqi is None:
+ eqi, eqj = i, j
+ continue
+ cruncher.set_seq1(ai)
+ # computing similarity is expensive, so use the quick
+ # upper bounds first -- have seen this speed up messy
+ # compares by a factor of 3.
+ # note that ratio() is only expensive to compute the first
+ # time it's called on a sequence pair; the expensive part
+ # of the computation is cached by cruncher
+ if cruncher.real_quick_ratio() > best_ratio and \
+ cruncher.quick_ratio() > best_ratio and \
+ cruncher.ratio() > best_ratio:
+ best_ratio, best_i, best_j = cruncher.ratio(), i, j
+ if best_ratio < cutoff:
+ # no non-identical "pretty close" pair
+ if eqi is None:
+ # no identical pair either -- treat it as a straight replace
+ self._plain_replace(a, alo, ahi, b, blo, bhi)
+ return
+ # no close pair, but an identical pair -- synch up on that
+ best_i, best_j, best_ratio = eqi, eqj, 1.0
+ else:
+ # there's a close pair, so forget the identical pair (if any)
+ eqi = None
+
+ # a[best_i] very similar to b[best_j]; eqi is None iff they're not
+ # identical
+ if TRACE:
+ self.results.append('*** best_ratio %s %s %s %s\n'
+ % (best_ratio, best_i, best_j))
+ self._dump('>', a, best_i, best_i+1)
+ self._dump('<', b, best_j, best_j+1)
+
+ # pump out diffs from before the synch point
+ self._fancy_helper(a, alo, best_i, b, blo, best_j)
+
+ # do intraline marking on the synch pair
+ aelt, belt = a[best_i], b[best_j]
+ if eqi is None:
+ # pump out a '-', '?', '+', '?' quad for the synched lines
+ atags = btags = ""
+ cruncher.set_seqs(aelt, belt)
+ for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
+ la, lb = ai2 - ai1, bj2 - bj1
+ if tag == 'replace':
+ atags += '^' * la
+ btags += '^' * lb
+ elif tag == 'delete':
+ atags += '-' * la
+ elif tag == 'insert':
+ btags += '+' * lb
+ elif tag == 'equal':
+ atags += ' ' * la
+ btags += ' ' * lb
+ else:
+ raise ValueError, 'unknown tag ' + `tag`
+ self._qformat(aelt, belt, atags, btags)
+ else:
+ # the synch pair is identical
+ self.results.append(' ' + aelt)
+
+ # pump out diffs from after the synch point
+ self._fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
+
+ def _fancy_helper(self, a, alo, ahi, b, blo, bhi):
+ if alo < ahi:
+ if blo < bhi:
+ self._fancy_replace(a, alo, ahi, b, blo, bhi)
+ else:
+ self._dump('-', a, alo, ahi)
+ elif blo < bhi:
+ self._dump('+', b, blo, bhi)
+
+ def _qformat(self, aline, bline, atags, btags):
+ r"""
+ Format "?" output and deal with leading tabs.
+
+ Example:
+
+ >>> d = Differ()
+ >>> d._qformat('\tabcDefghiJkl\n', '\t\tabcdefGhijkl\n',
+ ... ' ^ ^ ^ ', '+ ^ ^ ^ ')
+ >>> for line in d.results: print repr(line)
+ ...
+ '- \tabcDefghiJkl\n'
+ '? \t ^ ^ ^\n'
+ '+ \t\tabcdefGhijkl\n'
+ '? \t ^ ^ ^\n'
+ """
+
+ # Can hurt, but will probably help most of the time.
+ common = min(_count_leading(aline, "\t"),
+ _count_leading(bline, "\t"))
+ common = min(common, _count_leading(atags[:common], " "))
+ atags = atags[common:].rstrip()
+ btags = btags[common:].rstrip()
+
+ self.results.append("- " + aline)
+ if atags:
+ self.results.append("? %s%s\n" % ("\t" * common, atags))
+
+ self.results.append("+ " + bline)
+ if btags:
+ self.results.append("? %s%s\n" % ("\t" * common, btags))
+
+# With respect to junk, an earlier version of ndiff simply refused to
+# *start* a match with a junk element. The result was cases like this:
+# before: private Thread currentThread;
+# after: private volatile Thread currentThread;
+# If you consider whitespace to be junk, the longest contiguous match
+# not starting with junk is "e Thread currentThread". So ndiff reported
+# that "e volatil" was inserted between the 't' and the 'e' in "private".
+# While an accurate view, to people that's absurd. The current version
+# looks for matching blocks that are entirely junk-free, then extends the
+# longest one of those as far as possible but only with matching junk.
+# So now "currentThread" is matched, then extended to suck up the
+# preceding blank; then "private" is matched, and extended to suck up the
+# following blank; then "Thread" is matched; and finally ndiff reports
+# that "volatile " was inserted before "Thread". The only quibble
+# remaining is that perhaps it was really the case that " volatile"
+# was inserted after "private". I can live with that <wink>.
+
+import re
+
+def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match):
+ r"""
+ Return 1 for ignorable line: iff `line` is blank or contains a single '#'.
+
+ Examples:
+
+ >>> IS_LINE_JUNK('\n')
+ 1
+ >>> IS_LINE_JUNK(' # \n')
+ 1
+ >>> IS_LINE_JUNK('hello\n')
+ 0
+ """
+
+ return pat(line) is not None
+
+def IS_CHARACTER_JUNK(ch, ws=" \t"):
+ r"""
+ Return 1 for ignorable character: iff `ch` is a space or tab.
+
+ Examples:
+
+ >>> IS_CHARACTER_JUNK(' ')
+ 1
+ >>> IS_CHARACTER_JUNK('\t')
+ 1
+ >>> IS_CHARACTER_JUNK('\n')
+ 0
+ >>> IS_CHARACTER_JUNK('x')
+ 0
+ """
+
+ return ch in ws
+
+del re
+
+def ndiff(a, b, linejunk=IS_LINE_JUNK, charjunk=IS_CHARACTER_JUNK):
+ r"""
+ Compare `a` and `b` (lists of strings); return a `Differ`-style delta.
+
+ Optional keyword parameters `linejunk` and `charjunk` are for filter
+ functions (or None):
+
+ - linejunk: A function that should accept a single string argument, and
+ return true iff the string is junk. The default is module-level function
+ IS_LINE_JUNK, which filters out lines without visible characters, except
+ for at most one splat ('#').
+
+ - charjunk: A function that should accept a string of length 1. The
+ default is module-level function IS_CHARACTER_JUNK, which filters out
+ whitespace characters (a blank or tab; note: bad idea to include newline
+ in this!).
+
+ Tools/scripts/ndiff.py is a command-line front-end to this function.
+
+ Example:
+
+ >>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1),
+ ... 'ore\ntree\nemu\n'.splitlines(1))
+ >>> print ''.join(diff),
+ - one
+ ? ^
+ + ore
+ ? ^
+ - two
+ - three
+ ? -
+ + tree
+ + emu
+ """
+ return Differ(linejunk, charjunk).compare(a, b)
+
+def restore(delta, which):
+ r"""
+ Return one of the two sequences that generated a delta.
+
+ Given a `delta` produced by `Differ.compare()` or `ndiff()`, extract
+ lines originating from file 1 or 2 (parameter `which`), stripping off line
+ prefixes.
+
+ Examples:
+
+ >>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1),
+ ... 'ore\ntree\nemu\n'.splitlines(1))
+ >>> print ''.join(restore(diff, 1)),
+ one
+ two
+ three
+ >>> print ''.join(restore(diff, 2)),
+ ore
+ tree
+ emu
+ """
+ try:
+ tag = {1: "- ", 2: "+ "}[int(which)]
+ except KeyError:
+ raise ValueError, ('unknown delta choice (must be 1 or 2): %r'
+ % which)
+ prefixes = (" ", tag)
+ results = []
+ for line in delta:
+ if line[:2] in prefixes:
+ results.append(line[2:])
+ return results
+
+def _test():
+ import doctest, difflib
+ return doctest.testmod(difflib)
+
+if __name__ == "__main__":
+ _test()
diff --git a/test/functional/README.txt b/test/functional/README.txt
new file mode 100644
index 000000000..fc104d52e
--- /dev/null
+++ b/test/functional/README.txt
@@ -0,0 +1,5 @@
+This directory stores data files for functional tests.
+
+Please see the documentation on `functional testing`__ for details.
+
+__ ../../docs/dev/testing.html#functional
diff --git a/test/functional/expected/compact_lists.html b/test/functional/expected/compact_lists.html
new file mode 100644
index 000000000..a486f378a
--- /dev/null
+++ b/test/functional/expected/compact_lists.html
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title></title>
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+</head>
+<body>
+<div class="document">
+<ul class="simple">
+<li>This is an ordinary simple bullet list.</li>
+<li>It should be made compact (&lt;p&gt; &amp; &lt;/p&gt; tags omitted).</li>
+</ul>
+<hr class="docutils" />
+<ul>
+<li><p class="first">This is a bullet list that is not simple.</p>
+<p>There are multiple paragraphs in some items.</p>
+</li>
+<li><p class="first">It should not be made compact.</p>
+</li>
+<li><p class="first">Even though some items may have only one paragraph.</p>
+</li>
+</ul>
+<hr class="docutils" />
+<ul class="open">
+<li><p class="first">This is a simple bullet list, but class=&quot;open&quot; is set.</p>
+</li>
+<li><p class="first">It should not be made compact.</p>
+</li>
+</ul>
+<hr class="docutils" />
+<ul class="compact simple">
+<li>This is a bullet list that is not simple.<p>There are multiple paragraphs in some items.</p>
+</li>
+<li>However, the class=&quot;compact&quot; setting will cause
+all first paragraph's &lt;p&gt; &amp; &lt;/p&gt; tags to be omitted.</li>
+<li>Items with multiple paragraphs will not appear changed.</li>
+<li>Items may have one paragraph, or multiple.<p>Items with multiple paragraphs will still be followed
+by vertical whitespace because of the later paragraphs.</p>
+</li>
+<li>The effect is interesting.</li>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/dangerous.html b/test/functional/expected/dangerous.html
new file mode 100644
index 000000000..bba9f3408
--- /dev/null
+++ b/test/functional/expected/dangerous.html
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title></title>
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+</head>
+<body>
+<div class="document">
+<p>Potentially dangerous features (security holes):</p>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 3)</p>
+<p>&quot;include&quot; directive disabled.</p>
+<pre class="literal-block">
+.. include:: /etc/passwd
+</pre>
+</div>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 4)</p>
+<p>&quot;raw&quot; directive disabled.</p>
+<pre class="literal-block">
+.. raw:: html
+ :file: /etc/passwd
+</pre>
+</div>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 6)</p>
+<p>&quot;raw&quot; directive disabled.</p>
+<pre class="literal-block">
+.. raw:: html
+ :url: file:///etc/passwd
+</pre>
+</div>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 8)</p>
+<p>&quot;raw&quot; directive disabled.</p>
+<pre class="literal-block">
+.. raw:: html
+
+ &lt;script&gt;
+ that does something really nasty
+ &lt;/script&gt;
+</pre>
+</div>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 13)</p>
+<p>File and URL access deactivated; ignoring &quot;csv-table&quot; directive.</p>
+<pre class="literal-block">
+.. csv-table:: :file: /etc/passwd
+</pre>
+</div>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">functional/input/dangerous.txt</tt>, line 14)</p>
+<p>File and URL access deactivated; ignoring &quot;csv-table&quot; directive.</p>
+<pre class="literal-block">
+.. csv-table:: :url: file:///etc/passwd
+</pre>
+</div>
+<div class="figure">
+<img alt="picture.png" src="picture.png" />
+</div>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/field_name_limit.html b/test/functional/expected/field_name_limit.html
new file mode 100644
index 000000000..b4148c043
--- /dev/null
+++ b/test/functional/expected/field_name_limit.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title></title>
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+</head>
+<body>
+<div class="document">
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">short:</th><td class="field-body">This field's name is short.</td>
+</tr>
+<tr class="field"><th class="field-name">medium-length:</th><td class="field-body">This field's name is medium-length.</td>
+</tr>
+<tr class="field"><th class="field-name">long field name:</th><td class="field-body">This field's name is long.</td>
+</tr>
+<tr class="field"><th class="field-name">very very long field name:</th><td class="field-body">This field's name is quite long.</td>
+</tr>
+</tbody>
+</table>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/latex_docinfo.tex b/test/functional/expected/latex_docinfo.tex
new file mode 100644
index 000000000..04d9438f7
--- /dev/null
+++ b/test/functional/expected/latex_docinfo.tex
@@ -0,0 +1,85 @@
+\documentclass[10pt,a4paper,english]{article}
+\usepackage{babel}
+\usepackage{ae}
+\usepackage{aeguill}
+\usepackage{shortvrb}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\usepackage{longtable}
+\setlength{\extrarowheight}{2pt}
+\usepackage{amsmath}
+\usepackage{graphicx}
+\usepackage{color}
+\usepackage{multirow}
+\usepackage{ifthen}
+\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+\usepackage[DIV12]{typearea}
+%% generator Docutils: http://docutils.sourceforge.net/
+\newlength{\admonitionwidth}
+\setlength{\admonitionwidth}{0.9\textwidth}
+\newlength{\docinfowidth}
+\setlength{\docinfowidth}{0.9\textwidth}
+\newlength{\locallinewidth}
+\newcommand{\optionlistlabel}[1]{\bf #1 \hfill}
+\newenvironment{optionlist}[1]
+{\begin{list}{}
+ {\setlength{\labelwidth}{#1}
+ \setlength{\rightmargin}{1cm}
+ \setlength{\leftmargin}{\rightmargin}
+ \addtolength{\leftmargin}{\labelwidth}
+ \addtolength{\leftmargin}{\labelsep}
+ \renewcommand{\makelabel}{\optionlistlabel}}
+}{\end{list}}
+\newlength{\lineblockindentation}
+\setlength{\lineblockindentation}{2.5em}
+\newenvironment{lineblock}[1]
+{\begin{list}{}
+ {\setlength{\partopsep}{\parskip}
+ \addtolength{\partopsep}{\baselineskip}
+ \topsep0pt\itemsep0.15\baselineskip\parsep0pt
+ \leftmargin#1}
+ \raggedright}
+{\end{list}}
+% begin: floats for footnotes tweaking.
+\setlength{\floatsep}{0.5em}
+\setlength{\textfloatsep}{\fill}
+\addtolength{\textfloatsep}{3em}
+\renewcommand{\textfraction}{0.5}
+\renewcommand{\topfraction}{0.5}
+\renewcommand{\bottomfraction}{0.5}
+\setcounter{totalnumber}{50}
+\setcounter{topnumber}{50}
+\setcounter{bottomnumber}{50}
+% end floats for footnotes
+% some commands, that could be overwritten in the style file.
+\newcommand{\rubric}[1]{\subsection*{~\hfill {\it #1} \hfill ~}}
+\newcommand{\titlereference}[1]{\textsl{#1}}
+% end of "some commands"
+\title{}
+\author{Foo Fred~\\
+Food Foomatics {\&} Friends~\\
+foo@food.example.info~\\
+Fox St 13~\\
+Foowood \and
+Bar Barney~\\
+Bar-BQ Bar~\\
+1-800-BARBQBAR~\\
+Barbara St 16~\\
+South Barwell}
+\date{}
+\hypersetup{
+pdfauthor={Foo Fred;Bar Barney}
+}
+\raggedbottom
+\begin{document}
+\maketitle
+
+%___________________________________________________________________________
+\begin{center}
+\begin{tabularx}{\docinfowidth}{lX}
+\end{tabularx}
+\end{center}
+
+\setlength{\locallinewidth}{\linewidth}
+
+\end{document}
diff --git a/test/functional/expected/misc_rst_html4css1.html b/test/functional/expected/misc_rst_html4css1.html
new file mode 100644
index 000000000..f91844693
--- /dev/null
+++ b/test/functional/expected/misc_rst_html4css1.html
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title></title>
+<link rel="stylesheet" href="foo&amp;bar.css" type="text/css" />
+</head>
+<body>
+<div class="document">
+<p>simple input</p>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/pep_html.html b/test/functional/expected/pep_html.html
new file mode 100644
index 000000000..8c1a077c5
--- /dev/null
+++ b/test/functional/expected/pep_html.html
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!--
+This HTML is auto-generated. DO NOT EDIT THIS FILE! If you are writing a new
+PEP, see http://www.python.org/peps/pep-0001.html for instructions and links
+to templates. DO NOT USE THIS HTML FILE AS YOUR TEMPLATE!
+-->
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+ <title>PEP 100 -- Test PEP</title>
+ <link rel="stylesheet" href="../../../docutils/writers/pep_html/pep.css" type="text/css" />
+</head>
+<body bgcolor="white">
+<table class="navigation" cellpadding="0" cellspacing="0"
+ width="100%" border="0">
+<tr><td class="navicon" width="150" height="35">
+<a href="http://www.python.org/" title="Python Home Page">
+<img src="http://www.python.org/pics/PyBanner000.gif" alt="[Python]"
+ border="0" width="150" height="35" /></a></td>
+<td class="textlinks" align="left">
+[<b><a href="http://www.python.org/">Python Home</a></b>]
+[<b><a href="http://www.python.org/peps/">PEP Index</a></b>]
+[<b><a href="http://www.python.org/peps/pep-0100.txt">PEP Source</a></b>]
+</td></tr></table>
+<div class="document">
+<table class="rfc2822 docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">PEP:</th><td class="field-body">100</td>
+</tr>
+<tr class="field"><th class="field-name">Title:</th><td class="field-body">Test PEP</td>
+</tr>
+<tr class="field"><th class="field-name">Version:</th><td class="field-body">42</td>
+</tr>
+<tr class="field"><th class="field-name">Last-Modified:</th><td class="field-body"><a class="reference" href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python/nondist/peps/pep-0100.txt">A long time ago.</a></td>
+</tr>
+<tr class="field"><th class="field-name">Author:</th><td class="field-body">John Doe &lt;john&#32;&#97;t&#32;example.org&gt;</td>
+</tr>
+<tr class="field"><th class="field-name">Discussions-To:</th><td class="field-body">&lt;<a class="reference" href="mailto:devnull&#37;&#52;&#48;example&#46;org?subject=PEP%20100">devnull&#32;&#97;t&#32;example.org</a>&gt;</td>
+</tr>
+<tr class="field"><th class="field-name">Status:</th><td class="field-body">Draft</td>
+</tr>
+<tr class="field"><th class="field-name">Type:</th><td class="field-body">Standards Track</td>
+</tr>
+<tr class="field"><th class="field-name">Content-Type:</th><td class="field-body"><a class="reference" href="http://www.python.org/peps/pep-0012.html">text/x-rst</a></td>
+</tr>
+<tr class="field"><th class="field-name">Created:</th><td class="field-body">01-Jun-2001</td>
+</tr>
+<tr class="field"><th class="field-name">Post-History:</th><td class="field-body">13-Jun-2001</td>
+</tr>
+</tbody>
+</table>
+<hr />
+<div class="contents topic">
+<p class="topic-title first"><a id="contents" name="contents">Contents</a></p>
+<ul class="simple">
+<li><a class="reference" href="#abstract" id="id5" name="id5">Abstract</a></li>
+<li><a class="reference" href="#copyright" id="id6" name="id6">Copyright</a></li>
+<li><a class="reference" href="#references-and-footnotes" id="id7" name="id7">References and Footnotes</a></li>
+</ul>
+</div>
+<div class="section">
+<h1><a class="toc-backref" href="#id5" id="abstract" name="abstract">Abstract</a></h1>
+<p>This is just a test <a class="footnote-reference" href="#id2" id="id1" name="id1">[1]</a>. See the <a class="reference" href="http://www.python.org/peps/">PEP repository</a> <a class="footnote-reference" href="#id3" id="id4" name="id4">[2]</a> for the real
+thing.</p>
+</div>
+<div class="section">
+<h1><a class="toc-backref" href="#id6" id="copyright" name="copyright">Copyright</a></h1>
+<p>This document has been placed in the public domain.</p>
+</div>
+<div class="section">
+<h1><a class="toc-backref" href="#id7" id="references-and-footnotes" name="references-and-footnotes">References and Footnotes</a></h1>
+<table class="docutils footnote" frame="void" id="id2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id1" name="id2">[1]</a></td><td>PEP editors: <a class="reference" href="mailto:peps&#37;&#52;&#48;python&#46;org">peps<span>&#64;</span>python<span>&#46;</span>org</a></td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id3" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id4" name="id3">[2]</a></td><td><a class="reference" href="http://www.python.org/peps/">http://www.python.org/peps/</a></td></tr>
+</tbody>
+</table>
+</div>
+
+</div>
+</body>
+</html>
+
diff --git a/test/functional/expected/standalone_rst_html4css1.html b/test/functional/expected/standalone_rst_html4css1.html
new file mode 100644
index 000000000..4f823b504
--- /dev/null
+++ b/test/functional/expected/standalone_rst_html4css1.html
@@ -0,0 +1,1001 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title>reStructuredText Test Document</title>
+<meta name="author" content="David Goodger" />
+<meta name="authors" content="Me Myself I" />
+<meta name="organization" content="humankind" />
+<meta name="date" content="Now, or yesterday. Or maybe even before yesterday." />
+<meta name="copyright" content="This document has been placed in the public domain. You may do with it as you wish. You may copy, modify, redistribute, reattribute, sell, buy, rent, lease, destroy, or improve it, quote it at length, excerpt, incorporate, collate, fold, staple, or mutilate it, or do anything else to it that your or anyone else's heart desires." />
+<meta content="reStructuredText, test, parser" name="keywords" />
+<meta content="A test document, containing at least one example of each reStructuredText construct." lang="en" name="description" />
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+</head>
+<body>
+<div class="header">
+Document header
+<hr class="header"/>
+</div>
+<div class="document" id="restructuredtext-test-document">
+<span id="doctitle"></span><h1 class="title">reStructuredText Test Document</h1>
+<h2 class="subtitle" id="examples-of-syntax-constructs"><span id="subtitle"></span>Examples of Syntax Constructs</h2>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>David Goodger</td></tr>
+<tr><th class="docinfo-name">Address:</th>
+<td><pre class="address">
+123 Example Street
+Example, EX Canada
+A1B 2C3
+</pre>
+</td></tr>
+<tr><th class="docinfo-name">Contact:</th>
+<td><a class="first last reference" href="mailto:goodger&#64;users.sourceforge.net">goodger&#64;users.sourceforge.net</a></td></tr>
+<tr><th class="docinfo-name">Authors:</th>
+<td>Me
+<br />Myself
+<br />I</td></tr>
+<tr><th class="docinfo-name">Organization:</th>
+<td>humankind</td></tr>
+<tr><th class="docinfo-name">Date:</th>
+<td>Now, or yesterday. Or maybe even <em>before</em> yesterday.</td></tr>
+<tr><th class="docinfo-name">Status:</th>
+<td>This is a &quot;work in progress&quot;</td></tr>
+<tr><th class="docinfo-name">Revision:</th>
+<td>is managed by a version control system.</td></tr>
+<tr><th class="docinfo-name">Version:</th>
+<td>1</td></tr>
+<tr><th class="docinfo-name">Copyright:</th>
+<td>This document has been placed in the public domain. You
+may do with it as you wish. You may copy, modify,
+redistribute, reattribute, sell, buy, rent, lease,
+destroy, or improve it, quote it at length, excerpt,
+incorporate, collate, fold, staple, or mutilate it, or do
+anything else to it that your or anyone else's heart
+desires.</td></tr>
+<tr class="field"><th class="docinfo-name">field name:</th><td class="field-body">This is a &quot;generic bibliographic field&quot;.</td>
+</tr>
+<tr class="field"><th class="docinfo-name">field name &quot;2&quot;:</th><td class="field-body"><p class="first">Generic bibliographic fields may contain multiple body elements.</p>
+<p class="last">Like this.</p>
+</td>
+</tr>
+</tbody>
+</table>
+<div class="dedication topic">
+<p class="topic-title first">Dedication</p>
+<p>For Docutils users &amp; co-developers.</p>
+</div>
+<div class="abstract topic">
+<p class="topic-title first">Abstract</p>
+<p>This is a test document, containing at least one example of each
+reStructuredText construct.</p>
+</div>
+<!-- This is a comment. Note how any initial comments are moved by
+transforms to after the document title, subtitle, and docinfo. -->
+<!-- Above is the document title, and below is the subtitle.
+They are transformed from section titles after parsing. -->
+<!-- bibliographic fields (which also require a transform): -->
+<div class="contents topic">
+<p class="topic-title first"><a id="table-of-contents" name="table-of-contents">Table of Contents</a></p>
+<ul class="auto-toc simple">
+<li><a class="reference" href="#structural-elements" id="id32" name="id32">1&nbsp;&nbsp;&nbsp;Structural Elements</a><ul class="auto-toc">
+<li><a class="reference" href="#section-title" id="id33" name="id33">1.1&nbsp;&nbsp;&nbsp;Section Title</a></li>
+<li><a class="reference" href="#empty-section" id="id34" name="id34">1.2&nbsp;&nbsp;&nbsp;Empty Section</a></li>
+<li><a class="reference" href="#transitions" id="id35" name="id35">1.3&nbsp;&nbsp;&nbsp;Transitions</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#body-elements" id="id36" name="id36">2&nbsp;&nbsp;&nbsp;Body Elements</a><ul class="auto-toc">
+<li><a class="reference" href="#paragraphs" id="id37" name="id37">2.1&nbsp;&nbsp;&nbsp;Paragraphs</a><ul class="auto-toc">
+<li><a class="reference" href="#inline-markup" id="id38" name="id38">2.1.1&nbsp;&nbsp;&nbsp;Inline Markup</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#bullet-lists" id="id39" name="id39">2.2&nbsp;&nbsp;&nbsp;Bullet Lists</a></li>
+<li><a class="reference" href="#enumerated-lists" id="id40" name="id40">2.3&nbsp;&nbsp;&nbsp;Enumerated Lists</a></li>
+<li><a class="reference" href="#definition-lists" id="id41" name="id41">2.4&nbsp;&nbsp;&nbsp;Definition Lists</a></li>
+<li><a class="reference" href="#field-lists" id="id42" name="id42">2.5&nbsp;&nbsp;&nbsp;Field Lists</a></li>
+<li><a class="reference" href="#option-lists" id="id43" name="id43">2.6&nbsp;&nbsp;&nbsp;Option Lists</a></li>
+<li><a class="reference" href="#literal-blocks" id="id44" name="id44">2.7&nbsp;&nbsp;&nbsp;Literal Blocks</a></li>
+<li><a class="reference" href="#line-blocks" id="id45" name="id45">2.8&nbsp;&nbsp;&nbsp;Line Blocks</a></li>
+<li><a class="reference" href="#block-quotes" id="id46" name="id46">2.9&nbsp;&nbsp;&nbsp;Block Quotes</a></li>
+<li><a class="reference" href="#doctest-blocks" id="id47" name="id47">2.10&nbsp;&nbsp;&nbsp;Doctest Blocks</a></li>
+<li><a class="reference" href="#footnotes" id="id48" name="id48">2.11&nbsp;&nbsp;&nbsp;Footnotes</a></li>
+<li><a class="reference" href="#citations" id="id49" name="id49">2.12&nbsp;&nbsp;&nbsp;Citations</a></li>
+<li><a class="reference" href="#targets" id="id50" name="id50">2.13&nbsp;&nbsp;&nbsp;Targets</a><ul class="auto-toc">
+<li><a class="reference" href="#duplicate-target-names" id="id51" name="id51">2.13.1&nbsp;&nbsp;&nbsp;Duplicate Target Names</a></li>
+<li><a class="reference" href="#id20" id="id52" name="id52">2.13.2&nbsp;&nbsp;&nbsp;Duplicate Target Names</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#directives" id="id53" name="id53">2.14&nbsp;&nbsp;&nbsp;Directives</a><ul class="auto-toc">
+<li><a class="reference" href="#document-parts" id="id54" name="id54">2.14.1&nbsp;&nbsp;&nbsp;Document Parts</a></li>
+<li><a class="reference" href="#images" id="id55" name="id55">2.14.2&nbsp;&nbsp;&nbsp;Images</a></li>
+<li><a class="reference" href="#admonitions" id="id56" name="id56">2.14.3&nbsp;&nbsp;&nbsp;Admonitions</a></li>
+<li><a class="reference" href="#topics-sidebars-and-rubrics" id="id57" name="id57">2.14.4&nbsp;&nbsp;&nbsp;Topics, Sidebars, and Rubrics</a></li>
+<li><a class="reference" href="#target-footnotes" id="id58" name="id58">2.14.5&nbsp;&nbsp;&nbsp;Target Footnotes</a></li>
+<li><a class="reference" href="#replacement-text" id="id59" name="id59">2.14.6&nbsp;&nbsp;&nbsp;Replacement Text</a></li>
+<li><a class="reference" href="#compound-paragraph" id="id60" name="id60">2.14.7&nbsp;&nbsp;&nbsp;Compound Paragraph</a></li>
+<li><a class="reference" href="#parsed-literal-blocks" id="id61" name="id61">2.14.8&nbsp;&nbsp;&nbsp;Parsed Literal Blocks</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#substitution-definitions" id="id62" name="id62">2.15&nbsp;&nbsp;&nbsp;Substitution Definitions</a></li>
+<li><a class="reference" href="#comments" id="id63" name="id63">2.16&nbsp;&nbsp;&nbsp;Comments</a></li>
+<li><a class="reference" href="#raw-text" id="id64" name="id64">2.17&nbsp;&nbsp;&nbsp;Raw text</a></li>
+<li><a class="reference" href="#container" id="id65" name="id65">2.18&nbsp;&nbsp;&nbsp;Container</a></li>
+<li><a class="reference" href="#colspanning-tables" id="id66" name="id66">2.19&nbsp;&nbsp;&nbsp;Colspanning tables</a></li>
+<li><a class="reference" href="#rowspanning-tables" id="id67" name="id67">2.20&nbsp;&nbsp;&nbsp;Rowspanning tables</a></li>
+<li><a class="reference" href="#complex-tables" id="id68" name="id68">2.21&nbsp;&nbsp;&nbsp;Complex tables</a></li>
+<li><a class="reference" href="#list-tables" id="id69" name="id69">2.22&nbsp;&nbsp;&nbsp;List Tables</a></li>
+<li><a class="reference" href="#custom-roles" id="id70" name="id70">2.23&nbsp;&nbsp;&nbsp;Custom Roles</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#error-handling" id="id71" name="id71">3&nbsp;&nbsp;&nbsp;Error Handling</a></li>
+</ul>
+</div>
+<div class="section">
+<h1><a class="toc-backref" href="#id32" id="structural-elements" name="structural-elements">1&nbsp;&nbsp;&nbsp;Structural Elements</a></h1>
+<div class="section">
+<h2 class="with-subtitle"><a class="toc-backref" href="#id33" id="section-title" name="section-title">1.1&nbsp;&nbsp;&nbsp;Section Title</a></h2>
+<h2 class="section-subtitle" id="section-subtitle"><span class="section-subtitle">Section Subtitle</span></h2>
+<p>That's it, the text just above this line.</p>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id34" id="empty-section" name="empty-section">1.2&nbsp;&nbsp;&nbsp;Empty Section</a></h2>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id35" id="transitions" name="transitions">1.3&nbsp;&nbsp;&nbsp;Transitions</a></h2>
+<p>Here's a transition:</p>
+<hr class="docutils" />
+<p>It divides the section. Transitions may also occur between sections:</p>
+</div>
+</div>
+<hr class="docutils" />
+<div class="section">
+<h1><a class="toc-backref" href="#id36" id="body-elements" name="body-elements">2&nbsp;&nbsp;&nbsp;Body Elements</a></h1>
+<div class="section">
+<h2><a class="toc-backref" href="#id37" id="paragraphs" name="paragraphs">2.1&nbsp;&nbsp;&nbsp;Paragraphs</a></h2>
+<p>A paragraph.</p>
+<div class="section">
+<h3><a class="toc-backref" href="#id38" id="inline-markup" name="inline-markup">2.1.1&nbsp;&nbsp;&nbsp;Inline Markup</a></h3>
+<p>Paragraphs contain text and may contain inline markup: <em>emphasis</em>,
+<strong>strong emphasis</strong>, <tt class="docutils literal"><span class="pre">inline</span> <span class="pre">literals</span></tt>, standalone hyperlinks
+(<a class="reference" href="http://www.python.org">http://www.python.org</a>), external hyperlinks (<a class="reference" href="http://www.python.org/">Python</a> <a class="footnote-reference" href="#id25" id="id26" name="id26">[5]</a>), internal
+cross-references (<a class="reference" href="#example">example</a>), external hyperlinks with embedded URIs
+(<a class="reference" href="http://www.python.org">Python web site</a>), <a class="reference" href="http://www.python.org/">anonymous hyperlink
+references</a> <a class="footnote-reference" href="#id25" id="id29" name="id29">[5]</a> (<a class="reference" href="http://docutils.sourceforge.net/">a second reference</a> <a class="footnote-reference" href="#id30" id="id31" name="id31">[6]</a>), footnote references (manually
+numbered <a class="footnote-reference" href="#id8" id="id1" name="id1">[1]</a>, anonymous auto-numbered <a class="footnote-reference" href="#id11" id="id2" name="id2">[3]</a>, labeled auto-numbered
+<a class="footnote-reference" href="#label" id="id3" name="id3">[2]</a>, or symbolic <a class="footnote-reference" href="#id12" id="id4" name="id4">[*]</a>), citation references (<a class="citation-reference" href="#cit2002" id="id5" name="id5">[CIT2002]</a>),
+substitution references (<img alt="EXAMPLE" src="../../../docs/user/rst/images/biohazard.png" />), and <span class="target" id="inline-hyperlink-targets">inline hyperlink targets</span>
+(see <a class="reference" href="#id22">Targets</a> below for a reference back to here). Character-level
+inline markup is also possible (although exceedingly ugly!) in <em>re</em><tt class="docutils literal"><span class="pre">Structured</span></tt><em>Text</em>. Problems are indicated by <a href="#id23" name="id24"><span class="problematic" id="id24">|problematic|</span></a> text
+(generated by processing errors; this one is intentional). Here is a
+reference to the <a class="reference" href="#doctitle">doctitle</a> and the <a class="reference" href="#subtitle">subtitle</a>.</p>
+<p>The default role for interpreted text is <cite>Title Reference</cite>. Here are
+some explicit interpreted text roles: a PEP reference (<a class="reference" href="http://www.python.org/peps/pep-0287.html">PEP 287</a>); an
+RFC reference (<a class="reference" href="http://www.faqs.org/rfcs/rfc2822.html">RFC 2822</a>); a <sub>subscript</sub>; a <sup>superscript</sup>;
+and explicit roles for <em>standard</em> <strong>inline</strong>
+<tt class="docutils literal"><span class="pre">markup</span></tt>.</p>
+<!-- DO NOT RE-WRAP THE FOLLOWING PARAGRAPH! -->
+<p>Let's test wrapping and whitespace significance in inline literals:
+<tt class="docutils literal"><span class="pre">This</span> <span class="pre">is</span> <span class="pre">an</span> <span class="pre">example</span> <span class="pre">of</span> <span class="pre">--inline-literal</span> <span class="pre">--text,</span> <span class="pre">--including</span> <span class="pre">some--</span>
+<span class="pre">strangely--hyphenated-words.</span>&nbsp; <span class="pre">Adjust-the-width-of-your-browser-window</span>
+<span class="pre">to</span> <span class="pre">see</span> <span class="pre">how</span> <span class="pre">the</span> <span class="pre">text</span> <span class="pre">is</span> <span class="pre">wrapped.</span>&nbsp; <span class="pre">--</span> <span class="pre">----</span> <span class="pre">--------</span>&nbsp; <span class="pre">Now</span> <span class="pre">note</span>&nbsp;&nbsp;&nbsp; <span class="pre">the</span>
+<span class="pre">spacing</span>&nbsp;&nbsp;&nbsp; <span class="pre">between</span> <span class="pre">the</span>&nbsp;&nbsp;&nbsp; <span class="pre">words</span> <span class="pre">of</span>&nbsp;&nbsp;&nbsp; <span class="pre">this</span> <span class="pre">sentence</span>&nbsp;&nbsp;&nbsp; <span class="pre">(words</span>
+<span class="pre">should</span>&nbsp;&nbsp;&nbsp; <span class="pre">be</span> <span class="pre">grouped</span>&nbsp;&nbsp;&nbsp; <span class="pre">in</span> <span class="pre">pairs).</span></tt></p>
+<p>If the <tt class="docutils literal"><span class="pre">--pep-references</span></tt> option was supplied, there should be a
+live link to PEP 258 here.</p>
+</div>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id39" id="bullet-lists" name="bullet-lists">2.2&nbsp;&nbsp;&nbsp;Bullet Lists</a></h2>
+<ul>
+<li><p class="first">A bullet list</p>
+<ul class="simple">
+<li>Nested bullet list.</li>
+<li>Nested item 2.</li>
+</ul>
+</li>
+<li><p class="first">Item 2.</p>
+<p>Paragraph 2 of item 2.</p>
+<ul class="simple">
+<li>Nested bullet list.</li>
+<li>Nested item 2.<ul>
+<li>Third level.</li>
+<li>Item 2.</li>
+</ul>
+</li>
+<li>Nested item 3.</li>
+<li>This nested list should be compacted by the HTML writer.<span class="target" id="target"></span><!-- Even if this item contains a target and a comment. -->
+</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id40" id="enumerated-lists" name="enumerated-lists">2.3&nbsp;&nbsp;&nbsp;Enumerated Lists</a></h2>
+<ol class="arabic">
+<li><p class="first">Arabic numerals.</p>
+<ol class="loweralpha simple">
+<li>lower alpha)<ol class="lowerroman">
+<li>(lower roman)<ol class="upperalpha">
+<li>upper alpha.<ol class="upperroman">
+<li>upper roman)</li>
+</ol>
+</li>
+</ol>
+</li>
+</ol>
+</li>
+</ol>
+</li>
+<li><p class="first">Lists that don't start at 1:</p>
+<ol class="arabic simple" start="3">
+<li>Three</li>
+<li>Four</li>
+</ol>
+<ol class="upperalpha simple" start="3">
+<li>C</li>
+<li>D</li>
+</ol>
+<ol class="lowerroman simple" start="3">
+<li>iii</li>
+<li>iv</li>
+</ol>
+</li>
+</ol>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id41" id="definition-lists" name="definition-lists">2.4&nbsp;&nbsp;&nbsp;Definition Lists</a></h2>
+<dl class="docutils">
+<dt>Term</dt>
+<dd>Definition</dd>
+<dt>Term <span class="classifier-delimiter">:</span> <span class="classifier">classifier</span></dt>
+<dd><p class="first">Definition paragraph 1.</p>
+<p class="last">Definition paragraph 2.</p>
+</dd>
+<dt>Term</dt>
+<dd>Definition</dd>
+<dt>Term <span class="classifier-delimiter">:</span> <span class="classifier">classifier one</span> <span class="classifier-delimiter">:</span> <span class="classifier">classifier two</span></dt>
+<dd>Definition</dd>
+</dl>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id42" id="field-lists" name="field-lists">2.5&nbsp;&nbsp;&nbsp;Field Lists</a></h2>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">what:</th><td class="field-body"><p class="first">Field lists map field names to field bodies, like database
+records. They are often part of an extension syntax. They are
+an unambiguous variant of RFC 2822 fields.</p>
+</td>
+</tr>
+<tr class="field"><th class="field-name">how arg1 arg2:</th><td class="field-body"><p class="first">The field marker is a colon, the field name, and a colon.</p>
+<p>The field body may contain one or more body elements, indented
+relative to the field marker.</p>
+</td>
+</tr>
+<tr class="field"><th class="field-name">credits:</th><td class="field-body"><p class="credits first last">This paragraph has the <cite>credits</cite> class set. (This is actually not
+about credits but just for ensuring that the class attribute
+doesn't get stripped away.)</p>
+</td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id43" id="option-lists" name="option-lists">2.6&nbsp;&nbsp;&nbsp;Option Lists</a></h2>
+<p>For listing command-line options:</p>
+<table class="docutils option-list" frame="void" rules="none">
+<col class="option" />
+<col class="description" />
+<tbody valign="top">
+<tr><td class="option-group">
+<kbd><span class="option">-a</span></kbd></td>
+<td>command-line option &quot;a&quot;</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-b <var>file</var></span></kbd></td>
+<td>options can have arguments
+and long descriptions</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">--long</span></kbd></td>
+<td>options can be long also</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">--input=<var>file</var></span></kbd></td>
+<td>long options can also have
+arguments</td></tr>
+<tr><td class="option-group" colspan="2">
+<kbd><span class="option">--very-long-option</span></kbd></td>
+</tr>
+<tr><td>&nbsp;</td><td><p class="first">The description can also start on the next line.</p>
+<p class="last">The description may contain multiple body elements,
+regardless of where it starts.</p>
+</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-x</span>, <span class="option">-y</span>, <span class="option">-z</span></kbd></td>
+<td>Multiple options are an &quot;option group&quot;.</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">-v</span>, <span class="option">--verbose</span></kbd></td>
+<td>Commonly-seen: short &amp; long options.</td></tr>
+<tr><td class="option-group" colspan="2">
+<kbd><span class="option">-1 <var>file</var></span>, <span class="option">--one=<var>file</var></span>, <span class="option">--two <var>file</var></span></kbd></td>
+</tr>
+<tr><td>&nbsp;</td><td>Multiple options with arguments.</td></tr>
+<tr><td class="option-group">
+<kbd><span class="option">/V</span></kbd></td>
+<td>DOS/VMS-style options too</td></tr>
+</tbody>
+</table>
+<p>There must be at least two spaces between the option and the
+description.</p>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id44" id="literal-blocks" name="literal-blocks">2.7&nbsp;&nbsp;&nbsp;Literal Blocks</a></h2>
+<p>Literal blocks are indicated with a double-colon (&quot;::&quot;) at the end of
+the preceding paragraph (over there <tt class="docutils literal"><span class="pre">--&gt;</span></tt>). They can be indented:</p>
+<pre class="literal-block">
+if literal_block:
+ text = 'is left as-is'
+ spaces_and_linebreaks = 'are preserved'
+ markup_processing = None
+</pre>
+<p>Or they can be quoted without indentation:</p>
+<pre class="literal-block">
+&gt;&gt; Great idea!
+&gt;
+&gt; Why didn't I think of that?
+</pre>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id45" id="line-blocks" name="line-blocks">2.8&nbsp;&nbsp;&nbsp;Line Blocks</a></h2>
+<p>This section tests line blocks. Line blocks are body elements which
+consist of lines and other line blocks. Nested line blocks cause
+indentation.</p>
+<div class="line-block">
+<div class="line">This is a line block. It ends with a blank line.</div>
+<div class="line-block">
+<div class="line">New lines begin with a vertical bar (&quot;|&quot;).</div>
+<div class="line">Line breaks and initial indent are significant, and preserved.</div>
+<div class="line-block">
+<div class="line">Continuation lines are also possible. A long line that is intended
+to wrap should begin with a space in place of the vertical bar.</div>
+</div>
+<div class="line">The left edge of a continuation line need not be aligned with
+the left edge of the text above it.</div>
+</div>
+</div>
+<div class="line-block">
+<div class="line">This is a second line block.</div>
+<div class="line"><br /></div>
+<div class="line">Blank lines are permitted internally, but they must begin with a &quot;|&quot;.</div>
+</div>
+<p>Another line block, surrounded by paragraphs:</p>
+<div class="line-block">
+<div class="line">And it's no good waiting by the window</div>
+<div class="line">It's no good waiting for the sun</div>
+<div class="line">Please believe me, the things you dream of</div>
+<div class="line">They don't fall in the lap of no-one</div>
+</div>
+<p>Take it away, Eric the Orchestra Leader!</p>
+<blockquote>
+<div class="line-block">
+<div class="line">A one, two, a one two three four</div>
+<div class="line"><br /></div>
+<div class="line">Half a bee, philosophically,</div>
+<div class="line-block">
+<div class="line">must, <em>ipso facto</em>, half not be.</div>
+</div>
+<div class="line">But half the bee has got to be,</div>
+<div class="line-block">
+<div class="line"><em>vis a vis</em> its entity. D'you see?</div>
+<div class="line"><br /></div>
+</div>
+<div class="line">But can a bee be said to be</div>
+<div class="line-block">
+<div class="line">or not to be an entire bee,</div>
+<div class="line-block">
+<div class="line">when half the bee is not a bee,</div>
+<div class="line-block">
+<div class="line">due to some ancient injury?</div>
+<div class="line"><br /></div>
+</div>
+</div>
+</div>
+<div class="line">Singing...</div>
+</div>
+</blockquote>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id46" id="block-quotes" name="block-quotes">2.9&nbsp;&nbsp;&nbsp;Block Quotes</a></h2>
+<p>Block quotes consist of indented body elements:</p>
+<blockquote>
+<p>My theory by A. Elk. Brackets Miss, brackets. This theory goes
+as follows and begins now. All brontosauruses are thin at one
+end, much much thicker in the middle and then thin again at the
+far end. That is my theory, it is mine, and belongs to me and I
+own it, and what it is too.</p>
+<p class="attribution">&mdash;Anne Elk (Miss)</p>
+</blockquote>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id47" id="doctest-blocks" name="doctest-blocks">2.10&nbsp;&nbsp;&nbsp;Doctest Blocks</a></h2>
+<pre class="doctest-block">
+&gt;&gt;&gt; print 'Python-specific usage examples; begun with &quot;&gt;&gt;&gt;&quot;'
+Python-specific usage examples; begun with &quot;&gt;&gt;&gt;&quot;
+&gt;&gt;&gt; print '(cut and pasted from interactive Python sessions)'
+(cut and pasted from interactive Python sessions)
+</pre>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id48" id="footnotes" name="footnotes">2.11&nbsp;&nbsp;&nbsp;Footnotes</a></h2>
+<table class="docutils footnote" frame="void" id="id8" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a name="id8">[1]</a></td><td><em>(<a class="fn-backref" href="#id1">1</a>, <a class="fn-backref" href="#id9">2</a>, <a class="fn-backref" href="#id21">3</a>)</em> <p>A footnote contains body elements, consistently indented by at
+least 3 spaces.</p>
+<p class="last">This is the footnote's second paragraph.</p>
+</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="label" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a name="label">[2]</a></td><td><em>(<a class="fn-backref" href="#id3">1</a>, <a class="fn-backref" href="#id10">2</a>)</em> Footnotes may be numbered, either manually (as in <a class="footnote-reference" href="#id8" id="id9" name="id9">[1]</a>) or
+automatically using a &quot;#&quot;-prefixed label. This footnote has a
+label so it can be referred to from multiple places, both as a
+footnote reference (<a class="footnote-reference" href="#label" id="id10" name="id10">[2]</a>) and as a hyperlink reference
+(<a class="reference" href="#label">label</a>).</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id11" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id2" name="id11">[3]</a></td><td><p class="first">This footnote is numbered automatically and anonymously using a
+label of &quot;#&quot; only.</p>
+<p>This is the second paragraph.</p>
+<p class="last">And this is the third paragraph.</p>
+</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id12" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id4" name="id12">[*]</a></td><td>Footnotes may also use symbols, specified with a &quot;*&quot; label.
+Here's a reference to the next footnote: <a class="footnote-reference" href="#id14" id="id13" name="id13">[†]</a>.</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id14" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id13" name="id14">[†]</a></td><td>This footnote shows the next symbol in the sequence.</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id15" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a name="id15">[4]</a></td><td>Here's an unreferenced footnote, with a reference to a
+nonexistent footnote: <a href="#id80" name="id81"><span class="problematic" id="id81"><span id="id16"></span>[5]_</span></a>.</td></tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id49" id="citations" name="citations">2.12&nbsp;&nbsp;&nbsp;Citations</a></h2>
+<table class="docutils citation" frame="void" id="cit2002" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a name="cit2002">[CIT2002]</a></td><td><em>(<a class="fn-backref" href="#id5">1</a>, <a class="fn-backref" href="#id17">2</a>)</em> Citations are text-labeled footnotes. They may be
+rendered separately and differently from footnotes.</td></tr>
+</tbody>
+</table>
+<p>Here's a reference to the above, <a class="citation-reference" href="#cit2002" id="id17" name="id17">[CIT2002]</a>, and a <a href="#id82" name="id83"><span class="problematic" id="id83"><span id="id18"></span>[nonexistent]_</span></a>
+citation.</p>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id50" id="targets" name="targets"><span id="another-target"></span>2.13&nbsp;&nbsp;&nbsp;Targets</a></h2>
+<p id="example">This paragraph is pointed to by the explicit &quot;example&quot; target. A
+reference can be found under <a class="reference" href="#inline-markup">Inline Markup</a>, above. <a class="reference" href="#inline-hyperlink-targets">Inline
+hyperlink targets</a> are also possible.</p>
+<p>Section headers are implicit targets, referred to by name. See
+<a class="reference" href="#id22">Targets</a>, which is a subsection of <a class="reference" href="#body-elements">Body Elements</a>.</p>
+<p>Explicit external targets are interpolated into references such as
+&quot;<a class="reference" href="http://www.python.org/">Python</a> <a class="footnote-reference" href="#id25" id="id27" name="id27">[5]</a>&quot;.</p>
+<p>Targets may be indirect and anonymous. Thus <a class="reference" href="#id22">this phrase</a> may also
+refer to the <a class="reference" href="#id22">Targets</a> section.</p>
+<p>Here's a <a href="#id84" name="id85"><span class="problematic" id="id85">`hyperlink reference without a target`_</span></a>, which generates an
+error.</p>
+<div class="section">
+<h3><a class="toc-backref" href="#id51" id="duplicate-target-names" name="duplicate-target-names">2.13.1&nbsp;&nbsp;&nbsp;Duplicate Target Names</a></h3>
+<p>Duplicate names in section headers or other implicit targets will
+generate &quot;info&quot; (level-1) system messages. Duplicate names in
+explicit targets will generate &quot;warning&quot; (level-2) system messages.</p>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id52" id="id20" name="id20">2.13.2&nbsp;&nbsp;&nbsp;Duplicate Target Names</a></h3>
+<p>Since there are two &quot;Duplicate Target Names&quot; section headers, we
+cannot uniquely refer to either of them by name. If we try to (like
+this: <a href="#id86" name="id87"><span class="problematic" id="id87">`Duplicate Target Names`_</span></a>), an error is generated.</p>
+</div>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id53" id="directives" name="directives">2.14&nbsp;&nbsp;&nbsp;Directives</a></h2>
+<div class="contents local topic">
+<ul class="auto-toc simple">
+<li><a class="reference" href="#document-parts" id="id72" name="id72">2.14.1&nbsp;&nbsp;&nbsp;Document Parts</a></li>
+<li><a class="reference" href="#images" id="id73" name="id73">2.14.2&nbsp;&nbsp;&nbsp;Images</a></li>
+<li><a class="reference" href="#admonitions" id="id74" name="id74">2.14.3&nbsp;&nbsp;&nbsp;Admonitions</a></li>
+<li><a class="reference" href="#topics-sidebars-and-rubrics" id="id75" name="id75">2.14.4&nbsp;&nbsp;&nbsp;Topics, Sidebars, and Rubrics</a></li>
+<li><a class="reference" href="#target-footnotes" id="id76" name="id76">2.14.5&nbsp;&nbsp;&nbsp;Target Footnotes</a></li>
+<li><a class="reference" href="#replacement-text" id="id77" name="id77">2.14.6&nbsp;&nbsp;&nbsp;Replacement Text</a></li>
+<li><a class="reference" href="#compound-paragraph" id="id78" name="id78">2.14.7&nbsp;&nbsp;&nbsp;Compound Paragraph</a></li>
+<li><a class="reference" href="#parsed-literal-blocks" id="id79" name="id79">2.14.8&nbsp;&nbsp;&nbsp;Parsed Literal Blocks</a></li>
+</ul>
+</div>
+<p>These are just a sample of the many reStructuredText Directives. For
+others, please see
+<a class="reference" href="http://docutils.sourceforge.net/docs/ref/rst/directives.html">http://docutils.sourceforge.net/docs/ref/rst/directives.html</a>.</p>
+<div class="section">
+<h3><a class="toc-backref" href="#id72" id="document-parts" name="document-parts">2.14.1&nbsp;&nbsp;&nbsp;Document Parts</a></h3>
+<p>An example of the &quot;contents&quot; directive can be seen above this section
+(a local, untitled table of <a class="reference" href="#contents">contents</a>) and at the beginning of the
+document (a document-wide <a class="reference" href="#table-of-contents">table of contents</a>).</p>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id73" id="images" name="images">2.14.2&nbsp;&nbsp;&nbsp;Images</a></h3>
+<p>An image directive (also clickable -- a hyperlink reference):</p>
+<a class="reference image-reference" href="#directives"><img alt="../../../docs/user/rst/images/title.png" class="class1 class2" src="../../../docs/user/rst/images/title.png" /></a>
+<p>Image with multiple IDs:</p>
+<span id="image-target-2"></span><span id="image-target-1"></span><img alt="../../../docs/user/rst/images/title.png" id="image-target-3" name="image-target-3" src="../../../docs/user/rst/images/title.png" />
+<p>A centered image:</p>
+<div align="center" class="align-center"><img alt="../../../docs/user/rst/images/biohazard.png" class="align-center" src="../../../docs/user/rst/images/biohazard.png" /></div>
+<p>A left-aligned image:</p>
+<img align="left" alt="../../../docs/user/rst/images/biohazard.png" class="align-left" src="../../../docs/user/rst/images/biohazard.png" />
+<p>A right-aligned image:</p>
+<img align="right" alt="../../../docs/user/rst/images/biohazard.png" class="align-right" src="../../../docs/user/rst/images/biohazard.png" />
+<p>A figure directive:</p>
+<div align="right" class="figclass1 figclass2 figure">
+<img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/biohazard.png" style="width: 50px;" />
+<p class="caption">A figure is an image with a caption and/or a legend:</p>
+<div class="legend">
+<table border="1" class="docutils">
+<colgroup>
+<col width="20%" />
+<col width="80%" />
+</colgroup>
+<tbody valign="top">
+<tr><td>re</td>
+<td>Revised, revisited, based on 're' module.</td>
+</tr>
+<tr><td>Structured</td>
+<td>Structure-enhanced text, structuredtext.</td>
+</tr>
+<tr><td>Text</td>
+<td>Well it is, isn't it?</td>
+</tr>
+</tbody>
+</table>
+<p>This paragraph is also part of the legend.</p>
+</div>
+</div>
+<div align="left" class="figclass1 figclass2 figure">
+<img alt="reStructuredText, the markup syntax" class="class1 class2" src="../../../docs/user/rst/images/biohazard.png" style="width: 50px;" />
+<p class="caption">A left-aligned figure.</p>
+<div class="legend">
+This is the legend.</div>
+</div>
+<p>This paragraph might flow around the figure...</p>
+<p>A centered figure:</p>
+<div align="center" class="figure">
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="width: 50px;" />
+<p class="caption">This is the caption.</p>
+<div class="legend">
+<p>This is the legend.</p>
+<p>The legend may consist of several paragraphs.</p>
+</div>
+</div>
+<p>This paragraph might flow around the figure...</p>
+<p>A left-aligned figure:</p>
+<div align="left" class="figure">
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="width: 50px;" />
+<p class="caption">This is the caption.</p>
+<div class="legend">
+<p>This is the legend.</p>
+<p>The legend may consist of several paragraphs.</p>
+</div>
+</div>
+<p>This paragraph might flow around the figure...</p>
+<p>Now widths:</p>
+<p>An image 2 em wide:</p>
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="width: 2em;" />
+<p>An image 2 em wide and 30 pixel high:</p>
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="width: 2em; height: 30px;" />
+<p>An image occupying 70% of the line width:</p>
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="width: 70%;" />
+<p>An image 3 cm high:</p>
+<img alt="../../../docs/user/rst/images/biohazard.png" src="../../../docs/user/rst/images/biohazard.png" style="height: 3cm;" />
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id74" id="admonitions" name="admonitions">2.14.3&nbsp;&nbsp;&nbsp;Admonitions</a></h3>
+<div class="attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last">Directives at large.</p>
+</div>
+<div class="caution">
+<p class="first admonition-title">Caution!</p>
+<p class="last">Don't take any wooden nickels.</p>
+</div>
+<div class="danger">
+<p class="first admonition-title">!DANGER!</p>
+<p class="last">Mad scientist at work!</p>
+</div>
+<div class="error">
+<p class="first admonition-title">Error</p>
+<p class="last">Does not compute.</p>
+</div>
+<div class="hint">
+<p class="first admonition-title">Hint</p>
+<p class="last">It's bigger than a bread box.</p>
+</div>
+<div class="important">
+<p class="first admonition-title">Important</p>
+<ul class="last simple">
+<li>Wash behind your ears.</li>
+<li>Clean up your room.</li>
+<li>Call your mother.</li>
+<li>Back up your data.</li>
+</ul>
+</div>
+<div class="note">
+<p class="first admonition-title">Note</p>
+<p class="last">This is a note.</p>
+</div>
+<div class="tip">
+<p class="first admonition-title">Tip</p>
+<p class="last">15% if the service is good.</p>
+</div>
+<div class="warning">
+<p class="first admonition-title">Warning</p>
+<p class="last">Strong prose may provoke extreme mental exertion.
+Reader discretion is strongly advised.</p>
+</div>
+<div class="admonition-and-by-the-way admonition">
+<p class="first admonition-title">And, by the way...</p>
+<p class="last">You can make up your own admonition too.</p>
+</div>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id75" id="topics-sidebars-and-rubrics" name="topics-sidebars-and-rubrics">2.14.4&nbsp;&nbsp;&nbsp;Topics, Sidebars, and Rubrics</a></h3>
+<div class="sidebar">
+<p class="first sidebar-title">Sidebar Title</p>
+<p class="sidebar-subtitle">Optional Subtitle</p>
+<p>This is a sidebar. It is for text outside the flow of the main
+text.</p>
+<p class="rubric">This is a rubric inside a sidebar</p>
+<p class="last">Sidebars often appears beside the main text with a border and
+background color.</p>
+</div>
+<div class="topic">
+<p class="topic-title first">Topic Title</p>
+<p>This is a topic.</p>
+</div>
+<p class="rubric">This is a rubric</p>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id76" id="target-footnotes" name="target-footnotes">2.14.5&nbsp;&nbsp;&nbsp;Target Footnotes</a></h3>
+<table class="docutils footnote" frame="void" id="id25" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a name="id25">[5]</a></td><td><em>(<a class="fn-backref" href="#id26">1</a>, <a class="fn-backref" href="#id27">2</a>, <a class="fn-backref" href="#id28">3</a>, <a class="fn-backref" href="#id29">4</a>)</em> <a class="reference" href="http://www.python.org/">http://www.python.org/</a></td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id30" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id31" name="id30">[6]</a></td><td><a class="reference" href="http://docutils.sourceforge.net/">http://docutils.sourceforge.net/</a></td></tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id77" id="replacement-text" name="replacement-text">2.14.6&nbsp;&nbsp;&nbsp;Replacement Text</a></h3>
+<p>I recommend you try <a class="reference" href="http://www.python.org/">Python, <em>the</em> best language around</a> <a class="footnote-reference" href="#id25" id="id28" name="id28">[5]</a>.</p>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id78" id="compound-paragraph" name="compound-paragraph">2.14.7&nbsp;&nbsp;&nbsp;Compound Paragraph</a></h3>
+<div class="some-class compound">
+<p class="compound-first">Compound 1, paragraph 1.</p>
+<p class="compound-middle">Compound 1, paragraph 2.</p>
+<ul class="compound-last simple">
+<li>Compound 1, list item one.</li>
+<li>Compound 1, list item two.</li>
+</ul>
+</div>
+<p>Another compound statement:</p>
+<div class="compound">
+<p class="compound-first">Compound 2, a literal block:</p>
+<pre class="compound-middle literal-block">
+Compound 2, literal.
+</pre>
+<p class="compound-last">Compound 2, this is a test.</p>
+</div>
+<div class="compound">
+<p>Compound 3, only consisting of one paragraph.</p>
+</div>
+<div class="compound">
+<pre class="compound-first literal-block">
+Compound 4.
+This one starts with a literal block.
+</pre>
+<p class="compound-last">Compound 4, a paragraph.</p>
+</div>
+<p>Now something <em>really</em> perverted -- a nested compound block. This is
+just to test that it works at all; the results don't have to be
+meaningful.</p>
+<div class="compound">
+<p class="compound-first">Compound 5, block 1 (a paragraph).</p>
+<div class="compound-middle compound">
+<p class="compound-first">Compound 6, block 2 in compound 5.</p>
+<p class="compound-last">Compound 6, another paragraph.</p>
+</div>
+<p class="compound-last">Compound 5, block 3 (a paragraph).</p>
+</div>
+<div class="compound">
+<p class="compound-first">Compound 7, with a table inside:</p>
+<table border="1" class="compound-middle docutils">
+<colgroup>
+<col width="33%" />
+<col width="33%" />
+<col width="33%" />
+</colgroup>
+<tbody valign="top">
+<tr><td><p class="first">Left cell, first
+paragraph.</p>
+<p class="last">Left cell, second
+paragraph.</p>
+</td>
+<td>Middle cell,
+consisting of
+exactly one
+paragraph.</td>
+<td><p class="first">Right cell.</p>
+<p>Paragraph 2.</p>
+<p class="last">Paragraph 3.</p>
+</td>
+</tr>
+</tbody>
+</table>
+<p class="compound-middle">Compound 7, a paragraph after the table.</p>
+<p class="compound-last">Compound 7, another paragraph.</p>
+</div>
+</div>
+<div class="section">
+<h3><a class="toc-backref" href="#id79" id="parsed-literal-blocks" name="parsed-literal-blocks">2.14.8&nbsp;&nbsp;&nbsp;Parsed Literal Blocks</a></h3>
+<pre class="literal-block">
+This is a parsed literal block.
+ This line is indented. The next line is blank.
+
+Inline markup is supported, e.g. <em>emphasis</em>, <strong>strong</strong>, <tt class="docutils literal"><span class="pre">literal</span>
+<span class="pre">text</span></tt>, footnotes <a class="footnote-reference" href="#id8" id="id21" name="id21">[1]</a>, <span class="target" id="id22">targets</span>, and <a class="reference" href="http://www.python.org/">references</a>.
+</pre>
+</div>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id62" id="substitution-definitions" name="substitution-definitions">2.15&nbsp;&nbsp;&nbsp;Substitution Definitions</a></h2>
+<p>An inline image (<img alt="EXAMPLE" src="../../../docs/user/rst/images/biohazard.png" />) example:</p>
+<p>(Substitution definitions are not visible in the HTML source.)</p>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id63" id="comments" name="comments">2.16&nbsp;&nbsp;&nbsp;Comments</a></h2>
+<p>Here's one:</p>
+<!-- Comments begin with two dots and a space. Anything may
+follow, except for the syntax of footnotes, hyperlink
+targets, directives, or substitution definitions.
+
+Double-dashes - - "- -" - - must be escaped somehow in HTML output. -->
+<p>(View the HTML source to see the comment.)</p>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id64" id="raw-text" name="raw-text">2.17&nbsp;&nbsp;&nbsp;Raw text</a></h2>
+<p>This does not necessarily look nice, because there may be missing white space.</p>
+<p>It's just there to freeze the behavior.</p>
+A test.Second test.<div class="myclass">Another test with myclass set.</div><p>This is the <span class="myrawroleclass">fourth test</span> with myrawroleclass set.</p>
+Fifth test in HTML.<br />Line two.</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id65" id="container" name="container">2.18&nbsp;&nbsp;&nbsp;Container</a></h2>
+<div class="custom container">
+<p>paragraph 1</p>
+<p>paragraph 2</p>
+</div>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id66" id="colspanning-tables" name="colspanning-tables">2.19&nbsp;&nbsp;&nbsp;Colspanning tables</a></h2>
+<p>This table has a cell spanning two columns:</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="31%" />
+<col width="31%" />
+<col width="38%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head" colspan="2">Inputs</th>
+<th class="head">Output</th>
+</tr>
+<tr><th class="head">A</th>
+<th class="head">B</th>
+<th class="head">A or B</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><td>False</td>
+<td>False</td>
+<td>False</td>
+</tr>
+<tr><td>True</td>
+<td>False</td>
+<td>True</td>
+</tr>
+<tr><td>False</td>
+<td>True</td>
+<td>True</td>
+</tr>
+<tr><td>True</td>
+<td>True</td>
+<td>True</td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id67" id="rowspanning-tables" name="rowspanning-tables">2.20&nbsp;&nbsp;&nbsp;Rowspanning tables</a></h2>
+<p>Here's a table with cells spanning several rows:</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="44%" />
+<col width="22%" />
+<col width="33%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head">Header row, column 1
+(header rows optional)</th>
+<th class="head">Header 2</th>
+<th class="head">Header 3</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><td>body row 1, column 1</td>
+<td>column 2</td>
+<td>column 3</td>
+</tr>
+<tr><td>body row 2</td>
+<td rowspan="2">Cells may
+span rows.</td>
+<td rowspan="2">Another
+rowspanning
+cell.</td>
+</tr>
+<tr><td>body row 3</td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id68" id="complex-tables" name="complex-tables">2.21&nbsp;&nbsp;&nbsp;Complex tables</a></h2>
+<p>Here's a complex table, which should test all features.</p>
+<table border="1" class="docutils">
+<colgroup>
+<col width="43%" />
+<col width="21%" />
+<col width="18%" />
+<col width="18%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head">Header row, column 1
+(header rows optional)</th>
+<th class="head">Header 2</th>
+<th class="head">Header 3</th>
+<th class="head">Header 4</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><td>body row 1, column 1</td>
+<td>column 2</td>
+<td>column 3</td>
+<td>column 4</td>
+</tr>
+<tr><td>body row 2</td>
+<td colspan="3">Cells may span columns.</td>
+</tr>
+<tr><td>body row 3</td>
+<td rowspan="2"><p class="first">Cells may
+span rows.</p>
+<p class="last">Paragraph.</p>
+</td>
+<td colspan="2" rowspan="2"><ul class="first last simple">
+<li>Table cells</li>
+<li>contain</li>
+<li>body elements.</li>
+</ul>
+</td>
+</tr>
+<tr><td>body row 4</td>
+</tr>
+<tr><td>body row 5</td>
+<td colspan="2">Cells may also be
+empty: <tt class="docutils literal"><span class="pre">--&gt;</span></tt></td>
+<td>&nbsp;</td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id69" id="list-tables" name="list-tables">2.22&nbsp;&nbsp;&nbsp;List Tables</a></h2>
+<p>Here's a list table exercising all features:</p>
+<table border="1" class="test docutils">
+<caption>list table with integral header</caption>
+<colgroup>
+<col width="17%" />
+<col width="33%" />
+<col width="50%" />
+</colgroup>
+<thead valign="bottom">
+<tr><th class="head stub">Treat</th>
+<th class="head">Quantity</th>
+<th class="head">Description</th>
+</tr>
+</thead>
+<tbody valign="top">
+<tr><th class="stub">Albatross</th>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr><th class="stub">Crunchy Frog</th>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be
+crunchy, now would it?</td>
+</tr>
+<tr><th class="stub">Gannet Ripple</th>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="section">
+<h2><a class="toc-backref" href="#id70" id="custom-roles" name="custom-roles">2.23&nbsp;&nbsp;&nbsp;Custom Roles</a></h2>
+<p><tt class="custom docutils literal"><span class="pre">one</span></tt> <tt class="custom docutils literal"><span class="pre">two</span></tt> <tt class="custom docutils literal"><span class="pre">three</span></tt></p>
+</div>
+</div>
+<div class="section">
+<h1><a class="toc-backref" href="#id71" id="error-handling" name="error-handling">3&nbsp;&nbsp;&nbsp;Error Handling</a></h1>
+<p>Any errors caught during processing will generate system messages.</p>
+<p>There should be five messages in the following, auto-generated
+section, &quot;Docutils System Messages&quot;:</p>
+<!-- section should be added by Docutils automatically -->
+</div>
+<div class="system-messages section">
+<h1>Docutils System Messages</h1>
+<div class="system-message" id="id23">
+<p class="system-message-title">System Message: <a name="id23">ERROR/3</a> (<tt class="docutils">functional/input/data/standard.txt</tt>, line 100); <em><a href="#id24">backlink</a></em></p>
+Undefined substitution referenced: &quot;problematic&quot;.</div>
+<div class="system-message" id="id80">
+<p class="system-message-title">System Message: <a name="id80">ERROR/3</a> (<tt class="docutils">functional/input/standalone_rst_html4css1.txt</tt>, line 358); <em><a href="#id81">backlink</a></em></p>
+Unknown target name: &quot;5&quot;.</div>
+<div class="system-message" id="id82">
+<p class="system-message-title">System Message: <a name="id82">ERROR/3</a> (<tt class="docutils">functional/input/data/standard.txt</tt>, line 367); <em><a href="#id83">backlink</a></em></p>
+Unknown target name: &quot;nonexistent&quot;.</div>
+<div class="system-message" id="id84">
+<p class="system-message-title">System Message: <a name="id84">ERROR/3</a> (<tt class="docutils">functional/input/data/standard.txt</tt>, line 394); <em><a href="#id85">backlink</a></em></p>
+Unknown target name: &quot;hyperlink reference without a target&quot;.</div>
+<div class="system-message" id="id86">
+<p class="system-message-title">System Message: <a name="id86">ERROR/3</a> (<tt class="docutils">functional/input/data/standard.txt</tt>, line 407); <em><a href="#id87">backlink</a></em></p>
+Duplicate target name, cannot be used as a unique reference: &quot;duplicate target names&quot;.</div>
+</div>
+</div>
+<div class="footer">
+<hr class="footer" />
+Document footer
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/standalone_rst_latex.tex b/test/functional/expected/standalone_rst_latex.tex
new file mode 100644
index 000000000..ba5b63bb0
--- /dev/null
+++ b/test/functional/expected/standalone_rst_latex.tex
@@ -0,0 +1,1556 @@
+\documentclass[10pt,a4paper,english]{article}
+\usepackage{babel}
+\usepackage{ae}
+\usepackage{aeguill}
+\usepackage{shortvrb}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\usepackage{longtable}
+\setlength{\extrarowheight}{2pt}
+\usepackage{amsmath}
+\usepackage{graphicx}
+\usepackage{color}
+\usepackage{multirow}
+\usepackage{ifthen}
+\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+\usepackage[DIV12]{typearea}
+%% generator Docutils: http://docutils.sourceforge.net/
+\newlength{\admonitionwidth}
+\setlength{\admonitionwidth}{0.9\textwidth}
+\newlength{\docinfowidth}
+\setlength{\docinfowidth}{0.9\textwidth}
+\newlength{\locallinewidth}
+\newcommand{\optionlistlabel}[1]{\bf #1 \hfill}
+\newenvironment{optionlist}[1]
+{\begin{list}{}
+ {\setlength{\labelwidth}{#1}
+ \setlength{\rightmargin}{1cm}
+ \setlength{\leftmargin}{\rightmargin}
+ \addtolength{\leftmargin}{\labelwidth}
+ \addtolength{\leftmargin}{\labelsep}
+ \renewcommand{\makelabel}{\optionlistlabel}}
+}{\end{list}}
+\newlength{\lineblockindentation}
+\setlength{\lineblockindentation}{2.5em}
+\newenvironment{lineblock}[1]
+{\begin{list}{}
+ {\setlength{\partopsep}{\parskip}
+ \addtolength{\partopsep}{\baselineskip}
+ \topsep0pt\itemsep0.15\baselineskip\parsep0pt
+ \leftmargin#1}
+ \raggedright}
+{\end{list}}
+% begin: floats for footnotes tweaking.
+\setlength{\floatsep}{0.5em}
+\setlength{\textfloatsep}{\fill}
+\addtolength{\textfloatsep}{3em}
+\renewcommand{\textfraction}{0.5}
+\renewcommand{\topfraction}{0.5}
+\renewcommand{\bottomfraction}{0.5}
+\setcounter{totalnumber}{50}
+\setcounter{topnumber}{50}
+\setcounter{bottomnumber}{50}
+% end floats for footnotes
+% some commands, that could be overwritten in the style file.
+\newcommand{\rubric}[1]{\subsection*{~\hfill {\it #1} \hfill ~}}
+\newcommand{\titlereference}[1]{\textsl{#1}}
+% end of "some commands"
+\title{reStructuredText Test Document\\
+\large{Examples of Syntax Constructs}
+}
+\author{}
+\date{}
+\hypersetup{
+pdftitle={reStructuredText Test Document},
+pdfauthor={David Goodger;Me;Myself;I}
+}
+\raggedbottom
+\begin{document}
+\maketitle
+
+%___________________________________________________________________________
+\begin{center}
+\begin{tabularx}{\docinfowidth}{lX}
+\textbf{Author}: &
+ David Goodger \\
+\textbf{Address}: &
+ {\raggedright
+123 Example Street~\\
+Example, EX Canada~\\
+A1B 2C3 } \\
+\textbf{Contact}: &
+ \href{mailto:goodger@users.sourceforge.net}{goodger@users.sourceforge.net} \\
+\textbf{Author}: &
+ Me \\
+\textbf{Author}: &
+ Myself \\
+\textbf{Author}: &
+ I \\
+\textbf{Organization}: &
+ humankind \\
+\textbf{Date}: &
+ Now, or yesterday. Or maybe even \emph{before} yesterday. \\
+\textbf{Status}: &
+ This is a ``work in progress'' \\
+\textbf{Revision}: &
+ is managed by a version control system. \\
+\textbf{Version}: &
+ 1 \\
+\textbf{Copyright}: &
+ This document has been placed in the public domain. You
+may do with it as you wish. You may copy, modify,
+redistribute, reattribute, sell, buy, rent, lease,
+destroy, or improve it, quote it at length, excerpt,
+incorporate, collate, fold, staple, or mutilate it, or do
+anything else to it that your or anyone else's heart
+desires. \\
+\textbf{field name}: &
+ This is a ``generic bibliographic field''. \\
+\textbf{field name ``2''}: &
+ Generic bibliographic fields may contain multiple body elements.
+
+Like this. \\
+\end{tabularx}
+\end{center}
+
+\setlength{\locallinewidth}{\linewidth}
+
+
+\subsubsection*{~\hfill Dedication\hfill ~}
+
+For Docutils users {\&} co-developers.
+
+\subsubsection*{~\hfill Abstract\hfill ~}
+
+This is a test document, containing at least one example of each
+reStructuredText construct.
+
+% This is a comment. Note how any initial comments are moved by
+% transforms to after the document title, subtitle, and docinfo.
+% Above is the document title, and below is the subtitle.
+% They are transformed from section titles after parsing.
+% bibliographic fields (which also require a transform):
+\hypertarget{table-of-contents}{}
+\pdfbookmark[0]{Table of Contents}{table-of-contents}
+\subsubsection*{~\hfill Table of Contents\hfill ~}
+\begin{list}{}{}
+\item {} \href{\#structural-elements}{1~~~Structural Elements}
+\begin{list}{}{}
+\item {} \href{\#section-title}{1.1~~~Section Title}
+
+\item {} \href{\#empty-section}{1.2~~~Empty Section}
+
+\item {} \href{\#transitions}{1.3~~~Transitions}
+
+\end{list}
+
+\item {} \href{\#body-elements}{2~~~Body Elements}
+\begin{list}{}{}
+\item {} \href{\#paragraphs}{2.1~~~Paragraphs}
+\begin{list}{}{}
+\item {} \href{\#inline-markup}{2.1.1~~~Inline Markup}
+
+\end{list}
+
+\item {} \href{\#bullet-lists}{2.2~~~Bullet Lists}
+
+\item {} \href{\#enumerated-lists}{2.3~~~Enumerated Lists}
+
+\item {} \href{\#definition-lists}{2.4~~~Definition Lists}
+
+\item {} \href{\#field-lists}{2.5~~~Field Lists}
+
+\item {} \href{\#option-lists}{2.6~~~Option Lists}
+
+\item {} \href{\#literal-blocks}{2.7~~~Literal Blocks}
+
+\item {} \href{\#line-blocks}{2.8~~~Line Blocks}
+
+\item {} \href{\#block-quotes}{2.9~~~Block Quotes}
+
+\item {} \href{\#doctest-blocks}{2.10~~~Doctest Blocks}
+
+\item {} \href{\#footnotes}{2.11~~~Footnotes}
+
+\item {} \href{\#citations}{2.12~~~Citations}
+
+\item {} \href{\#targets}{2.13~~~Targets}
+\begin{list}{}{}
+\item {} \href{\#duplicate-target-names}{2.13.1~~~Duplicate Target Names}
+
+\item {} \href{\#id20}{2.13.2~~~Duplicate Target Names}
+
+\end{list}
+
+\item {} \href{\#directives}{2.14~~~Directives}
+\begin{list}{}{}
+\item {} \href{\#document-parts}{2.14.1~~~Document Parts}
+
+\item {} \href{\#images}{2.14.2~~~Images}
+
+\item {} \href{\#admonitions}{2.14.3~~~Admonitions}
+
+\item {} \href{\#topics-sidebars-and-rubrics}{2.14.4~~~Topics, Sidebars, and Rubrics}
+
+\item {} \href{\#target-footnotes}{2.14.5~~~Target Footnotes}
+
+\item {} \href{\#replacement-text}{2.14.6~~~Replacement Text}
+
+\item {} \href{\#compound-paragraph}{2.14.7~~~Compound Paragraph}
+
+\item {} \href{\#parsed-literal-blocks}{2.14.8~~~Parsed Literal Blocks}
+
+\end{list}
+
+\item {} \href{\#substitution-definitions}{2.15~~~Substitution Definitions}
+
+\item {} \href{\#comments}{2.16~~~Comments}
+
+\item {} \href{\#raw-text}{2.17~~~Raw text}
+
+\item {} \href{\#container}{2.18~~~Container}
+
+\item {} \href{\#colspanning-tables}{2.19~~~Colspanning tables}
+
+\item {} \href{\#rowspanning-tables}{2.20~~~Rowspanning tables}
+
+\end{list}
+
+\item {} \href{\#tests-for-the-latex-writer}{3~~~Tests for the LaTeX writer}
+\begin{list}{}{}
+\item {} \href{\#monospaced-non-alphanumeric-characters}{3.1~~~Monospaced non-alphanumeric characters}
+
+\item {} \href{\#various-non-ascii-characters}{3.2~~~Various non-ASCII characters}
+
+\end{list}
+
+\item {} \href{\#error-handling}{4~~~Error Handling}
+
+\end{list}
+
+
+
+%___________________________________________________________________________
+
+\hypertarget{structural-elements}{}
+\pdfbookmark[0]{1~~~Structural Elements}{structural-elements}
+\section*{1~~~Structural Elements}
+
+
+%___________________________________________________________________________
+
+\hypertarget{section-title}{}
+\pdfbookmark[1]{1.1~~~Section Title}{section-title}
+\subsection*{1.1~~~Section Title}
+\textbf{Section Subtitle}\vspace{0.2cm}
+
+\noindent
+That's it, the text just above this line.
+
+
+%___________________________________________________________________________
+
+\hypertarget{empty-section}{}
+\pdfbookmark[1]{1.2~~~Empty Section}{empty-section}
+\subsection*{1.2~~~Empty Section}
+
+
+%___________________________________________________________________________
+
+\hypertarget{transitions}{}
+\pdfbookmark[1]{1.3~~~Transitions}{transitions}
+\subsection*{1.3~~~Transitions}
+
+Here's a transition:
+
+
+%___________________________________________________________________________
+\hspace*{\fill}\hrulefill\hspace*{\fill}
+
+
+It divides the section. Transitions may also occur between sections:
+
+
+%___________________________________________________________________________
+\hspace*{\fill}\hrulefill\hspace*{\fill}
+
+
+
+%___________________________________________________________________________
+
+\hypertarget{body-elements}{}
+\pdfbookmark[0]{2~~~Body Elements}{body-elements}
+\section*{2~~~Body Elements}
+
+
+%___________________________________________________________________________
+
+\hypertarget{paragraphs}{}
+\pdfbookmark[1]{2.1~~~Paragraphs}{paragraphs}
+\subsection*{2.1~~~Paragraphs}
+
+A paragraph.
+
+
+%___________________________________________________________________________
+
+\hypertarget{inline-markup}{}
+\pdfbookmark[2]{2.1.1~~~Inline Markup}{inline-markup}
+\subsubsection*{2.1.1~~~Inline Markup}
+
+Paragraphs contain text and may contain inline markup: \emph{emphasis},
+\textbf{strong emphasis}, \texttt{inline literals}, standalone hyperlinks
+(\href{http://www.python.org}{http://www.python.org}), external hyperlinks (\href{http://www.python.org/}{Python}\raisebox{.5em}[0em]{\scriptsize\hyperlink{id25}{5}}), internal
+cross-references (\href{\#example}{example}), external hyperlinks with embedded URIs
+(\href{http://www.python.org}{Python web site}), \href{http://www.python.org/}{anonymous hyperlink
+references}\raisebox{.5em}[0em]{\scriptsize\hyperlink{id25}{5}} (\href{http://docutils.sourceforge.net/}{a second reference}\raisebox{.5em}[0em]{\scriptsize\hyperlink{id30}{6}}), footnote references (manually
+numbered\raisebox{.5em}[0em]{\scriptsize\hyperlink{id8}{1}}, anonymous auto-numbered\raisebox{.5em}[0em]{\scriptsize\hyperlink{id11}{3}}, labeled auto-numbered\raisebox{.5em}[0em]{\scriptsize\hyperlink{label}{2}}, or symbolic\raisebox{.5em}[0em]{\scriptsize\hyperlink{id12}{*}}), citation references ([\hyperlink{cit2002}{CIT2002}]),
+substitution references (\includegraphics{../../../docs/user/rst/images/biohazard.png}), and \hypertarget{inline-hyperlink-targets}{inline hyperlink targets}
+(see \href{\#id22}{Targets} below for a reference back to here). Character-level
+inline markup is also possible (although exceedingly ugly!) in \emph{re}\texttt{Structured}\emph{Text}. Problems are indicated by {\color{red}\bfseries{}{\textbar}problematic{\textbar}} text
+(generated by processing errors; this one is intentional). Here is a
+reference to the \href{\#doctitle}{doctitle} and the \href{\#subtitle}{subtitle}.
+
+The default role for interpreted text is \titlereference{Title Reference}. Here are
+some explicit interpreted text roles: a PEP reference (\href{http://www.python.org/peps/pep-0287.html}{PEP 287}); an
+RFC reference (\href{http://www.faqs.org/rfcs/rfc2822.html}{RFC 2822}); a $_{subscript}$; a $^{superscript}$;
+and explicit roles for \emph{standard} \textbf{inline}
+\texttt{markup}.
+% DO NOT RE-WRAP THE FOLLOWING PARAGRAPH!
+
+Let's test wrapping and whitespace significance in inline literals:
+\texttt{This is an example of -{}-inline-literal -{}-text, -{}-including some-{}-
+strangely-{}-hyphenated-words. Adjust-the-width-of-your-browser-window
+to see how the text is wrapped. -{}- -{}-{}-{}- -{}-{}-{}-{}-{}-{}-{}- Now note the
+spacing between the words of this sentence (words
+should be grouped in pairs).}
+
+If the \texttt{-{}-pep-references} option was supplied, there should be a
+live link to PEP 258 here.
+
+
+%___________________________________________________________________________
+
+\hypertarget{bullet-lists}{}
+\pdfbookmark[1]{2.2~~~Bullet Lists}{bullet-lists}
+\subsection*{2.2~~~Bullet Lists}
+\begin{itemize}
+\item {}
+A bullet list
+\begin{itemize}
+\item {}
+Nested bullet list.
+
+\item {}
+Nested item 2.
+
+\end{itemize}
+
+\item {}
+Item 2.
+
+Paragraph 2 of item 2.
+\begin{itemize}
+\item {}
+Nested bullet list.
+
+\item {}
+Nested item 2.
+\begin{itemize}
+\item {}
+Third level.
+
+\item {}
+Item 2.
+
+\end{itemize}
+
+\item {}
+Nested item 3.
+
+\item {}
+This nested list should be compacted by the HTML writer.
+\hypertarget{target}{}% Even if this item contains a target and a comment.
+
+\end{itemize}
+
+\end{itemize}
+
+
+%___________________________________________________________________________
+
+\hypertarget{enumerated-lists}{}
+\pdfbookmark[1]{2.3~~~Enumerated Lists}{enumerated-lists}
+\subsection*{2.3~~~Enumerated Lists}
+\newcounter{listcnt1}
+\begin{list}{\arabic{listcnt1}.}
+{
+\usecounter{listcnt1}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+Arabic numerals.
+\newcounter{listcnt2}
+\begin{list}{\alph{listcnt2})}
+{
+\usecounter{listcnt2}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+lower alpha)
+\newcounter{listcnt3}
+\begin{list}{(\roman{listcnt3})}
+{
+\usecounter{listcnt3}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+(lower roman)
+\newcounter{listcnt4}
+\begin{list}{\Alph{listcnt4}.}
+{
+\usecounter{listcnt4}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+upper alpha.
+\newcounter{listcnt5}
+\begin{list}{\Roman{listcnt5})}
+{
+\usecounter{listcnt5}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+upper roman)
+
+\end{list}
+
+\end{list}
+
+\end{list}
+
+\end{list}
+
+\item {}
+Lists that don't start at 1:
+\newcounter{listcnt6}
+\begin{list}{\arabic{listcnt6}.}
+{
+\usecounter{listcnt6}
+\addtocounter{listcnt6}{2}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+Three
+
+\item {}
+Four
+
+\end{list}
+\newcounter{listcnt7}
+\begin{list}{\Alph{listcnt7}.}
+{
+\usecounter{listcnt7}
+\addtocounter{listcnt7}{2}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+C
+
+\item {}
+D
+
+\end{list}
+\newcounter{listcnt8}
+\begin{list}{\roman{listcnt8}.}
+{
+\usecounter{listcnt8}
+\addtocounter{listcnt8}{2}
+\setlength{\rightmargin}{\leftmargin}
+}
+\item {}
+iii
+
+\item {}
+iv
+
+\end{list}
+
+\end{list}
+
+
+%___________________________________________________________________________
+
+\hypertarget{definition-lists}{}
+\pdfbookmark[1]{2.4~~~Definition Lists}{definition-lists}
+\subsection*{2.4~~~Definition Lists}
+\begin{description}
+%[visit_definition_list_item]
+\item[{Term}] %[visit_definition]
+
+Definition
+
+%[depart_definition]
+%[depart_definition_list_item]
+%[visit_definition_list_item]
+\item[{Term}] (\textbf{classifier})
+%[visit_definition]
+
+Definition paragraph 1.
+
+Definition paragraph 2.
+
+%[depart_definition]
+%[depart_definition_list_item]
+%[visit_definition_list_item]
+\item[{Term}] %[visit_definition]
+
+Definition
+
+%[depart_definition]
+%[depart_definition_list_item]
+%[visit_definition_list_item]
+\item[{Term}] (\textbf{classifier one})
+(\textbf{classifier two})
+%[visit_definition]
+
+Definition
+
+%[depart_definition]
+%[depart_definition_list_item]
+\end{description}
+
+
+%___________________________________________________________________________
+
+\hypertarget{field-lists}{}
+\pdfbookmark[1]{2.5~~~Field Lists}{field-lists}
+\subsection*{2.5~~~Field Lists}
+\begin{quote}
+\begin{description}
+\item [what:]
+Field lists map field names to field bodies, like database
+records. They are often part of an extension syntax. They are
+an unambiguous variant of RFC 2822 fields.
+
+
+\item [how arg1 arg2:]
+The field marker is a colon, the field name, and a colon.
+
+The field body may contain one or more body elements, indented
+relative to the field marker.
+
+
+\item [credits:]
+This paragraph has the \titlereference{credits} class set. (This is actually not
+about credits but just for ensuring that the class attribute
+doesn't get stripped away.)
+
+
+\end{description}
+\end{quote}
+
+
+%___________________________________________________________________________
+
+\hypertarget{option-lists}{}
+\pdfbookmark[1]{2.6~~~Option Lists}{option-lists}
+\subsection*{2.6~~~Option Lists}
+
+For listing command-line options:
+% [option list]
+\begin{optionlist}{3cm}
+\item [-a]
+command-line option ``a''
+\item [-b file]
+options can have arguments
+and long descriptions
+\item [-{}-long]
+options can be long also
+\item [-{}-input=file]
+long options can also have
+arguments
+\item [-{}-very-long-option]
+The description can also start on the next line.
+
+The description may contain multiple body elements,
+regardless of where it starts.
+\item [-x, -y, -z]
+Multiple options are an ``option group''.
+\item [-v, -{}-verbose]
+Commonly-seen: short {\&} long options.
+\item [-1 file, -{}-one=file, -{}-two file]
+Multiple options with arguments.
+\item [/V]
+DOS/VMS-style options too
+\end{optionlist}
+
+There must be at least two spaces between the option and the
+description.
+
+
+%___________________________________________________________________________
+
+\hypertarget{literal-blocks}{}
+\pdfbookmark[1]{2.7~~~Literal Blocks}{literal-blocks}
+\subsection*{2.7~~~Literal Blocks}
+
+Literal blocks are indicated with a double-colon (``::'') at the end of
+the preceding paragraph (over there \texttt{-{}->}). They can be indented:
+\begin{quote}{\ttfamily \raggedright \noindent
+if~literal{\_}block:~\\
+~~~~text~=~'is~left~as-is'~\\
+~~~~spaces{\_}and{\_}linebreaks~=~'are~preserved'~\\
+~~~~markup{\_}processing~=~None
+}\end{quote}
+
+Or they can be quoted without indentation:
+\begin{quote}{\ttfamily \raggedright \noindent
+>{}>~Great~idea!~\\
+>~\\
+>~Why~didn't~I~think~of~that?
+}\end{quote}
+
+
+%___________________________________________________________________________
+
+\hypertarget{line-blocks}{}
+\pdfbookmark[1]{2.8~~~Line Blocks}{line-blocks}
+\subsection*{2.8~~~Line Blocks}
+
+This section tests line blocks. Line blocks are body elements which
+consist of lines and other line blocks. Nested line blocks cause
+indentation.
+
+\begin{lineblock}{0em}
+\item[] This is a line block. It ends with a blank line.
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] New lines begin with a vertical bar (``{\textbar}'').
+\item[] Line breaks and initial indent are significant, and preserved.
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] Continuation lines are also possible. A long line that is intended
+to wrap should begin with a space in place of the vertical bar.
+\end{lineblock}
+\item[] The left edge of a continuation line need not be aligned with
+the left edge of the text above it.
+\end{lineblock}
+\end{lineblock}
+
+\begin{lineblock}{0em}
+\item[] This is a second line block.
+\item[]
+\item[] Blank lines are permitted internally, but they must begin with a ``{\textbar}''.
+\end{lineblock}
+
+Another line block, surrounded by paragraphs:
+
+\begin{lineblock}{0em}
+\item[] And it's no good waiting by the window
+\item[] It's no good waiting for the sun
+\item[] Please believe me, the things you dream of
+\item[] They don't fall in the lap of no-one
+\end{lineblock}
+
+Take it away, Eric the Orchestra Leader!
+\begin{quote}
+
+\begin{lineblock}{0em}
+\item[] A one, two, a one two three four
+\item[]
+\item[] Half a bee, philosophically,
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] must, \emph{ipso facto}, half not be.
+\end{lineblock}
+\item[] But half the bee has got to be,
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] \emph{vis a vis} its entity. D'you see?
+\item[]
+\end{lineblock}
+\item[] But can a bee be said to be
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] or not to be an entire bee,
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] when half the bee is not a bee,
+\item[]
+\begin{lineblock}{\lineblockindentation}
+\item[] due to some ancient injury?
+\item[]
+\end{lineblock}
+\end{lineblock}
+\end{lineblock}
+\item[] Singing...
+\end{lineblock}
+\end{quote}
+
+
+%___________________________________________________________________________
+
+\hypertarget{block-quotes}{}
+\pdfbookmark[1]{2.9~~~Block Quotes}{block-quotes}
+\subsection*{2.9~~~Block Quotes}
+
+Block quotes consist of indented body elements:
+\begin{quote}
+
+My theory by A. Elk. Brackets Miss, brackets. This theory goes
+as follows and begins now. All brontosauruses are thin at one
+end, much much thicker in the middle and then thin again at the
+far end. That is my theory, it is mine, and belongs to me and I
+own it, and what it is too.
+
+\begin{flushright}
+---Anne Elk (Miss)
+\end{flushright}
+\end{quote}
+
+
+%___________________________________________________________________________
+
+\hypertarget{doctest-blocks}{}
+\pdfbookmark[1]{2.10~~~Doctest Blocks}{doctest-blocks}
+\subsection*{2.10~~~Doctest Blocks}
+\begin{verbatim}>>> print 'Python-specific usage examples; begun with ">>>"'
+Python-specific usage examples; begun with ">>>"
+>>> print '(cut and pasted from interactive Python sessions)'
+(cut and pasted from interactive Python sessions)\end{verbatim}
+
+
+%___________________________________________________________________________
+
+\hypertarget{footnotes}{}
+\pdfbookmark[1]{2.11~~~Footnotes}{footnotes}
+\subsection*{2.11~~~Footnotes}
+\begin{figure}[b]\hypertarget{id8}$^{1}$
+A footnote contains body elements, consistently indented by at
+least 3 spaces.
+
+This is the footnote's second paragraph.
+\end{figure}
+\begin{figure}[b]\hypertarget{label}$^{2}$
+Footnotes may be numbered, either manually (as in\raisebox{.5em}[0em]{\scriptsize\hyperlink{id8}{1}}) or
+automatically using a ``{\#}''-prefixed label. This footnote has a
+label so it can be referred to from multiple places, both as a
+footnote reference (\raisebox{.5em}[0em]{\scriptsize\hyperlink{label}{2}}) and as a hyperlink reference
+(\href{\#label}{label}).
+\end{figure}
+\begin{figure}[b]\hypertarget{id11}$^{3}$
+This footnote is numbered automatically and anonymously using a
+label of ``{\#}'' only.
+
+This is the second paragraph.
+
+And this is the third paragraph.
+\end{figure}
+\begin{figure}[b]\hypertarget{id12}$^{*}$
+Footnotes may also use symbols, specified with a ``*'' label.
+Here's a reference to the next footnote:\raisebox{.5em}[0em]{\scriptsize\hyperlink{id14}{{\dag}}}.
+\end{figure}
+\begin{figure}[b]\hypertarget{id14}$^{{\dag}}$
+This footnote shows the next symbol in the sequence.
+\end{figure}
+\begin{figure}[b]\hypertarget{id15}$^{4}$
+Here's an unreferenced footnote, with a reference to a
+nonexistent footnote:{\color{red}\bfseries{}{[}5{]}{\_}}.
+\end{figure}
+
+
+%___________________________________________________________________________
+
+\hypertarget{citations}{}
+\pdfbookmark[1]{2.12~~~Citations}{citations}
+\subsection*{2.12~~~Citations}
+\begin{figure}[b]\hypertarget{cit2002}[CIT2002]
+Citations are text-labeled footnotes. They may be
+rendered separately and differently from footnotes.
+\end{figure}
+
+Here's a reference to the above, [\hyperlink{cit2002}{CIT2002}], and a {\color{red}\bfseries{}{[}nonexistent{]}{\_}}
+citation.
+
+
+%___________________________________________________________________________
+
+\hypertarget{targets}{}
+\hypertarget{another-target}{}
+\pdfbookmark[1]{2.13~~~Targets}{targets}
+\pdfbookmark[1]{2.13~~~Targets}{another-target}
+\subsection*{2.13~~~Targets}
+
+This paragraph is pointed to by the explicit ``example'' target. A
+reference can be found under \href{\#inline-markup}{Inline Markup}, above. \href{\#inline-hyperlink-targets}{Inline
+hyperlink targets} are also possible.
+
+Section headers are implicit targets, referred to by name. See
+\href{\#id22}{Targets}, which is a subsection of \href{\#body-elements}{Body Elements}.
+
+Explicit external targets are interpolated into references such as
+``\href{http://www.python.org/}{Python}\raisebox{.5em}[0em]{\scriptsize\hyperlink{id25}{5}}''.
+
+Targets may be indirect and anonymous. Thus \href{\#id22}{this phrase} may also
+refer to the \href{\#id22}{Targets} section.
+
+Here's a {\color{red}\bfseries{}`hyperlink reference without a target`{\_}}, which generates an
+error.
+
+
+%___________________________________________________________________________
+
+\hypertarget{duplicate-target-names}{}
+\pdfbookmark[2]{2.13.1~~~Duplicate Target Names}{duplicate-target-names}
+\subsubsection*{2.13.1~~~Duplicate Target Names}
+
+Duplicate names in section headers or other implicit targets will
+generate ``info'' (level-1) system messages. Duplicate names in
+explicit targets will generate ``warning'' (level-2) system messages.
+
+
+%___________________________________________________________________________
+
+\hypertarget{id20}{}
+\pdfbookmark[2]{2.13.2~~~Duplicate Target Names}{id20}
+\subsubsection*{2.13.2~~~Duplicate Target Names}
+
+Since there are two ``Duplicate Target Names'' section headers, we
+cannot uniquely refer to either of them by name. If we try to (like
+this: {\color{red}\bfseries{}`Duplicate Target Names`{\_}}), an error is generated.
+
+
+%___________________________________________________________________________
+
+\hypertarget{directives}{}
+\pdfbookmark[1]{2.14~~~Directives}{directives}
+\subsection*{2.14~~~Directives}
+\begin{list}{}{}
+\item {} \href{\#document-parts}{2.14.1~~~Document Parts}
+
+\item {} \href{\#images}{2.14.2~~~Images}
+
+\item {} \href{\#admonitions}{2.14.3~~~Admonitions}
+
+\item {} \href{\#topics-sidebars-and-rubrics}{2.14.4~~~Topics, Sidebars, and Rubrics}
+
+\item {} \href{\#target-footnotes}{2.14.5~~~Target Footnotes}
+
+\item {} \href{\#replacement-text}{2.14.6~~~Replacement Text}
+
+\item {} \href{\#compound-paragraph}{2.14.7~~~Compound Paragraph}
+
+\item {} \href{\#parsed-literal-blocks}{2.14.8~~~Parsed Literal Blocks}
+
+\end{list}
+
+
+These are just a sample of the many reStructuredText Directives. For
+others, please see
+\href{http://docutils.sourceforge.net/docs/ref/rst/directives.html}{http://docutils.sourceforge.net/docs/ref/rst/directives.html}.
+
+
+%___________________________________________________________________________
+
+\hypertarget{document-parts}{}
+\pdfbookmark[2]{2.14.1~~~Document Parts}{document-parts}
+\subsubsection*{2.14.1~~~Document Parts}
+
+An example of the ``contents'' directive can be seen above this section
+(a local, untitled table of \href{\#contents}{contents}) and at the beginning of the
+document (a document-wide \href{\#table-of-contents}{table of contents}).
+
+
+%___________________________________________________________________________
+
+\hypertarget{images}{}
+\pdfbookmark[2]{2.14.2~~~Images}{images}
+\subsubsection*{2.14.2~~~Images}
+
+An image directive (also clickable -{}- a hyperlink reference):
+\href{\#directives}{\includegraphics{../../../docs/user/rst/images/title.png}}
+Image with multiple IDs:
+
+\includegraphics{../../../docs/user/rst/images/title.png}
+
+A centered image:
+
+{\hfill\includegraphics{../../../docs/user/rst/images/biohazard.png}\hfill}
+
+A left-aligned image:
+
+{\includegraphics{../../../docs/user/rst/images/biohazard.png}\hfill}
+
+A right-aligned image:
+
+{\hfill\includegraphics{../../../docs/user/rst/images/biohazard.png}}
+
+A figure directive:
+\begin{figure}[htbp]\begin{flushright}
+
+\includegraphics[width=50]{../../../docs/user/rst/images/biohazard.png}
+\caption{A figure is an image with a caption and/or a legend:}{\small
+\begin{longtable}[c]{|p{0.16\locallinewidth}|p{0.56\locallinewidth}|}
+\hline
+
+re
+ &
+Revised, revisited, based on 're' module.
+ \\
+\hline
+
+Structured
+ &
+Structure-enhanced text, structuredtext.
+ \\
+\hline
+
+Text
+ &
+Well it is, isn't it?
+ \\
+\hline
+\end{longtable}
+
+This paragraph is also part of the legend.
+}\end{flushright}\end{figure}
+\begin{figure}[htbp]\begin{flushleft}
+
+\includegraphics[width=50]{../../../docs/user/rst/images/biohazard.png}
+\caption{A left-aligned figure.}{\small
+This is the legend.
+}\end{flushleft}\end{figure}
+
+This paragraph might flow around the figure...
+
+A centered figure:
+\begin{figure}[htbp]\begin{flushcenter}
+
+\includegraphics[width=50]{../../../docs/user/rst/images/biohazard.png}
+\caption{This is the caption.}{\small
+This is the legend.
+
+The legend may consist of several paragraphs.
+}\end{flushcenter}\end{figure}
+
+This paragraph might flow around the figure...
+
+A left-aligned figure:
+\begin{figure}[htbp]\begin{flushleft}
+
+\includegraphics[width=50]{../../../docs/user/rst/images/biohazard.png}
+\caption{This is the caption.}{\small
+This is the legend.
+
+The legend may consist of several paragraphs.
+}\end{flushleft}\end{figure}
+
+This paragraph might flow around the figure...
+
+Now widths:
+
+An image 2 em wide:
+
+\includegraphics[width=2em]{../../../docs/user/rst/images/biohazard.png}
+
+An image 2 em wide and 30 pixel high:
+
+\includegraphics[width=2em]{../../../docs/user/rst/images/biohazard.png}
+
+An image occupying 70{\%} of the line width:
+
+\includegraphics[width=70%]{../../../docs/user/rst/images/biohazard.png}
+
+An image 3 cm high:
+
+\includegraphics{../../../docs/user/rst/images/biohazard.png}
+
+
+%___________________________________________________________________________
+
+\hypertarget{admonitions}{}
+\pdfbookmark[2]{2.14.3~~~Admonitions}{admonitions}
+\subsubsection*{2.14.3~~~Admonitions}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Attention!}
+\vspace{2mm}
+
+Directives at large.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Caution!}
+\vspace{2mm}
+
+Don't take any wooden nickels.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large !DANGER!}
+\vspace{2mm}
+
+Mad scientist at work!
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Error}
+\vspace{2mm}
+
+Does not compute.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Hint}
+\vspace{2mm}
+
+It's bigger than a bread box.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Important}
+\vspace{2mm}
+\begin{itemize}
+\item {}
+Wash behind your ears.
+
+\item {}
+Clean up your room.
+
+\item {}
+Call your mother.
+
+\item {}
+Back up your data.
+
+\end{itemize}
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Note}
+\vspace{2mm}
+
+This is a note.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Tip}
+\vspace{2mm}
+
+15{\%} if the service is good.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\textbf{\large Warning}
+\vspace{2mm}
+
+Strong prose may provoke extreme mental exertion.
+Reader discretion is strongly advised.
+}}
+\end{sffamily}
+\end{center}
+\begin{center}\begin{sffamily}
+\fbox{\parbox{\admonitionwidth}{
+\vspace{2mm}
+\textbf{\large And, by the way...}
+\smallskip
+
+You can make up your own admonition too.
+}}
+\end{sffamily}
+\end{center}
+
+
+%___________________________________________________________________________
+
+\hypertarget{topics-sidebars-and-rubrics}{}
+\pdfbookmark[2]{2.14.4~~~Topics, Sidebars, and Rubrics}{topics-sidebars-and-rubrics}
+\subsubsection*{2.14.4~~~Topics, Sidebars, and Rubrics}
+
+\setlength{\locallinewidth}{0.9\admonitionwidth}
+\begin{center}\begin{sffamily}
+\fbox{\colorbox[gray]{0.80}{\parbox{\admonitionwidth}{
+\textbf{\large Sidebar Title}
+\smallskip
+~\\
+\textbf{Optional Subtitle}
+\smallskip
+
+This is a sidebar. It is for text outside the flow of the main
+text.
+\rubric{This is a rubric inside a sidebar}
+
+Sidebars often appears beside the main text with a border and
+background color.
+}}}
+\end{sffamily}
+\end{center}
+
+\setlength{\locallinewidth}{\linewidth}
+\subsubsection*{~\hfill Topic Title\hfill ~}
+
+This is a topic.
+
+\rubric{This is a rubric}
+
+
+%___________________________________________________________________________
+
+\hypertarget{target-footnotes}{}
+\pdfbookmark[2]{2.14.5~~~Target Footnotes}{target-footnotes}
+\subsubsection*{2.14.5~~~Target Footnotes}
+\begin{figure}[b]\hypertarget{id25}$^{5}$
+\href{http://www.python.org/}{http://www.python.org/}
+\end{figure}
+\begin{figure}[b]\hypertarget{id30}$^{6}$
+\href{http://docutils.sourceforge.net/}{http://docutils.sourceforge.net/}
+\end{figure}
+
+
+%___________________________________________________________________________
+
+\hypertarget{replacement-text}{}
+\pdfbookmark[2]{2.14.6~~~Replacement Text}{replacement-text}
+\subsubsection*{2.14.6~~~Replacement Text}
+
+I recommend you try \href{http://www.python.org/}{Python, \emph{the} best language around}\raisebox{.5em}[0em]{\scriptsize\hyperlink{id25}{5}}.
+
+
+%___________________________________________________________________________
+
+\hypertarget{compound-paragraph}{}
+\pdfbookmark[2]{2.14.7~~~Compound Paragraph}{compound-paragraph}
+\subsubsection*{2.14.7~~~Compound Paragraph}
+
+Compound 1, paragraph 1.
+
+Compound 1, paragraph 2.
+\begin{itemize}
+\item {}
+Compound 1, list item one.
+
+\item {}
+Compound 1, list item two.
+
+\end{itemize}
+
+Another compound statement:
+
+Compound 2, a literal block:
+\begin{quote}{\ttfamily \raggedright \noindent
+Compound~2,~literal.
+}\end{quote}
+Compound 2, this is a test.
+
+Compound 3, only consisting of one paragraph.
+\begin{quote}{\ttfamily \raggedright \noindent
+Compound~4.~\\
+This~one~starts~with~a~literal~block.
+}\end{quote}
+Compound 4, a paragraph.
+
+Now something \emph{really} perverted -{}- a nested compound block. This is
+just to test that it works at all; the results don't have to be
+meaningful.
+
+Compound 5, block 1 (a paragraph).
+
+Compound 6, block 2 in compound 5.
+
+Compound 6, another paragraph.
+
+Compound 5, block 3 (a paragraph).
+
+Compound 7, with a table inside:
+
+\begin{longtable}[c]{|p{0.25\locallinewidth}|p{0.25\locallinewidth}|p{0.25\locallinewidth}|}
+\hline
+
+Left cell, first
+paragraph.
+
+Left cell, second
+paragraph.
+ &
+Middle cell,
+consisting of
+exactly one
+paragraph.
+ &
+Right cell.
+
+Paragraph 2.
+
+Paragraph 3.
+ \\
+\hline
+\end{longtable}
+Compound 7, a paragraph after the table.
+
+Compound 7, another paragraph.
+
+
+%___________________________________________________________________________
+
+\hypertarget{parsed-literal-blocks}{}
+\pdfbookmark[2]{2.14.8~~~Parsed Literal Blocks}{parsed-literal-blocks}
+\subsubsection*{2.14.8~~~Parsed Literal Blocks}
+\begin{quote}{\ttfamily \raggedright \noindent
+This~is~a~parsed~literal~block.~\\
+~~~~This~line~is~indented.~~The~next~line~is~blank.~\\
+~\\
+Inline~markup~is~supported,~e.g.~\emph{emphasis},~\textbf{strong},~\texttt{literal~\\
+text},~footnotes\raisebox{.5em}[0em]{\scriptsize\hyperlink{id8}{1}},~\hypertarget{id22}{targets},~and~\href{http://www.python.org/}{references}.
+}\end{quote}
+
+
+%___________________________________________________________________________
+
+\hypertarget{substitution-definitions}{}
+\pdfbookmark[1]{2.15~~~Substitution Definitions}{substitution-definitions}
+\subsection*{2.15~~~Substitution Definitions}
+
+An inline image (\includegraphics{../../../docs/user/rst/images/biohazard.png}) example:
+
+(Substitution definitions are not visible in the HTML source.)
+
+
+%___________________________________________________________________________
+
+\hypertarget{comments}{}
+\pdfbookmark[1]{2.16~~~Comments}{comments}
+\subsection*{2.16~~~Comments}
+
+Here's one:
+% Comments begin with two dots and a space. Anything may
+% follow, except for the syntax of footnotes, hyperlink
+% targets, directives, or substitution definitions.
+%
+% Double-dashes -- "--" -- must be escaped somehow in HTML output.
+
+(View the HTML source to see the comment.)
+
+
+%___________________________________________________________________________
+
+\hypertarget{raw-text}{}
+\pdfbookmark[1]{2.17~~~Raw text}{raw-text}
+\subsection*{2.17~~~Raw text}
+
+This does not necessarily look nice, because there may be missing white space.
+
+It's just there to freeze the behavior.
+A test.Second test.Another test with myclass set.
+This is the fourth test with myrawroleclass set.
+Fifth test in LaTeX.\\Line two.
+
+%___________________________________________________________________________
+
+\hypertarget{container}{}
+\pdfbookmark[1]{2.18~~~Container}{container}
+\subsection*{2.18~~~Container}
+
+paragraph 1
+
+paragraph 2
+
+
+%___________________________________________________________________________
+
+\hypertarget{colspanning-tables}{}
+\pdfbookmark[1]{2.19~~~Colspanning tables}{colspanning-tables}
+\subsection*{2.19~~~Colspanning tables}
+
+This table has a cell spanning two columns:
+
+\begin{longtable}[c]{|p{0.07\locallinewidth}|p{0.07\locallinewidth}|p{0.09\locallinewidth}|}
+\hline
+\multicolumn{2}{|l|}{\textbf{
+Inputs
+}} & \textbf{
+Output
+} \\
+\hline
+\textbf{
+A
+} & \textbf{
+B
+} & \textbf{
+A or B
+} \\
+\hline
+\endhead
+
+False
+ &
+False
+ &
+False
+ \\
+\hline
+
+True
+ &
+False
+ &
+True
+ \\
+\hline
+
+False
+ &
+True
+ &
+True
+ \\
+\hline
+
+True
+ &
+True
+ &
+True
+ \\
+\hline
+\end{longtable}
+
+
+%___________________________________________________________________________
+
+\hypertarget{rowspanning-tables}{}
+\pdfbookmark[1]{2.20~~~Rowspanning tables}{rowspanning-tables}
+\subsection*{2.20~~~Rowspanning tables}
+
+Here's a table with cells spanning several rows:
+
+\begin{longtable}[c]{|p{0.30\locallinewidth}|p{0.16\locallinewidth}|p{0.23\locallinewidth}|}
+\hline
+\textbf{
+Header row, column 1
+(header rows optional)
+} & \textbf{
+Header 2
+} & \textbf{
+Header 3
+} \\
+\hline
+\endhead
+
+body row 1, column 1
+ &
+column 2
+ &
+column 3
+ \\
+\hline
+
+body row 2
+ & \multirow{2}{0.16\locallinewidth}{
+Cells may
+span rows.
+} & \multirow{2}{0.23\locallinewidth}{
+Another
+rowspanning
+cell.
+} \\
+\cline{1-1}
+
+body row 3
+ & \\
+\hline
+\end{longtable}
+
+
+%___________________________________________________________________________
+
+\hypertarget{tests-for-the-latex-writer}{}
+\pdfbookmark[0]{3~~~Tests for the LaTeX writer}{tests-for-the-latex-writer}
+\section*{3~~~Tests for the LaTeX writer}
+
+
+%___________________________________________________________________________
+
+\hypertarget{monospaced-non-alphanumeric-characters}{}
+\pdfbookmark[1]{3.1~~~Monospaced non-alphanumeric characters}{monospaced-non-alphanumeric-characters}
+\subsection*{3.1~~~Monospaced non-alphanumeric characters}
+
+These are all ASCII characters except a-zA-Z0-9 and space:
+
+\texttt{!!!"{}"{}"{\#}{\#}{\#}{\$}{\$}{\$}{\%}{\%}{\%}{\&}{\&}{\&}'{}'{}'((()))***+++,{},{},-{}-{}-...///:::}
+
+\texttt{;;;<{}<{}<===>{}>{}>???@@@{[}{[}{[}{\textbackslash}{\textbackslash}{\textbackslash}{]}{]}{]}{\textasciicircum}{\textasciicircum}{\textasciicircum}{\_}{\_}{\_}`{}`{}`{\{}{\{}{\{}|||{\}}{\}}{\}}{\textasciitilde}{\textasciitilde}{\textasciitilde}}
+
+\texttt{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
+
+The two lines of non-alphanumeric characters should both have the same
+width as the third line.
+
+
+%___________________________________________________________________________
+
+\hypertarget{various-non-ascii-characters}{}
+\pdfbookmark[1]{3.2~~~Various non-ASCII characters}{various-non-ascii-characters}
+\subsection*{3.2~~~Various non-ASCII characters}
+
+\begin{longtable}[c]{|p{0.03\locallinewidth}|p{0.42\locallinewidth}|}
+\hline
+
+ &
+copyright sign
+ \\
+\hline
+
+ &
+registered sign
+ \\
+\hline
+
+ &
+left pointing guillemet
+ \\
+\hline
+
+ &
+right pointing guillemet
+ \\
+\hline
+
+{--}
+ &
+en-dash
+ \\
+\hline
+
+{---}
+ &
+em-dash
+ \\
+\hline
+
+`
+ &
+single turned comma quotation mark
+ \\
+\hline
+
+'
+ &
+single comma quotation mark
+ \\
+\hline
+
+,
+ &
+low single comma quotation mark
+ \\
+\hline
+
+``
+ &
+double turned comma quotation mark
+ \\
+\hline
+
+''
+ &
+double comma quotation mark
+ \\
+\hline
+
+,,
+ &
+low double comma quotation mark
+ \\
+\hline
+
+{\dag}
+ &
+dagger
+ \\
+\hline
+
+{\ddag}
+ &
+double dagger
+ \\
+\hline
+
+{\dots}
+ &
+ellipsis
+ \\
+\hline
+
+{\texttrademark}
+ &
+trade mark sign
+ \\
+\hline
+
+{$\Leftrightarrow$}
+ &
+left-right double arrow
+ \\
+\hline
+\end{longtable}
+
+The following line should not be wrapped, because it uses
+non-breakable spaces:
+
+X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X~X
+
+
+%___________________________________________________________________________
+
+\hypertarget{error-handling}{}
+\pdfbookmark[0]{4~~~Error Handling}{error-handling}
+\section*{4~~~Error Handling}
+
+Any errors caught during processing will generate system messages.
+
+There should be five messages in the following, auto-generated
+section, ``Docutils System Messages'':
+% section should be added by Docutils automatically
+
+
+%___________________________________________________________________________
+
+\section*{Docutils System Messages}
+
+Undefined substitution referenced: ``problematic''.
+
+
+Unknown target name: ``5''.
+
+
+Unknown target name: ``nonexistent''.
+
+
+Unknown target name: ``hyperlink reference without a target''.
+
+
+Duplicate target name, cannot be used as a unique reference: ``duplicate target names''.
+
+
+\end{document}
diff --git a/test/functional/expected/standalone_rst_pseudoxml.txt b/test/functional/expected/standalone_rst_pseudoxml.txt
new file mode 100644
index 000000000..193f8c37c
--- /dev/null
+++ b/test/functional/expected/standalone_rst_pseudoxml.txt
@@ -0,0 +1,1841 @@
+<document ids="restructuredtext-test-document doctitle" names="restructuredtext\ test\ document doctitle" source="functional/input/standalone_rst_pseudoxml.txt" title="reStructuredText Test Document">
+ <title>
+ reStructuredText Test Document
+ <subtitle ids="examples-of-syntax-constructs subtitle" names="examples\ of\ syntax\ constructs subtitle">
+ Examples of Syntax Constructs
+ <decoration>
+ <header>
+ <paragraph>
+ Document header
+ <footer>
+ <paragraph>
+ Document footer
+ <docinfo>
+ <author>
+ David Goodger
+ <address xml:space="preserve">
+ 123 Example Street
+ Example, EX Canada
+ A1B 2C3
+ <contact>
+ <reference refuri="mailto:goodger@users.sourceforge.net">
+ goodger@users.sourceforge.net
+ <authors>
+ <author>
+ Me
+ <author>
+ Myself
+ <author>
+ I
+ <organization>
+ humankind
+ <date>
+ Now, or yesterday. Or maybe even
+ <emphasis>
+ before
+ yesterday.
+ <status>
+ This is a "work in progress"
+ <revision>
+ is managed by a version control system.
+ <version>
+ 1
+ <copyright>
+ This document has been placed in the public domain. You
+ may do with it as you wish. You may copy, modify,
+ redistribute, reattribute, sell, buy, rent, lease,
+ destroy, or improve it, quote it at length, excerpt,
+ incorporate, collate, fold, staple, or mutilate it, or do
+ anything else to it that your or anyone else's heart
+ desires.
+ <field>
+ <field_name>
+ field name
+ <field_body>
+ <paragraph>
+ This is a "generic bibliographic field".
+ <field>
+ <field_name>
+ field name "2"
+ <field_body>
+ <paragraph>
+ Generic bibliographic fields may contain multiple body elements.
+ <paragraph>
+ Like this.
+ <topic classes="dedication">
+ <title>
+ Dedication
+ <paragraph>
+ For Docutils users & co-developers.
+ <topic classes="abstract">
+ <title>
+ Abstract
+ <paragraph>
+ This is a test document, containing at least one example of each
+ reStructuredText construct.
+ <comment xml:space="preserve">
+ This is a comment. Note how any initial comments are moved by
+ transforms to after the document title, subtitle, and docinfo.
+ <target refid="doctitle">
+ <comment xml:space="preserve">
+ Above is the document title, and below is the subtitle.
+ They are transformed from section titles after parsing.
+ <target refid="subtitle">
+ <comment xml:space="preserve">
+ bibliographic fields (which also require a transform):
+ <meta content="reStructuredText, test, parser" name="keywords">
+ <meta content="A test document, containing at least one example of each reStructuredText construct." lang="en" name="description">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id32" refid="structural-elements">
+ <generated classes="sectnum">
+ 1   
+ Structural Elements
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id33" refid="section-title">
+ <generated classes="sectnum">
+ 1.1   
+ Section Title
+ <list_item>
+ <paragraph>
+ <reference ids="id34" refid="empty-section">
+ <generated classes="sectnum">
+ 1.2   
+ Empty Section
+ <list_item>
+ <paragraph>
+ <reference ids="id35" refid="transitions">
+ <generated classes="sectnum">
+ 1.3   
+ Transitions
+ <list_item>
+ <paragraph>
+ <reference ids="id36" refid="body-elements">
+ <generated classes="sectnum">
+ 2   
+ Body Elements
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id37" refid="paragraphs">
+ <generated classes="sectnum">
+ 2.1   
+ Paragraphs
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id38" refid="inline-markup">
+ <generated classes="sectnum">
+ 2.1.1   
+ Inline Markup
+ <list_item>
+ <paragraph>
+ <reference ids="id39" refid="bullet-lists">
+ <generated classes="sectnum">
+ 2.2   
+ Bullet Lists
+ <list_item>
+ <paragraph>
+ <reference ids="id40" refid="enumerated-lists">
+ <generated classes="sectnum">
+ 2.3   
+ Enumerated Lists
+ <list_item>
+ <paragraph>
+ <reference ids="id41" refid="definition-lists">
+ <generated classes="sectnum">
+ 2.4   
+ Definition Lists
+ <list_item>
+ <paragraph>
+ <reference ids="id42" refid="field-lists">
+ <generated classes="sectnum">
+ 2.5   
+ Field Lists
+ <list_item>
+ <paragraph>
+ <reference ids="id43" refid="option-lists">
+ <generated classes="sectnum">
+ 2.6   
+ Option Lists
+ <list_item>
+ <paragraph>
+ <reference ids="id44" refid="literal-blocks">
+ <generated classes="sectnum">
+ 2.7   
+ Literal Blocks
+ <list_item>
+ <paragraph>
+ <reference ids="id45" refid="line-blocks">
+ <generated classes="sectnum">
+ 2.8   
+ Line Blocks
+ <list_item>
+ <paragraph>
+ <reference ids="id46" refid="block-quotes">
+ <generated classes="sectnum">
+ 2.9   
+ Block Quotes
+ <list_item>
+ <paragraph>
+ <reference ids="id47" refid="doctest-blocks">
+ <generated classes="sectnum">
+ 2.10   
+ Doctest Blocks
+ <list_item>
+ <paragraph>
+ <reference ids="id48" refid="footnotes">
+ <generated classes="sectnum">
+ 2.11   
+ Footnotes
+ <list_item>
+ <paragraph>
+ <reference ids="id49" refid="citations">
+ <generated classes="sectnum">
+ 2.12   
+ Citations
+ <list_item>
+ <paragraph>
+ <reference ids="id50" refid="targets">
+ <generated classes="sectnum">
+ 2.13   
+ Targets
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id51" refid="duplicate-target-names">
+ <generated classes="sectnum">
+ 2.13.1   
+ Duplicate Target Names
+ <list_item>
+ <paragraph>
+ <reference ids="id52" refid="id20">
+ <generated classes="sectnum">
+ 2.13.2   
+ Duplicate Target Names
+ <list_item>
+ <paragraph>
+ <reference ids="id53" refid="directives">
+ <generated classes="sectnum">
+ 2.14   
+ Directives
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id54" refid="document-parts">
+ <generated classes="sectnum">
+ 2.14.1   
+ Document Parts
+ <list_item>
+ <paragraph>
+ <reference ids="id55" refid="images">
+ <generated classes="sectnum">
+ 2.14.2   
+ Images
+ <list_item>
+ <paragraph>
+ <reference ids="id56" refid="admonitions">
+ <generated classes="sectnum">
+ 2.14.3   
+ Admonitions
+ <list_item>
+ <paragraph>
+ <reference ids="id57" refid="topics-sidebars-and-rubrics">
+ <generated classes="sectnum">
+ 2.14.4   
+ Topics, Sidebars, and Rubrics
+ <list_item>
+ <paragraph>
+ <reference ids="id58" refid="target-footnotes">
+ <generated classes="sectnum">
+ 2.14.5   
+ Target Footnotes
+ <list_item>
+ <paragraph>
+ <reference ids="id59" refid="replacement-text">
+ <generated classes="sectnum">
+ 2.14.6   
+ Replacement Text
+ <list_item>
+ <paragraph>
+ <reference ids="id60" refid="compound-paragraph">
+ <generated classes="sectnum">
+ 2.14.7   
+ Compound Paragraph
+ <list_item>
+ <paragraph>
+ <reference ids="id61" refid="parsed-literal-blocks">
+ <generated classes="sectnum">
+ 2.14.8   
+ Parsed Literal Blocks
+ <list_item>
+ <paragraph>
+ <reference ids="id62" refid="substitution-definitions">
+ <generated classes="sectnum">
+ 2.15   
+ Substitution Definitions
+ <list_item>
+ <paragraph>
+ <reference ids="id63" refid="comments">
+ <generated classes="sectnum">
+ 2.16   
+ Comments
+ <list_item>
+ <paragraph>
+ <reference ids="id64" refid="raw-text">
+ <generated classes="sectnum">
+ 2.17   
+ Raw text
+ <list_item>
+ <paragraph>
+ <reference ids="id65" refid="container">
+ <generated classes="sectnum">
+ 2.18   
+ Container
+ <list_item>
+ <paragraph>
+ <reference ids="id66" refid="colspanning-tables">
+ <generated classes="sectnum">
+ 2.19   
+ Colspanning tables
+ <list_item>
+ <paragraph>
+ <reference ids="id67" refid="rowspanning-tables">
+ <generated classes="sectnum">
+ 2.20   
+ Rowspanning tables
+ <list_item>
+ <paragraph>
+ <reference ids="id68" refid="complex-tables">
+ <generated classes="sectnum">
+ 2.21   
+ Complex tables
+ <list_item>
+ <paragraph>
+ <reference ids="id69" refid="list-tables">
+ <generated classes="sectnum">
+ 2.22   
+ List Tables
+ <list_item>
+ <paragraph>
+ <reference ids="id70" refid="error-handling">
+ <generated classes="sectnum">
+ 3   
+ Error Handling
+ <section ids="structural-elements" names="structural\ elements">
+ <title auto="1" refid="id32">
+ <generated classes="sectnum">
+ 1   
+ Structural Elements
+ <section ids="section-title" names="section\ title">
+ <title auto="1" refid="id33">
+ <generated classes="sectnum">
+ 1.1   
+ Section Title
+ <subtitle ids="section-subtitle" names="section\ subtitle">
+ Section Subtitle
+ <paragraph>
+ That's it, the text just above this line.
+ <section ids="empty-section" names="empty\ section">
+ <title auto="1" refid="id34">
+ <generated classes="sectnum">
+ 1.2   
+ Empty Section
+ <section ids="transitions" names="transitions">
+ <title auto="1" refid="id35">
+ <generated classes="sectnum">
+ 1.3   
+ Transitions
+ <paragraph>
+ Here's a transition:
+ <transition>
+ <paragraph>
+ It divides the section. Transitions may also occur between sections:
+ <transition>
+ <section ids="body-elements" names="body\ elements">
+ <title auto="1" refid="id36">
+ <generated classes="sectnum">
+ 2   
+ Body Elements
+ <section ids="paragraphs" names="paragraphs">
+ <title auto="1" refid="id37">
+ <generated classes="sectnum">
+ 2.1   
+ Paragraphs
+ <paragraph>
+ A paragraph.
+ <section ids="inline-markup" names="inline\ markup">
+ <title auto="1" refid="id38">
+ <generated classes="sectnum">
+ 2.1.1   
+ Inline Markup
+ <paragraph>
+ Paragraphs contain text and may contain inline markup:
+ <emphasis>
+ emphasis
+ ,
+ <strong>
+ strong emphasis
+ ,
+ <literal>
+ inline literals
+ , standalone hyperlinks
+ (
+ <reference refuri="http://www.python.org">
+ http://www.python.org
+ ), external hyperlinks (
+ <reference name="Python" refuri="http://www.python.org/">
+ Python
+
+ <footnote_reference auto="1" ids="id26" refid="id25">
+ 5
+ ), internal
+ cross-references (
+ <reference name="example" refid="example">
+ example
+ ), external hyperlinks with embedded URIs
+ (
+ <reference name="Python web site" refuri="http://www.python.org">
+ Python web site
+ ),
+ <reference anonymous="1" name="anonymous hyperlink references" refuri="http://www.python.org/">
+ anonymous hyperlink
+ references
+
+ <footnote_reference auto="1" ids="id29" refid="id25">
+ 5
+ (
+ <reference anonymous="1" name="a second reference" refuri="http://docutils.sourceforge.net/">
+ a second reference
+
+ <footnote_reference auto="1" ids="id31" refid="id30">
+ 6
+ ), footnote references (manually
+ numbered
+ <footnote_reference ids="id1" refid="id8">
+ 1
+ , anonymous auto-numbered
+ <footnote_reference auto="1" ids="id2" refid="id11">
+ 3
+ , labeled auto-numbered
+ <footnote_reference auto="1" ids="id3" refid="label">
+ 2
+ , or symbolic
+ <footnote_reference auto="*" ids="id4" refid="id12">
+ *
+ ), citation references (
+ <citation_reference ids="id5" refid="cit2002">
+ CIT2002
+ ),
+ substitution references (
+ <image alt="EXAMPLE" uri="../../../docs/user/rst/images/biohazard.png">
+ ), and
+ <target ids="inline-hyperlink-targets" names="inline\ hyperlink\ targets">
+ inline hyperlink targets
+
+ (see
+ <reference name="Targets" refid="id22">
+ Targets
+ below for a reference back to here). Character-level
+ inline markup is also possible (although exceedingly ugly!) in
+ <emphasis>
+ re
+ <literal>
+ Structured
+ <emphasis>
+ Text
+ . Problems are indicated by
+ <problematic ids="id24" refid="id23">
+ |problematic|
+ text
+ (generated by processing errors; this one is intentional). Here is a
+ reference to the
+ <reference name="doctitle" refid="doctitle">
+ doctitle
+ and the
+ <reference name="subtitle" refid="subtitle">
+ subtitle
+ .
+ <target anonymous="1" ids="id6" refuri="http://www.python.org/">
+ <target anonymous="1" ids="id7" refuri="http://docutils.sourceforge.net/">
+ <paragraph>
+ The default role for interpreted text is
+ <title_reference>
+ Title Reference
+ . Here are
+ some explicit interpreted text roles: a PEP reference (
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ PEP 287
+ ); an
+ RFC reference (
+ <reference refuri="http://www.faqs.org/rfcs/rfc2822.html">
+ RFC 2822
+ ); a
+ <subscript>
+ subscript
+ ; a
+ <superscript>
+ superscript
+ ;
+ and explicit roles for
+ <emphasis>
+ standard
+
+ <strong>
+ inline
+
+ <literal>
+ markup
+ .
+ <comment xml:space="preserve">
+ DO NOT RE-WRAP THE FOLLOWING PARAGRAPH!
+ <paragraph>
+ Let's test wrapping and whitespace significance in inline literals:
+ <literal>
+ This is an example of --inline-literal --text, --including some--
+ strangely--hyphenated-words. Adjust-the-width-of-your-browser-window
+ to see how the text is wrapped. -- ---- -------- Now note the
+ spacing between the words of this sentence (words
+ should be grouped in pairs).
+ <paragraph>
+ If the
+ <literal>
+ --pep-references
+ option was supplied, there should be a
+ live link to PEP 258 here.
+ <section ids="bullet-lists" names="bullet\ lists">
+ <title auto="1" refid="id39">
+ <generated classes="sectnum">
+ 2.2   
+ Bullet Lists
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ A bullet list
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ Nested bullet list.
+ <list_item>
+ <paragraph>
+ Nested item 2.
+ <list_item>
+ <paragraph>
+ Item 2.
+ <paragraph>
+ Paragraph 2 of item 2.
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ Nested bullet list.
+ <list_item>
+ <paragraph>
+ Nested item 2.
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Third level.
+ <list_item>
+ <paragraph>
+ Item 2.
+ <list_item>
+ <paragraph>
+ Nested item 3.
+ <list_item>
+ <paragraph>
+ This nested list should be compacted by the HTML writer.
+ <target ids="target" names="target">
+ <comment xml:space="preserve">
+ Even if this item contains a target and a comment.
+ <section ids="enumerated-lists" names="enumerated\ lists">
+ <title auto="1" refid="id40">
+ <generated classes="sectnum">
+ 2.3   
+ Enumerated Lists
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Arabic numerals.
+ <enumerated_list enumtype="loweralpha" prefix="" suffix=")">
+ <list_item>
+ <paragraph>
+ lower alpha)
+ <enumerated_list enumtype="lowerroman" prefix="(" suffix=")">
+ <list_item>
+ <paragraph>
+ (lower roman)
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ upper alpha.
+ <enumerated_list enumtype="upperroman" prefix="" suffix=")">
+ <list_item>
+ <paragraph>
+ upper roman)
+ <list_item>
+ <paragraph>
+ Lists that don't start at 1:
+ <enumerated_list enumtype="arabic" prefix="" start="3" suffix=".">
+ <list_item>
+ <paragraph>
+ Three
+ <list_item>
+ <paragraph>
+ Four
+ <enumerated_list enumtype="upperalpha" prefix="" start="3" suffix=".">
+ <list_item>
+ <paragraph>
+ C
+ <list_item>
+ <paragraph>
+ D
+ <enumerated_list enumtype="lowerroman" prefix="" start="3" suffix=".">
+ <list_item>
+ <paragraph>
+ iii
+ <list_item>
+ <paragraph>
+ iv
+ <section ids="definition-lists" names="definition\ lists">
+ <title auto="1" refid="id41">
+ <generated classes="sectnum">
+ 2.4   
+ Definition Lists
+ <definition_list>
+ <definition_list_item>
+ <term>
+ Term
+ <definition>
+ <paragraph>
+ Definition
+ <definition_list_item>
+ <term>
+ Term
+ <classifier>
+ classifier
+ <definition>
+ <paragraph>
+ Definition paragraph 1.
+ <paragraph>
+ Definition paragraph 2.
+ <definition_list_item>
+ <term>
+ Term
+ <definition>
+ <paragraph>
+ Definition
+ <definition_list_item>
+ <term>
+ Term
+ <classifier>
+ classifier one
+ <classifier>
+ classifier two
+ <definition>
+ <paragraph>
+ Definition
+ <section ids="field-lists" names="field\ lists">
+ <title auto="1" refid="id42">
+ <generated classes="sectnum">
+ 2.5   
+ Field Lists
+ <field_list>
+ <field>
+ <field_name>
+ what
+ <field_body>
+ <paragraph>
+ Field lists map field names to field bodies, like database
+ records. They are often part of an extension syntax. They are
+ an unambiguous variant of RFC 2822 fields.
+ <field>
+ <field_name>
+ how arg1 arg2
+ <field_body>
+ <paragraph>
+ The field marker is a colon, the field name, and a colon.
+ <paragraph>
+ The field body may contain one or more body elements, indented
+ relative to the field marker.
+ <field>
+ <field_name>
+ credits
+ <field_body>
+ <paragraph classes="credits">
+ This paragraph has the
+ <title_reference>
+ credits
+ class set. (This is actually not
+ about credits but just for ensuring that the class attribute
+ doesn't get stripped away.)
+ <section ids="option-lists" names="option\ lists">
+ <title auto="1" refid="id43">
+ <generated classes="sectnum">
+ 2.6   
+ Option Lists
+ <paragraph>
+ For listing command-line options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ command-line option "a"
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ options can have arguments
+ and long descriptions
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long
+ <description>
+ <paragraph>
+ options can be long also
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --input
+ <option_argument delimiter="=">
+ file
+ <description>
+ <paragraph>
+ long options can also have
+ arguments
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --very-long-option
+ <description>
+ <paragraph>
+ The description can also start on the next line.
+ <paragraph>
+ The description may contain multiple body elements,
+ regardless of where it starts.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -x
+ <option>
+ <option_string>
+ -y
+ <option>
+ <option_string>
+ -z
+ <description>
+ <paragraph>
+ Multiple options are an "option group".
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -v
+ <option>
+ <option_string>
+ --verbose
+ <description>
+ <paragraph>
+ Commonly-seen: short & long options.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -1
+ <option_argument delimiter=" ">
+ file
+ <option>
+ <option_string>
+ --one
+ <option_argument delimiter="=">
+ file
+ <option>
+ <option_string>
+ --two
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ Multiple options with arguments.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /V
+ <description>
+ <paragraph>
+ DOS/VMS-style options too
+ <paragraph>
+ There must be at least two spaces between the option and the
+ description.
+ <section ids="literal-blocks" names="literal\ blocks">
+ <title auto="1" refid="id44">
+ <generated classes="sectnum">
+ 2.7   
+ Literal Blocks
+ <paragraph>
+ Literal blocks are indicated with a double-colon ("::") at the end of
+ the preceding paragraph (over there
+ <literal>
+ -->
+ ). They can be indented:
+ <literal_block xml:space="preserve">
+ if literal_block:
+ text = 'is left as-is'
+ spaces_and_linebreaks = 'are preserved'
+ markup_processing = None
+ <paragraph>
+ Or they can be quoted without indentation:
+ <literal_block xml:space="preserve">
+ >> Great idea!
+ >
+ > Why didn't I think of that?
+ <section ids="line-blocks" names="line\ blocks">
+ <title auto="1" refid="id45">
+ <generated classes="sectnum">
+ 2.8   
+ Line Blocks
+ <paragraph>
+ This section tests line blocks. Line blocks are body elements which
+ consist of lines and other line blocks. Nested line blocks cause
+ indentation.
+ <line_block>
+ <line>
+ This is a line block. It ends with a blank line.
+ <line_block>
+ <line>
+ New lines begin with a vertical bar ("|").
+ <line>
+ Line breaks and initial indent are significant, and preserved.
+ <line_block>
+ <line>
+ Continuation lines are also possible. A long line that is intended
+ to wrap should begin with a space in place of the vertical bar.
+ <line>
+ The left edge of a continuation line need not be aligned with
+ the left edge of the text above it.
+ <line_block>
+ <line>
+ This is a second line block.
+ <line>
+ <line>
+ Blank lines are permitted internally, but they must begin with a "|".
+ <paragraph>
+ Another line block, surrounded by paragraphs:
+ <line_block>
+ <line>
+ And it's no good waiting by the window
+ <line>
+ It's no good waiting for the sun
+ <line>
+ Please believe me, the things you dream of
+ <line>
+ They don't fall in the lap of no-one
+ <paragraph>
+ Take it away, Eric the Orchestra Leader!
+ <block_quote>
+ <line_block>
+ <line>
+ A one, two, a one two three four
+ <line>
+ <line>
+ Half a bee, philosophically,
+ <line_block>
+ <line>
+ must,
+ <emphasis>
+ ipso facto
+ , half not be.
+ <line>
+ But half the bee has got to be,
+ <line_block>
+ <line>
+ <emphasis>
+ vis a vis
+ its entity. D'you see?
+ <line>
+ <line>
+ But can a bee be said to be
+ <line_block>
+ <line>
+ or not to be an entire bee,
+ <line_block>
+ <line>
+ when half the bee is not a bee,
+ <line_block>
+ <line>
+ due to some ancient injury?
+ <line>
+ <line>
+ Singing...
+ <section ids="block-quotes" names="block\ quotes">
+ <title auto="1" refid="id46">
+ <generated classes="sectnum">
+ 2.9   
+ Block Quotes
+ <paragraph>
+ Block quotes consist of indented body elements:
+ <block_quote>
+ <paragraph>
+ My theory by A. Elk. Brackets Miss, brackets. This theory goes
+ as follows and begins now. All brontosauruses are thin at one
+ end, much much thicker in the middle and then thin again at the
+ far end. That is my theory, it is mine, and belongs to me and I
+ own it, and what it is too.
+ <attribution>
+ Anne Elk (Miss)
+ <section ids="doctest-blocks" names="doctest\ blocks">
+ <title auto="1" refid="id47">
+ <generated classes="sectnum">
+ 2.10   
+ Doctest Blocks
+ <doctest_block xml:space="preserve">
+ >>> print 'Python-specific usage examples; begun with ">>>"'
+ Python-specific usage examples; begun with ">>>"
+ >>> print '(cut and pasted from interactive Python sessions)'
+ (cut and pasted from interactive Python sessions)
+ <section ids="footnotes" names="footnotes">
+ <title auto="1" refid="id48">
+ <generated classes="sectnum">
+ 2.11   
+ Footnotes
+ <footnote backrefs="id1 id9 id21" ids="id8" names="1">
+ <label>
+ 1
+ <paragraph>
+ A footnote contains body elements, consistently indented by at
+ least 3 spaces.
+ <paragraph>
+ This is the footnote's second paragraph.
+ <footnote auto="1" backrefs="id3 id10" ids="label" names="label">
+ <label>
+ 2
+ <paragraph>
+ Footnotes may be numbered, either manually (as in
+ <footnote_reference ids="id9" refid="id8">
+ 1
+ ) or
+ automatically using a "#"-prefixed label. This footnote has a
+ label so it can be referred to from multiple places, both as a
+ footnote reference (
+ <footnote_reference auto="1" ids="id10" refid="label">
+ 2
+ ) and as a hyperlink reference
+ (
+ <reference name="label" refid="label">
+ label
+ ).
+ <footnote auto="1" backrefs="id2" ids="id11" names="3">
+ <label>
+ 3
+ <paragraph>
+ This footnote is numbered automatically and anonymously using a
+ label of "#" only.
+ <paragraph>
+ This is the second paragraph.
+ <paragraph>
+ And this is the third paragraph.
+ <footnote auto="*" backrefs="id4" ids="id12">
+ <label>
+ *
+ <paragraph>
+ Footnotes may also use symbols, specified with a "*" label.
+ Here's a reference to the next footnote:
+ <footnote_reference auto="*" ids="id13" refid="id14">
+ †
+ .
+ <footnote auto="*" backrefs="id13" ids="id14">
+ <label>
+ †
+ <paragraph>
+ This footnote shows the next symbol in the sequence.
+ <footnote ids="id15" names="4">
+ <label>
+ 4
+ <paragraph>
+ Here's an unreferenced footnote, with a reference to a
+ nonexistent footnote:
+ <problematic ids="id80 id16" refid="id79">
+ [5]_
+ .
+ <section ids="citations" names="citations">
+ <title auto="1" refid="id49">
+ <generated classes="sectnum">
+ 2.12   
+ Citations
+ <citation backrefs="id5 id17" ids="cit2002" names="cit2002">
+ <label>
+ CIT2002
+ <paragraph>
+ Citations are text-labeled footnotes. They may be
+ rendered separately and differently from footnotes.
+ <paragraph>
+ Here's a reference to the above,
+ <citation_reference ids="id17" refid="cit2002">
+ CIT2002
+ , and a
+ <problematic ids="id82 id18" refid="id81">
+ [nonexistent]_
+
+ citation.
+ <target refid="another-target">
+ <section dupnames="targets" ids="targets another-target" names="another\ target">
+ <title auto="1" refid="id50">
+ <generated classes="sectnum">
+ 2.13   
+ Targets
+ <target refid="example">
+ <paragraph ids="example" names="example">
+ This paragraph is pointed to by the explicit "example" target. A
+ reference can be found under
+ <reference name="Inline Markup" refid="inline-markup">
+ Inline Markup
+ , above.
+ <reference name="Inline hyperlink targets" refid="inline-hyperlink-targets">
+ Inline
+ hyperlink targets
+ are also possible.
+ <paragraph>
+ Section headers are implicit targets, referred to by name. See
+ <reference name="Targets" refid="id22">
+ Targets
+ , which is a subsection of
+ <reference name="Body Elements" refid="body-elements">
+ Body Elements
+ .
+ <paragraph>
+ Explicit external targets are interpolated into references such as
+ "
+ <reference name="Python" refuri="http://www.python.org/">
+ Python
+
+ <footnote_reference auto="1" ids="id27" refid="id25">
+ 5
+ ".
+ <target ids="python" names="python" refuri="http://www.python.org/">
+ <paragraph>
+ Targets may be indirect and anonymous. Thus
+ <reference anonymous="1" name="this phrase" refid="id22">
+ this phrase
+ may also
+ refer to the
+ <reference name="Targets" refid="id22">
+ Targets
+ section.
+ <target anonymous="1" ids="id19" refid="id22">
+ <paragraph>
+ Here's a
+ <problematic ids="id84" refid="id83">
+ `hyperlink reference without a target`_
+ , which generates an
+ error.
+ <section dupnames="duplicate\ target\ names" ids="duplicate-target-names">
+ <title auto="1" refid="id51">
+ <generated classes="sectnum">
+ 2.13.1   
+ Duplicate Target Names
+ <paragraph>
+ Duplicate names in section headers or other implicit targets will
+ generate "info" (level-1) system messages. Duplicate names in
+ explicit targets will generate "warning" (level-2) system messages.
+ <section dupnames="duplicate\ target\ names" ids="id20">
+ <title auto="1" refid="id52">
+ <generated classes="sectnum">
+ 2.13.2   
+ Duplicate Target Names
+ <paragraph>
+ Since there are two "Duplicate Target Names" section headers, we
+ cannot uniquely refer to either of them by name. If we try to (like
+ this:
+ <problematic ids="id86" refid="id85">
+ `Duplicate Target Names`_
+ ), an error is generated.
+ <section ids="directives" names="directives">
+ <title auto="1" refid="id53">
+ <generated classes="sectnum">
+ 2.14   
+ Directives
+ <topic classes="contents local" ids="contents" names="contents">
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id71" refid="document-parts">
+ <generated classes="sectnum">
+ 2.14.1   
+ Document Parts
+ <list_item>
+ <paragraph>
+ <reference ids="id72" refid="images">
+ <generated classes="sectnum">
+ 2.14.2   
+ Images
+ <list_item>
+ <paragraph>
+ <reference ids="id73" refid="admonitions">
+ <generated classes="sectnum">
+ 2.14.3   
+ Admonitions
+ <list_item>
+ <paragraph>
+ <reference ids="id74" refid="topics-sidebars-and-rubrics">
+ <generated classes="sectnum">
+ 2.14.4   
+ Topics, Sidebars, and Rubrics
+ <list_item>
+ <paragraph>
+ <reference ids="id75" refid="target-footnotes">
+ <generated classes="sectnum">
+ 2.14.5   
+ Target Footnotes
+ <list_item>
+ <paragraph>
+ <reference ids="id76" refid="replacement-text">
+ <generated classes="sectnum">
+ 2.14.6   
+ Replacement Text
+ <list_item>
+ <paragraph>
+ <reference ids="id77" refid="compound-paragraph">
+ <generated classes="sectnum">
+ 2.14.7   
+ Compound Paragraph
+ <list_item>
+ <paragraph>
+ <reference ids="id78" refid="parsed-literal-blocks">
+ <generated classes="sectnum">
+ 2.14.8   
+ Parsed Literal Blocks
+ <paragraph>
+ These are just a sample of the many reStructuredText Directives. For
+ others, please see
+ <reference refuri="http://docutils.sourceforge.net/docs/ref/rst/directives.html">
+ http://docutils.sourceforge.net/docs/ref/rst/directives.html
+ .
+ <section ids="document-parts" names="document\ parts">
+ <title auto="1" refid="id71">
+ <generated classes="sectnum">
+ 2.14.1   
+ Document Parts
+ <paragraph>
+ An example of the "contents" directive can be seen above this section
+ (a local, untitled table of
+ <reference name="contents" refid="contents">
+ contents
+ ) and at the beginning of the
+ document (a document-wide
+ <reference name="table of contents" refid="table-of-contents">
+ table of contents
+ ).
+ <section ids="images" names="images">
+ <title auto="1" refid="id72">
+ <generated classes="sectnum">
+ 2.14.2   
+ Images
+ <paragraph>
+ An image directive (also clickable -- a hyperlink reference):
+ <reference name="directives" refid="directives">
+ <image classes="class1 class2" uri="../../../docs/user/rst/images/title.png">
+ <paragraph>
+ Image with multiple IDs:
+ <target refid="image-target-1">
+ <target refid="image-target-2">
+ <target refid="image-target-3">
+ <image ids="image-target-3 image-target-2 image-target-1" names="image\ target\ 3 image\ target\ 2 image\ target\ 1" uri="../../../docs/user/rst/images/title.png">
+ <paragraph>
+ A centered image:
+ <image align="center" uri="../../../docs/user/rst/images/biohazard.png">
+ <paragraph>
+ A left-aligned image:
+ <image align="left" uri="../../../docs/user/rst/images/biohazard.png">
+ <paragraph>
+ A right-aligned image:
+ <image align="right" uri="../../../docs/user/rst/images/biohazard.png">
+ <paragraph>
+ A figure directive:
+ <figure align="right" classes="figclass1 figclass2">
+ <image alt="reStructuredText, the markup syntax" classes="class1 class2" uri="../../../docs/user/rst/images/biohazard.png" width="50">
+ <caption>
+ A figure is an image with a caption and/or a legend:
+ <legend>
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="47">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ re
+ <entry>
+ <paragraph>
+ Revised, revisited, based on 're' module.
+ <row>
+ <entry>
+ <paragraph>
+ Structured
+ <entry>
+ <paragraph>
+ Structure-enhanced text, structuredtext.
+ <row>
+ <entry>
+ <paragraph>
+ Text
+ <entry>
+ <paragraph>
+ Well it is, isn't it?
+ <paragraph>
+ This paragraph is also part of the legend.
+ <figure align="left" classes="figclass1 figclass2">
+ <image alt="reStructuredText, the markup syntax" classes="class1 class2" uri="../../../docs/user/rst/images/biohazard.png" width="50">
+ <caption>
+ A left-aligned figure.
+ <legend>
+ <paragraph>
+ This is the legend.
+ <paragraph>
+ This paragraph might flow around the figure...
+ <paragraph>
+ A centered figure:
+ <figure align="center">
+ <image uri="../../../docs/user/rst/images/biohazard.png" width="50">
+ <caption>
+ This is the caption.
+ <legend>
+ <paragraph>
+ This is the legend.
+ <paragraph>
+ The legend may consist of several paragraphs.
+ <paragraph>
+ This paragraph might flow around the figure...
+ <paragraph>
+ A left-aligned figure:
+ <figure align="left">
+ <image uri="../../../docs/user/rst/images/biohazard.png" width="50">
+ <caption>
+ This is the caption.
+ <legend>
+ <paragraph>
+ This is the legend.
+ <paragraph>
+ The legend may consist of several paragraphs.
+ <paragraph>
+ This paragraph might flow around the figure...
+ <paragraph>
+ Now widths:
+ <paragraph>
+ An image 2 em wide:
+ <image uri="../../../docs/user/rst/images/biohazard.png" width="2em">
+ <paragraph>
+ An image 2 em wide and 30 pixel high:
+ <image height="30px" uri="../../../docs/user/rst/images/biohazard.png" width="2em">
+ <paragraph>
+ An image occupying 70% of the line width:
+ <image uri="../../../docs/user/rst/images/biohazard.png" width="70%">
+ <paragraph>
+ An image 3 cm high:
+ <image height="3cm" uri="../../../docs/user/rst/images/biohazard.png">
+ <section ids="admonitions" names="admonitions">
+ <title auto="1" refid="id73">
+ <generated classes="sectnum">
+ 2.14.3   
+ Admonitions
+ <attention>
+ <paragraph>
+ Directives at large.
+ <caution>
+ <paragraph>
+ Don't take any wooden nickels.
+ <danger>
+ <paragraph>
+ Mad scientist at work!
+ <error>
+ <paragraph>
+ Does not compute.
+ <hint>
+ <paragraph>
+ It's bigger than a bread box.
+ <important>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Wash behind your ears.
+ <list_item>
+ <paragraph>
+ Clean up your room.
+ <list_item>
+ <paragraph>
+ Call your mother.
+ <list_item>
+ <paragraph>
+ Back up your data.
+ <note>
+ <paragraph>
+ This is a note.
+ <tip>
+ <paragraph>
+ 15% if the service is good.
+ <warning>
+ <paragraph>
+ Strong prose may provoke extreme mental exertion.
+ Reader discretion is strongly advised.
+ <admonition classes="admonition-and-by-the-way">
+ <title>
+ And, by the way...
+ <paragraph>
+ You can make up your own admonition too.
+ <target ids="docutils" names="docutils" refuri="http://docutils.sourceforge.net/">
+ <section ids="topics-sidebars-and-rubrics" names="topics,\ sidebars,\ and\ rubrics">
+ <title auto="1" refid="id74">
+ <generated classes="sectnum">
+ 2.14.4   
+ Topics, Sidebars, and Rubrics
+ <sidebar>
+ <title>
+ Sidebar Title
+ <subtitle>
+ Optional Subtitle
+ <paragraph>
+ This is a sidebar. It is for text outside the flow of the main
+ text.
+ <rubric>
+ This is a rubric inside a sidebar
+ <paragraph>
+ Sidebars often appears beside the main text with a border and
+ background color.
+ <topic>
+ <title>
+ Topic Title
+ <paragraph>
+ This is a topic.
+ <rubric>
+ This is a rubric
+ <section ids="target-footnotes" names="target\ footnotes">
+ <title auto="1" refid="id75">
+ <generated classes="sectnum">
+ 2.14.5   
+ Target Footnotes
+ <footnote auto="1" backrefs="id26 id27 id28 id29" ids="id25" names="TARGET_NOTE:\ id25">
+ <label>
+ 5
+ <paragraph>
+ <reference refuri="http://www.python.org/">
+ http://www.python.org/
+ <footnote auto="1" backrefs="id31" ids="id30" names="TARGET_NOTE:\ id30">
+ <label>
+ 6
+ <paragraph>
+ <reference refuri="http://docutils.sourceforge.net/">
+ http://docutils.sourceforge.net/
+ <section ids="replacement-text" names="replacement\ text">
+ <title auto="1" refid="id76">
+ <generated classes="sectnum">
+ 2.14.6   
+ Replacement Text
+ <paragraph>
+ I recommend you try
+ <reference refuri="http://www.python.org/">
+ Python,
+ <emphasis>
+ the
+ best language around
+
+ <footnote_reference auto="1" ids="id28" refid="id25">
+ 5
+ .
+ <substitution_definition names="Python">
+ Python,
+ <emphasis>
+ the
+ best language around
+ <section ids="compound-paragraph" names="compound\ paragraph">
+ <title auto="1" refid="id77">
+ <generated classes="sectnum">
+ 2.14.7   
+ Compound Paragraph
+ <compound classes="some-class">
+ <paragraph>
+ Compound 1, paragraph 1.
+ <paragraph>
+ Compound 1, paragraph 2.
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ Compound 1, list item one.
+ <list_item>
+ <paragraph>
+ Compound 1, list item two.
+ <paragraph>
+ Another compound statement:
+ <compound>
+ <paragraph>
+ Compound 2, a literal block:
+ <literal_block xml:space="preserve">
+ Compound 2, literal.
+ <paragraph>
+ Compound 2, this is a test.
+ <compound>
+ <paragraph>
+ Compound 3, only consisting of one paragraph.
+ <compound>
+ <literal_block xml:space="preserve">
+ Compound 4.
+ This one starts with a literal block.
+ <paragraph>
+ Compound 4, a paragraph.
+ <paragraph>
+ Now something
+ <emphasis>
+ really
+ perverted -- a nested compound block. This is
+ just to test that it works at all; the results don't have to be
+ meaningful.
+ <compound>
+ <paragraph>
+ Compound 5, block 1 (a paragraph).
+ <compound>
+ <paragraph>
+ Compound 6, block 2 in compound 5.
+ <paragraph>
+ Compound 6, another paragraph.
+ <paragraph>
+ Compound 5, block 3 (a paragraph).
+ <compound>
+ <paragraph>
+ Compound 7, with a table inside:
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="20">
+ <colspec colwidth="20">
+ <colspec colwidth="20">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Left cell, first
+ paragraph.
+ <paragraph>
+ Left cell, second
+ paragraph.
+ <entry>
+ <paragraph>
+ Middle cell,
+ consisting of
+ exactly one
+ paragraph.
+ <entry>
+ <paragraph>
+ Right cell.
+ <paragraph>
+ Paragraph 2.
+ <paragraph>
+ Paragraph 3.
+ <paragraph>
+ Compound 7, a paragraph after the table.
+ <paragraph>
+ Compound 7, another paragraph.
+ <section ids="parsed-literal-blocks" names="parsed\ literal\ blocks">
+ <title auto="1" refid="id78">
+ <generated classes="sectnum">
+ 2.14.8   
+ Parsed Literal Blocks
+ <literal_block xml:space="preserve">
+ This is a parsed literal block.
+ This line is indented. The next line is blank.
+
+ Inline markup is supported, e.g.
+ <emphasis>
+ emphasis
+ ,
+ <strong>
+ strong
+ ,
+ <literal>
+ literal
+ text
+ , footnotes
+ <footnote_reference ids="id21" refid="id8">
+ 1
+ ,
+ <target ids="id22" names="targets">
+ targets
+ , and
+ <reference name="references" refuri="http://www.python.org/">
+ references
+ <target ids="references" names="references" refuri="http://www.python.org/">
+ .
+ <section ids="substitution-definitions" names="substitution\ definitions">
+ <title auto="1" refid="id62">
+ <generated classes="sectnum">
+ 2.15   
+ Substitution Definitions
+ <paragraph>
+ An inline image (
+ <image alt="EXAMPLE" uri="../../../docs/user/rst/images/biohazard.png">
+ ) example:
+ <substitution_definition names="EXAMPLE">
+ <image alt="EXAMPLE" uri="../../../docs/user/rst/images/biohazard.png">
+ <paragraph>
+ (Substitution definitions are not visible in the HTML source.)
+ <section ids="comments" names="comments">
+ <title auto="1" refid="id63">
+ <generated classes="sectnum">
+ 2.16   
+ Comments
+ <paragraph>
+ Here's one:
+ <comment xml:space="preserve">
+ Comments begin with two dots and a space. Anything may
+ follow, except for the syntax of footnotes, hyperlink
+ targets, directives, or substitution definitions.
+
+ Double-dashes -- "--" -- must be escaped somehow in HTML output.
+ <paragraph>
+ (View the HTML source to see the comment.)
+ <section ids="raw-text" names="raw\ text">
+ <title auto="1" refid="id64">
+ <generated classes="sectnum">
+ 2.17   
+ Raw text
+ <paragraph>
+ This does not necessarily look nice, because there may be missing white space.
+ <paragraph>
+ It's just there to freeze the behavior.
+ <raw format="html latex" xml:space="preserve">
+ A test.
+ <raw format="html latex" xml:space="preserve">
+ Second test.
+ <raw classes="myclass" format="html latex" xml:space="preserve">
+ Another test with myclass set.
+ <paragraph>
+ This is the
+ <raw classes="myrawroleclass" format="html latex" xml:space="preserve">
+ fourth test
+ with myrawroleclass set.
+ <raw format="html" xml:space="preserve">
+ Fifth test in HTML.<br />Line two.
+ <raw format="latex" xml:space="preserve">
+ Fifth test in LaTeX.\\Line two.
+ <section ids="container" names="container">
+ <title auto="1" refid="id65">
+ <generated classes="sectnum">
+ 2.18   
+ Container
+ <container classes="custom">
+ <paragraph>
+ paragraph 1
+ <paragraph>
+ paragraph 2
+ <section ids="colspanning-tables" names="colspanning\ tables">
+ <title auto="1" refid="id66">
+ <generated classes="sectnum">
+ 2.19   
+ Colspanning tables
+ <paragraph>
+ This table has a cell spanning two columns:
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="5">
+ <colspec colwidth="5">
+ <colspec colwidth="6">
+ <thead>
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ Inputs
+ <entry>
+ <paragraph>
+ Output
+ <row>
+ <entry>
+ <paragraph>
+ A
+ <entry>
+ <paragraph>
+ B
+ <entry>
+ <paragraph>
+ A or B
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ False
+ <entry>
+ <paragraph>
+ False
+ <entry>
+ <paragraph>
+ False
+ <row>
+ <entry>
+ <paragraph>
+ True
+ <entry>
+ <paragraph>
+ False
+ <entry>
+ <paragraph>
+ True
+ <row>
+ <entry>
+ <paragraph>
+ False
+ <entry>
+ <paragraph>
+ True
+ <entry>
+ <paragraph>
+ True
+ <row>
+ <entry>
+ <paragraph>
+ True
+ <entry>
+ <paragraph>
+ True
+ <entry>
+ <paragraph>
+ True
+ <section ids="rowspanning-tables" names="rowspanning\ tables">
+ <title auto="1" refid="id67">
+ <generated classes="sectnum">
+ 2.20   
+ Rowspanning tables
+ <paragraph>
+ Here's a table with cells spanning several rows:
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="24">
+ <colspec colwidth="12">
+ <colspec colwidth="18">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Header row, column 1
+ (header rows optional)
+ <entry>
+ <paragraph>
+ Header 2
+ <entry>
+ <paragraph>
+ Header 3
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ body row 1, column 1
+ <entry>
+ <paragraph>
+ column 2
+ <entry>
+ <paragraph>
+ column 3
+ <row>
+ <entry>
+ <paragraph>
+ body row 2
+ <entry morerows="1">
+ <paragraph>
+ Cells may
+ span rows.
+ <entry morerows="1">
+ <paragraph>
+ Another
+ rowspanning
+ cell.
+ <row>
+ <entry>
+ <paragraph>
+ body row 3
+ <section ids="complex-tables" names="complex\ tables">
+ <title auto="1" refid="id68">
+ <generated classes="sectnum">
+ 2.21   
+ Complex tables
+ <paragraph>
+ Here's a complex table, which should test all features.
+ <table>
+ <tgroup cols="4">
+ <colspec colwidth="24">
+ <colspec colwidth="12">
+ <colspec colwidth="10">
+ <colspec colwidth="10">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Header row, column 1
+ (header rows optional)
+ <entry>
+ <paragraph>
+ Header 2
+ <entry>
+ <paragraph>
+ Header 3
+ <entry>
+ <paragraph>
+ Header 4
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ body row 1, column 1
+ <entry>
+ <paragraph>
+ column 2
+ <entry>
+ <paragraph>
+ column 3
+ <entry>
+ <paragraph>
+ column 4
+ <row>
+ <entry>
+ <paragraph>
+ body row 2
+ <entry morecols="2">
+ <paragraph>
+ Cells may span columns.
+ <row>
+ <entry>
+ <paragraph>
+ body row 3
+ <entry morerows="1">
+ <paragraph>
+ Cells may
+ span rows.
+ <paragraph>
+ Paragraph.
+ <entry morecols="1" morerows="1">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Table cells
+ <list_item>
+ <paragraph>
+ contain
+ <list_item>
+ <paragraph>
+ body elements.
+ <row>
+ <entry>
+ <paragraph>
+ body row 4
+ <row>
+ <entry>
+ <paragraph>
+ body row 5
+ <entry morecols="1">
+ <paragraph>
+ Cells may also be
+ empty:
+ <literal>
+ -->
+ <entry>
+ <section ids="list-tables" names="list\ tables">
+ <title auto="1" refid="id69">
+ <generated classes="sectnum">
+ 2.22   
+ List Tables
+ <paragraph>
+ Here's a list table exercising all features:
+ <table classes="test">
+ <title>
+ list table with integral header
+ <tgroup cols="3">
+ <colspec colwidth="10" stub="1">
+ <colspec colwidth="20">
+ <colspec colwidth="30">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <paragraph>
+ Description
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Albatross
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ On a stick!
+ <row>
+ <entry>
+ <paragraph>
+ Crunchy Frog
+ <entry>
+ <paragraph>
+ 1.49
+ <entry>
+ <paragraph>
+ If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ <row>
+ <entry>
+ <paragraph>
+ Gannet Ripple
+ <entry>
+ <paragraph>
+ 1.99
+ <entry>
+ <paragraph>
+ On a stick!
+ <section ids="error-handling" names="error\ handling">
+ <title auto="1" refid="id70">
+ <generated classes="sectnum">
+ 3   
+ Error Handling
+ <paragraph>
+ Any errors caught during processing will generate system messages.
+ <paragraph>
+ There should be five messages in the following, auto-generated
+ section, "Docutils System Messages":
+ <comment xml:space="preserve">
+ section should be added by Docutils automatically
+ <section classes="system-messages">
+ <title>
+ Docutils System Messages
+ <system_message backrefs="id24" ids="id23" level="3" line="100" source="functional/input/data/standard.txt" type="ERROR">
+ <paragraph>
+ Undefined substitution referenced: "problematic".
+ <system_message backrefs="id80" ids="id79" level="3" line="358" source="functional/input/standalone_rst_pseudoxml.txt" type="ERROR">
+ <paragraph>
+ Unknown target name: "5".
+ <system_message backrefs="id82" ids="id81" level="3" line="367" source="functional/input/data/standard.txt" type="ERROR">
+ <paragraph>
+ Unknown target name: "nonexistent".
+ <system_message backrefs="id84" ids="id83" level="3" line="394" source="functional/input/data/standard.txt" type="ERROR">
+ <paragraph>
+ Unknown target name: "hyperlink reference without a target".
+ <system_message backrefs="id86" ids="id85" level="3" line="407" source="functional/input/data/standard.txt" type="ERROR">
+ <paragraph>
+ Duplicate target name, cannot be used as a unique reference: "duplicate target names".
diff --git a/test/functional/expected/standalone_rst_s5_html_1.html b/test/functional/expected/standalone_rst_s5_html_1.html
new file mode 100644
index 000000000..54caa3916
--- /dev/null
+++ b/test/functional/expected/standalone_rst_s5_html_1.html
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<meta name="version" content="S5 1.1" />
+<title>Slide Shows</title>
+<meta name="author" content="David Goodger" />
+<meta name="date" content="2005-11-28" />
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+<!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
+<!-- style sheet links -->
+<script src="ui/small-black/slides.js" type="text/javascript"></script>
+<link rel="stylesheet" href="ui/small-black/slides.css"
+ type="text/css" media="projection" id="slideProj" />
+<link rel="stylesheet" href="ui/small-black/outline.css"
+ type="text/css" media="screen" id="outlineStyle" />
+<link rel="stylesheet" href="ui/small-black/print.css"
+ type="text/css" media="print" id="slidePrint" />
+<link rel="stylesheet" href="ui/small-black/opera.css"
+ type="text/css" media="projection" id="operaFix" />
+
+<style type="text/css">
+#currentSlide {display: none;}
+</style>
+</head>
+<body>
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header">
+
+</div>
+<div id="footer">
+<h1>Slide Shows</h1>
+<h2>Location • Date</h2>
+</div>
+</div>
+<div class="presentation">
+<div class="slide" id="slide0">
+<h1 class="title">Slide Shows</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>David Goodger</td></tr>
+<tr><th class="docinfo-name">Date:</th>
+<td>2005-11-28</td></tr>
+</tbody>
+</table>
+<!-- Definitions of interpreted text roles (classes) for S5/HTML data. -->
+<!-- This data file has been placed in the public domain. -->
+<!-- Colours
+======= -->
+<!-- Text Sizes
+========== -->
+<!-- Display in Slides (Presentation Mode) Only
+========================================== -->
+<!-- Display in Outline Mode Only
+============================ -->
+<!-- Display in Print Only
+===================== -->
+<!-- Incremental Display
+=================== -->
+<div class="contents handout topic">
+<p class="topic-title first"><a id="contents" name="contents">Contents</a></p>
+<ul class="simple">
+<li><a class="reference" href="#introduction" id="id1" name="id1">Introduction</a></li>
+<li><a class="reference" href="#features-1" id="id2" name="id2">Features (1)</a></li>
+<li><a class="reference" href="#features-2" id="id3" name="id3">Features (2)</a></li>
+<li><a class="reference" href="#checklist" id="id4" name="id4">Checklist</a></li>
+</ul>
+</div>
+<p class="handout">This is a test. This is only a test. If this were a real slide
+show, there would be a projector handy.</p>
+<p>Let's test the S5/HTML writer!</p>
+<ul class="small simple">
+<li>Use the arrow keys to navigate.</li>
+<li>Click the &quot;Ø&quot; button to switch between presentation &amp;
+handout/outline modes.</li>
+</ul>
+<div class="handout container">
+In presentation mode, mouse over to the lower right-hand corner to
+display the controls.</div>
+
+</div>
+<div class="slide" id="introduction">
+<h1>Introduction</h1>
+<ul class="compact simple">
+<li>reStructuredText<p class="handout">Uses normal reStructuredText as input.</p>
+</li>
+<li>One section per slide<p class="handout">Each first-level section is converted into a single slide.</p>
+</li>
+<li>(X)HTML output<p class="handout">Presentations can be viewed using any modern graphical web browser.
+The browser must support CSS, JavaScript, and XHTML. S5 even works
+with IE!</p>
+</li>
+<li>Themes<p class="handout">A variety of themes are available.</p>
+</li>
+<li><tt class="docutils literal"><span class="pre">rst2s5.py</span></tt><p class="handout">The front-end tool to generate S5 slide shows.</p>
+</li>
+</ul>
+</div>
+<div class="slide" id="features-1">
+<h1>Features (1)</h1>
+<p class="left">A flush-left paragraph</p>
+<p class="center">A centered paragraph</p>
+<p class="right">A flush-right paragraph</p>
+<p>Some colours: <span class="black">black</span> [black], <span class="gray">gray</span>, <span class="silver">silver</span>,
+<span class="white">white</span> [white], <span class="maroon">maroon</span>, <span class="red">red</span>,
+<span class="magenta">magenta</span>, <span class="fuchsia">fuchsia</span>, <span class="pink">pink</span>,
+<span class="orange">orange</span>, <span class="yellow">yellow</span>, <span class="lime">lime</span>, <span class="green">green</span>,
+<span class="olive">olive</span>, <span class="teal">teal</span>, <span class="cyan">cyan</span>, <span class="aqua">aqua</span>,
+<span class="blue">blue</span>, <span class="navy">navy</span>, <span class="purple">purple</span></p>
+</div>
+<div class="slide" id="features-2">
+<h1>Features (2)</h1>
+<p><span class="incremental">Some</span> <span class="incremental">incremental</span> <span class="incremental">text.</span></p>
+<ul class="incremental open">
+<li><p class="first"><span class="tiny">tiny</span> (class &amp; role name: &quot;tiny&quot;, e.g. &quot;<tt class="docutils literal"><span class="pre">:tiny:`text`</span></tt>&quot;)</p>
+</li>
+<li><p class="first"><span class="small">small</span> (&quot;small&quot;)</p>
+</li>
+<li><p class="first">normal (unstyled)</p>
+</li>
+<li><p class="first"><span class="big">big</span> (&quot;big&quot;)</p>
+</li>
+<li><p class="first"><span class="huge">huge</span> (&quot;huge&quot;)</p>
+</li>
+</ul>
+</div>
+<div class="slide" id="checklist">
+<h1>Checklist</h1>
+<ul class="simple">
+<li>The document title should be duplicated on each slide in the footer
+(except for the first slide, <tt class="docutils literal"><span class="pre">slide0</span></tt>, where the entire footer is
+disabled).</li>
+<li>The footer also contains a second line, &quot;Location • Date&quot;</li>
+<li>There's no table of contents on the first slide, although it does
+appear in the handout/outline.</li>
+<li>Handout material is not displayed in presentation mode.</li>
+<li>The theme directories should be created, and the theme files copied
+over.</li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/standalone_rst_s5_html_2.html b/test/functional/expected/standalone_rst_s5_html_2.html
new file mode 100644
index 000000000..e6e474a25
--- /dev/null
+++ b/test/functional/expected/standalone_rst_s5_html_2.html
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<meta name="version" content="S5 1.1" />
+<title>Slide Shows</title>
+<meta name="author" content="David Goodger" />
+<meta name="date" content="2005-11-28" />
+<link rel="stylesheet" href="../../../docutils/writers/html4css1/html4css1.css" type="text/css" />
+<!-- configuration parameters -->
+<meta name="defaultView" content="slideshow" />
+<meta name="controlVis" content="hidden" />
+<!-- style sheet links -->
+<script src="ui/default/slides.js" type="text/javascript"></script>
+<link rel="stylesheet" href="ui/default/slides.css"
+ type="text/css" media="projection" id="slideProj" />
+<link rel="stylesheet" href="ui/default/outline.css"
+ type="text/css" media="screen" id="outlineStyle" />
+<link rel="stylesheet" href="ui/default/print.css"
+ type="text/css" media="print" id="slidePrint" />
+<link rel="stylesheet" href="ui/default/opera.css"
+ type="text/css" media="projection" id="operaFix" />
+</head>
+<body>
+<div class="layout">
+<div id="controls"></div>
+<div id="currentSlide"></div>
+<div id="header">
+
+</div>
+<div id="footer">
+<h1>Slide Shows</h1>
+<h2>Location • Date</h2>
+</div>
+</div>
+<div class="presentation">
+<div class="slide" id="slide0">
+<h1 class="title">Slide Shows</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>David Goodger</td></tr>
+<tr><th class="docinfo-name">Date:</th>
+<td>2005-11-28</td></tr>
+</tbody>
+</table>
+<!-- Definitions of interpreted text roles (classes) for S5/HTML data. -->
+<!-- This data file has been placed in the public domain. -->
+<!-- Colours
+======= -->
+<!-- Text Sizes
+========== -->
+<!-- Display in Slides (Presentation Mode) Only
+========================================== -->
+<!-- Display in Outline Mode Only
+============================ -->
+<!-- Display in Print Only
+===================== -->
+<!-- Incremental Display
+=================== -->
+<div class="contents handout topic">
+<p class="topic-title first"><a id="contents" name="contents">Contents</a></p>
+<ul class="simple">
+<li><a class="reference" href="#introduction" id="id1" name="id1">Introduction</a></li>
+<li><a class="reference" href="#features-1" id="id2" name="id2">Features (1)</a></li>
+<li><a class="reference" href="#features-2" id="id3" name="id3">Features (2)</a></li>
+<li><a class="reference" href="#checklist" id="id4" name="id4">Checklist</a></li>
+</ul>
+</div>
+<p class="handout">This is a test. This is only a test. If this were a real slide
+show, there would be a projector handy.</p>
+<p>Let's test the S5/HTML writer!</p>
+<ul class="small simple">
+<li>Use the arrow keys to navigate.</li>
+<li>Click the &quot;Ø&quot; button to switch between presentation &amp;
+handout/outline modes.</li>
+</ul>
+<div class="handout container">
+In presentation mode, mouse over to the lower right-hand corner to
+display the controls.</div>
+
+</div>
+<div class="slide" id="introduction">
+<h1>Introduction</h1>
+<ul class="compact simple">
+<li>reStructuredText<p class="handout">Uses normal reStructuredText as input.</p>
+</li>
+<li>One section per slide<p class="handout">Each first-level section is converted into a single slide.</p>
+</li>
+<li>(X)HTML output<p class="handout">Presentations can be viewed using any modern graphical web browser.
+The browser must support CSS, JavaScript, and XHTML. S5 even works
+with IE!</p>
+</li>
+<li>Themes<p class="handout">A variety of themes are available.</p>
+</li>
+<li><tt class="docutils literal"><span class="pre">rst2s5.py</span></tt><p class="handout">The front-end tool to generate S5 slide shows.</p>
+</li>
+</ul>
+</div>
+<div class="slide" id="features-1">
+<h1>Features (1)</h1>
+<p class="left">A flush-left paragraph</p>
+<p class="center">A centered paragraph</p>
+<p class="right">A flush-right paragraph</p>
+<p>Some colours: <span class="black">black</span> [black], <span class="gray">gray</span>, <span class="silver">silver</span>,
+<span class="white">white</span> [white], <span class="maroon">maroon</span>, <span class="red">red</span>,
+<span class="magenta">magenta</span>, <span class="fuchsia">fuchsia</span>, <span class="pink">pink</span>,
+<span class="orange">orange</span>, <span class="yellow">yellow</span>, <span class="lime">lime</span>, <span class="green">green</span>,
+<span class="olive">olive</span>, <span class="teal">teal</span>, <span class="cyan">cyan</span>, <span class="aqua">aqua</span>,
+<span class="blue">blue</span>, <span class="navy">navy</span>, <span class="purple">purple</span></p>
+</div>
+<div class="slide" id="features-2">
+<h1>Features (2)</h1>
+<p><span class="incremental">Some</span> <span class="incremental">incremental</span> <span class="incremental">text.</span></p>
+<ul class="incremental open">
+<li><p class="first"><span class="tiny">tiny</span> (class &amp; role name: &quot;tiny&quot;, e.g. &quot;<tt class="docutils literal"><span class="pre">:tiny:`text`</span></tt>&quot;)</p>
+</li>
+<li><p class="first"><span class="small">small</span> (&quot;small&quot;)</p>
+</li>
+<li><p class="first">normal (unstyled)</p>
+</li>
+<li><p class="first"><span class="big">big</span> (&quot;big&quot;)</p>
+</li>
+<li><p class="first"><span class="huge">huge</span> (&quot;huge&quot;)</p>
+</li>
+</ul>
+</div>
+<div class="slide" id="checklist">
+<h1>Checklist</h1>
+<ul class="simple">
+<li>The document title should be duplicated on each slide in the footer
+(except for the first slide, <tt class="docutils literal"><span class="pre">slide0</span></tt>, where the entire footer is
+disabled).</li>
+<li>The footer also contains a second line, &quot;Location • Date&quot;</li>
+<li>There's no table of contents on the first slide, although it does
+appear in the handout/outline.</li>
+<li>Handout material is not displayed in presentation mode.</li>
+<li>The theme directories should be created, and the theme files copied
+over.</li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/test/functional/expected/ui/default/blank.gif b/test/functional/expected/ui/default/blank.gif
new file mode 100644
index 000000000..75b945d25
--- /dev/null
+++ b/test/functional/expected/ui/default/blank.gif
Binary files differ
diff --git a/test/functional/expected/ui/default/framing.css b/test/functional/expected/ui/default/framing.css
new file mode 100644
index 000000000..c4727f303
--- /dev/null
+++ b/test/functional/expected/ui/default/framing.css
@@ -0,0 +1,25 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#header {position: fixed; top: 0; height: 3em; z-index: 1;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 2.5em 4% 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/test/functional/expected/ui/default/iepngfix.htc b/test/functional/expected/ui/default/iepngfix.htc
new file mode 100644
index 000000000..9f3d628b5
--- /dev/null
+++ b/test/functional/expected/ui/default/iepngfix.htc
@@ -0,0 +1,42 @@
+<public:component>
+<public:attach event="onpropertychange" onevent="doFix()" />
+
+<script>
+
+// IE5.5+ PNG Alpha Fix v1.0 by Angus Turnbull http://www.twinhelix.com
+// Free usage permitted as long as this notice remains intact.
+
+// This must be a path to a blank image. That's all the configuration you need here.
+var blankImg = 'ui/default/blank.gif';
+
+var f = 'DXImageTransform.Microsoft.AlphaImageLoader';
+
+function filt(s, m) {
+ if (filters[f]) {
+ filters[f].enabled = s ? true : false;
+ if (s) with (filters[f]) { src = s; sizingMethod = m }
+ } else if (s) style.filter = 'progid:'+f+'(src="'+s+'",sizingMethod="'+m+'")';
+}
+
+function doFix() {
+ if ((parseFloat(navigator.userAgent.match(/MSIE (\S+)/)[1]) < 5.5) ||
+ (event && !/(background|src)/.test(event.propertyName))) return;
+
+ if (tagName == 'IMG') {
+ if ((/\.png$/i).test(src)) {
+ filt(src, 'image'); // was 'scale'
+ src = blankImg;
+ } else if (src.indexOf(blankImg) < 0) filt();
+ } else if (style.backgroundImage) {
+ if (style.backgroundImage.match(/^url[("']+(.*\.png)[)"']+$/i)) {
+ var s = RegExp.$1;
+ style.backgroundImage = '';
+ filt(s, 'crop');
+ } else filt();
+ }
+}
+
+doFix();
+
+</script>
+</public:component> \ No newline at end of file
diff --git a/test/functional/expected/ui/default/opera.css b/test/functional/expected/ui/default/opera.css
new file mode 100644
index 000000000..c9d1148be
--- /dev/null
+++ b/test/functional/expected/ui/default/opera.css
@@ -0,0 +1,8 @@
+/* This file has been placed in the public domain. */
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
diff --git a/test/functional/expected/ui/default/outline.css b/test/functional/expected/ui/default/outline.css
new file mode 100644
index 000000000..fa767e227
--- /dev/null
+++ b/test/functional/expected/ui/default/outline.css
@@ -0,0 +1,16 @@
+/* This file has been placed in the public domain. */
+/* Don't change this unless you want the layout stuff to show up in the
+ outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
+
+.outline {display: inline ! important;}
diff --git a/test/functional/expected/ui/default/pretty.css b/test/functional/expected/ui/default/pretty.css
new file mode 100644
index 000000000..1cede72d4
--- /dev/null
+++ b/test/functional/expected/ui/default/pretty.css
@@ -0,0 +1,120 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: white; color: black;}
+/* Replace the background style above with the style below (and again for
+ div#header) for a graphic: */
+/* background: white url(bodybg.gif) -16px 0 no-repeat; */
+:link, :visited {text-decoration: none; color: #00C;}
+#controls :active {color: #88A !important;}
+#controls :focus {outline: 1px dotted #227;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#header, div#footer {background: #005; color: #AAB; font-family: sans-serif;}
+/* background: #005 url(bodybg.gif) -16px 0 no-repeat; */
+div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.2em;}
+.slide h1 {position: absolute; top: 0.45em; z-index: 1;
+ margin: 0; padding-left: 0.7em; white-space: nowrap;
+ font: bold 150% sans-serif; color: #DDE; background: #005;}
+.slide h2 {font: bold 120%/1em sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ background: #005; border: none; color: #779; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: #DDD; color: #227;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #449;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 {padding-top: 1.5em}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; color: #000;
+ font: bold 2em sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #77B;}
+
+.incremental, .incremental *, .incremental *:after {visibility: visible;
+ color: white; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: green;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 1em 0 0.5em 2em;}
+
+pre.literal-block, pre.doctest-block {background-color: white;}
+
+tt.docutils {background-color: white;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/test/functional/expected/ui/default/print.css b/test/functional/expected/ui/default/print.css
new file mode 100644
index 000000000..9d057cc8c
--- /dev/null
+++ b/test/functional/expected/ui/default/print.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following rule is necessary to have all slides appear in print!
+ DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray;
+ font-style: italic;}
+#footer h2, #controls {display: none;}
+
+.print {display: inline ! important;}
+
+/* The following rule keeps the layout stuff out of print.
+ Remove at your own risk! */
+.layout, .layout * {display: none !important;}
diff --git a/test/functional/expected/ui/default/s5-core.css b/test/functional/expected/ui/default/s5-core.css
new file mode 100644
index 000000000..6965f5e8f
--- /dev/null
+++ b/test/functional/expected/ui/default/s5-core.css
@@ -0,0 +1,11 @@
+/* This file has been placed in the public domain. */
+/* Do not edit or override these styles!
+ The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
diff --git a/test/functional/expected/ui/default/slides.css b/test/functional/expected/ui/default/slides.css
new file mode 100644
index 000000000..82bdc0ee0
--- /dev/null
+++ b/test/functional/expected/ui/default/slides.css
@@ -0,0 +1,10 @@
+/* This file has been placed in the public domain. */
+
+/* required to make the slide show run at all */
+@import url(s5-core.css);
+
+/* sets basic placement and size of slide components */
+@import url(framing.css);
+
+/* styles that make the slides look good */
+@import url(pretty.css);
diff --git a/test/functional/expected/ui/default/slides.js b/test/functional/expected/ui/default/slides.js
new file mode 100644
index 000000000..81e04e5d4
--- /dev/null
+++ b/test/functional/expected/ui/default/slides.js
@@ -0,0 +1,558 @@
+// S5 v1.1 slides.js -- released into the Public Domain
+// Modified for Docutils (http://docutils.sf.net) by David Goodger
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for
+// information about all the wonderful and talented contributors to this code!
+
+var undef;
+var slideCSS = '';
+var snum = 0;
+var smax = 1;
+var slideIDs = new Array();
+var incpos = 0;
+var number = undef;
+var s5mode = true;
+var defaultView = 'slideshow';
+var controlVis = 'visible';
+
+var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0;
+var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
+var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
+
+function hasClass(object, className) {
+ if (!object.className) return false;
+ return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
+}
+
+function hasValue(object, value) {
+ if (!object) return false;
+ return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
+}
+
+function removeClass(object,className) {
+ if (!object) return;
+ object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
+}
+
+function addClass(object,className) {
+ if (!object || hasClass(object, className)) return;
+ if (object.className) {
+ object.className += ' '+className;
+ } else {
+ object.className = className;
+ }
+}
+
+function GetElementsWithClassName(elementName,className) {
+ var allElements = document.getElementsByTagName(elementName);
+ var elemColl = new Array();
+ for (var i = 0; i< allElements.length; i++) {
+ if (hasClass(allElements[i], className)) {
+ elemColl[elemColl.length] = allElements[i];
+ }
+ }
+ return elemColl;
+}
+
+function isParentOrSelf(element, id) {
+ if (element == null || element.nodeName=='BODY') return false;
+ else if (element.id == id) return true;
+ else return isParentOrSelf(element.parentNode, id);
+}
+
+function nodeValue(node) {
+ var result = "";
+ if (node.nodeType == 1) {
+ var children = node.childNodes;
+ for (var i = 0; i < children.length; ++i) {
+ result += nodeValue(children[i]);
+ }
+ }
+ else if (node.nodeType == 3) {
+ result = node.nodeValue;
+ }
+ return(result);
+}
+
+function slideLabel() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var list = document.getElementById('jumplist');
+ smax = slideColl.length;
+ for (var n = 0; n < smax; n++) {
+ var obj = slideColl[n];
+
+ var did = 'slide' + n.toString();
+ if (obj.getAttribute('id')) {
+ slideIDs[n] = obj.getAttribute('id');
+ }
+ else {
+ obj.setAttribute('id',did);
+ slideIDs[n] = did;
+ }
+ if (isOp) continue;
+
+ var otext = '';
+ var menu = obj.firstChild;
+ if (!menu) continue; // to cope with empty slides
+ while (menu && menu.nodeType == 3) {
+ menu = menu.nextSibling;
+ }
+ if (!menu) continue; // to cope with slides with only text nodes
+
+ var menunodes = menu.childNodes;
+ for (var o = 0; o < menunodes.length; o++) {
+ otext += nodeValue(menunodes[o]);
+ }
+ list.options[list.length] = new Option(n + ' : ' + otext, n);
+ }
+}
+
+function currentSlide() {
+ var cs;
+ var footer_nodes;
+ var vis = 'visible';
+ if (document.getElementById) {
+ cs = document.getElementById('currentSlide');
+ footer_nodes = document.getElementById('footer').childNodes;
+ } else {
+ cs = document.currentSlide;
+ footer = document.footer.childNodes;
+ }
+ cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
+ '<span id="csSep">\/<\/span> ' +
+ '<span id="csTotal">' + (smax-1) + '<\/span>';
+ if (snum == 0) {
+ vis = 'hidden';
+ }
+ cs.style.visibility = vis;
+ for (var i = 0; i < footer_nodes.length; i++) {
+ if (footer_nodes[i].nodeType == 1) {
+ footer_nodes[i].style.visibility = vis;
+ }
+ }
+}
+
+function go(step) {
+ if (document.getElementById('slideProj').disabled || step == 0) return;
+ var jl = document.getElementById('jumplist');
+ var cid = slideIDs[snum];
+ var ce = document.getElementById(cid);
+ if (incrementals[snum].length > 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ removeClass(incrementals[snum][i], 'current');
+ removeClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (step != 'j') {
+ snum += step;
+ lmax = smax - 1;
+ if (snum > lmax) snum = lmax;
+ if (snum < 0) snum = 0;
+ } else
+ snum = parseInt(jl.value);
+ var nid = slideIDs[snum];
+ var ne = document.getElementById(nid);
+ if (!ne) {
+ ne = document.getElementById(slideIDs[0]);
+ snum = 0;
+ }
+ if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
+ if (incrementals[snum].length > 0 && incpos == 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ if (hasClass(incrementals[snum][i], 'current'))
+ incpos = i + 1;
+ else
+ addClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (incrementals[snum].length > 0 && incpos > 0)
+ addClass(incrementals[snum][incpos - 1], 'current');
+ ce.style.visibility = 'hidden';
+ ne.style.visibility = 'visible';
+ jl.selectedIndex = snum;
+ currentSlide();
+ number = 0;
+}
+
+function goTo(target) {
+ if (target >= smax || target == snum) return;
+ go(target - snum);
+}
+
+function subgo(step) {
+ if (step > 0) {
+ removeClass(incrementals[snum][incpos - 1],'current');
+ removeClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos],'current');
+ incpos++;
+ } else {
+ incpos--;
+ removeClass(incrementals[snum][incpos],'current');
+ addClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos - 1],'current');
+ }
+}
+
+function toggle() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ if (!slides.disabled) {
+ slides.disabled = true;
+ outline.disabled = false;
+ s5mode = false;
+ fontSize('1em');
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'visible';
+ }
+ } else {
+ slides.disabled = false;
+ outline.disabled = true;
+ s5mode = true;
+ fontScale();
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'hidden';
+ }
+ slideColl[snum].style.visibility = 'visible';
+ }
+}
+
+function showHide(action) {
+ var obj = GetElementsWithClassName('*','hideme')[0];
+ switch (action) {
+ case 's': obj.style.visibility = 'visible'; break;
+ case 'h': obj.style.visibility = 'hidden'; break;
+ case 'k':
+ if (obj.style.visibility != 'visible') {
+ obj.style.visibility = 'visible';
+ } else {
+ obj.style.visibility = 'hidden';
+ }
+ break;
+ }
+}
+
+// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
+function keys(key) {
+ if (!key) {
+ key = event;
+ key.which = key.keyCode;
+ }
+ if (key.which == 84) {
+ toggle();
+ return;
+ }
+ if (s5mode) {
+ switch (key.which) {
+ case 10: // return
+ case 13: // enter
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ if(number != undef) {
+ goTo(number);
+ break;
+ }
+ case 32: // spacebar
+ case 34: // page down
+ case 39: // rightkey
+ case 40: // downkey
+ if(number != undef) {
+ go(number);
+ } else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ break;
+ case 33: // page up
+ case 37: // leftkey
+ case 38: // upkey
+ if(number != undef) {
+ go(-1 * number);
+ } else if (!incrementals[snum] || incpos <= 0) {
+ go(-1);
+ } else {
+ subgo(-1);
+ }
+ break;
+ case 36: // home
+ goTo(0);
+ break;
+ case 35: // end
+ goTo(smax-1);
+ break;
+ case 67: // c
+ showHide('k');
+ break;
+ }
+ if (key.which < 48 || key.which > 57) {
+ number = undef;
+ } else {
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
+ }
+ }
+ return false;
+}
+
+function clicker(e) {
+ number = undef;
+ var target;
+ if (window.event) {
+ target = window.event.srcElement;
+ e = window.event;
+ } else target = e.target;
+ if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target, 'object')) return true;
+ if (!e.which || e.which == 1) {
+ if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ }
+}
+
+function findSlide(hash) {
+ var target = document.getElementById(hash);
+ if (target) {
+ for (var i = 0; i < slideIDs.length; i++) {
+ if (target.id == slideIDs[i]) return i;
+ }
+ }
+ return null;
+}
+
+function slideJump() {
+ if (window.location.hash == null || window.location.hash == '') {
+ currentSlide();
+ return;
+ }
+ if (window.location.hash == null) return;
+ var dest = null;
+ dest = findSlide(window.location.hash.slice(1));
+ if (dest == null) {
+ dest = 0;
+ }
+ go(dest - snum);
+}
+
+function fixLinks() {
+ var thisUri = window.location.href;
+ thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
+ var aelements = document.getElementsByTagName('A');
+ for (var i = 0; i < aelements.length; i++) {
+ var a = aelements[i].href;
+ var slideID = a.match('\#.+');
+ if ((slideID) && (slideID[0].slice(0,1) == '#')) {
+ var dest = findSlide(slideID[0].slice(1));
+ if (dest != null) {
+ if (aelements[i].addEventListener) {
+ aelements[i].addEventListener("click", new Function("e",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "if (e.preventDefault) e.preventDefault();"), true);
+ } else if (aelements[i].attachEvent) {
+ aelements[i].attachEvent("onclick", new Function("",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "event.returnValue = false;"));
+ }
+ }
+ }
+ }
+}
+
+function externalLinks() {
+ if (!document.getElementsByTagName) return;
+ var anchors = document.getElementsByTagName('a');
+ for (var i=0; i<anchors.length; i++) {
+ var anchor = anchors[i];
+ if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
+ anchor.target = '_blank';
+ addClass(anchor,'external');
+ }
+ }
+}
+
+function createControls() {
+ var controlsDiv = document.getElementById("controls");
+ if (!controlsDiv) return;
+ var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
+ var hideDiv, hideList = '';
+ if (controlVis == 'hidden') {
+ hideDiv = hider;
+ } else {
+ hideList = hider;
+ }
+ controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
+ '<div id="navLinks">' +
+ '<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>' +
+ '<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>' +
+ '<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>' +
+ '<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
+ '<\/div><\/form>';
+ if (controlVis == 'hidden') {
+ var hidden = document.getElementById('navLinks');
+ } else {
+ var hidden = document.getElementById('jumplist');
+ }
+ addClass(hidden,'hideme');
+}
+
+function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
+ if (!s5mode) return false;
+ var vScale = 22; // both yield 32 (after rounding) at 1024x768
+ var hScale = 32; // perhaps should auto-calculate based on theme's declared value?
+ if (window.innerHeight) {
+ var vSize = window.innerHeight;
+ var hSize = window.innerWidth;
+ } else if (document.documentElement.clientHeight) {
+ var vSize = document.documentElement.clientHeight;
+ var hSize = document.documentElement.clientWidth;
+ } else if (document.body.clientHeight) {
+ var vSize = document.body.clientHeight;
+ var hSize = document.body.clientWidth;
+ } else {
+ var vSize = 700; // assuming 1024x768, minus chrome and such
+ var hSize = 1024; // these do not account for kiosk mode or Opera Show
+ }
+ var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
+ fontSize(newSize + 'px');
+ if (isGe) { // hack to counter incremental reflow bugs
+ var obj = document.getElementsByTagName('body')[0];
+ obj.style.display = 'none';
+ obj.style.display = 'block';
+ }
+}
+
+function fontSize(value) {
+ if (!(s5ss = document.getElementById('s5ss'))) {
+ if (!isIE) {
+ document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
+ s5ss.setAttribute('media','screen, projection');
+ s5ss.setAttribute('id','s5ss');
+ } else {
+ document.createStyleSheet();
+ document.s5ss = document.styleSheets[document.styleSheets.length - 1];
+ }
+ }
+ if (!isIE) {
+ while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
+ s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
+ } else {
+ document.s5ss.addRule('body','font-size: ' + value + ' !important;');
+ }
+}
+
+function notOperaFix() {
+ slideCSS = document.getElementById('slideProj').href;
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ slides.setAttribute('media','screen');
+ outline.disabled = true;
+ if (isGe) {
+ slides.setAttribute('href','null'); // Gecko fix
+ slides.setAttribute('href',slideCSS); // Gecko fix
+ }
+ if (isIE && document.styleSheets && document.styleSheets[0]) {
+ document.styleSheets[0].addRule('img', 'behavior: url(ui/default/iepngfix.htc)');
+ document.styleSheets[0].addRule('div', 'behavior: url(ui/default/iepngfix.htc)');
+ document.styleSheets[0].addRule('.slide', 'behavior: url(ui/default/iepngfix.htc)');
+ }
+}
+
+function getIncrementals(obj) {
+ var incrementals = new Array();
+ if (!obj)
+ return incrementals;
+ var children = obj.childNodes;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if (hasClass(child, 'incremental')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'incremental');
+ for (var j = 0; j < child.childNodes.length; j++) {
+ if (child.childNodes[j].nodeType == 1) {
+ addClass(child.childNodes[j], 'incremental');
+ }
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ removeClass(child,'incremental');
+ }
+ }
+ if (hasClass(child, 'show-first')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'show-first');
+ if (child.childNodes[isGe].nodeType == 1) {
+ removeClass(child.childNodes[isGe], 'incremental');
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ }
+ }
+ incrementals = incrementals.concat(getIncrementals(child));
+ }
+ return incrementals;
+}
+
+function createIncrementals() {
+ var incrementals = new Array();
+ for (var i = 0; i < smax; i++) {
+ incrementals[i] = getIncrementals(document.getElementById(slideIDs[i]));
+ }
+ return incrementals;
+}
+
+function defaultCheck() {
+ var allMetas = document.getElementsByTagName('meta');
+ for (var i = 0; i< allMetas.length; i++) {
+ if (allMetas[i].name == 'defaultView') {
+ defaultView = allMetas[i].content;
+ }
+ if (allMetas[i].name == 'controlVis') {
+ controlVis = allMetas[i].content;
+ }
+ }
+}
+
+// Key trap fix, new function body for trap()
+function trap(e) {
+ if (!e) {
+ e = event;
+ e.which = e.keyCode;
+ }
+ try {
+ modifierKey = e.ctrlKey || e.altKey || e.metaKey;
+ }
+ catch(e) {
+ modifierKey = false;
+ }
+ return modifierKey || e.which == 0;
+}
+
+function startup() {
+ defaultCheck();
+ if (!isOp) createControls();
+ slideLabel();
+ fixLinks();
+ externalLinks();
+ fontScale();
+ if (!isOp) {
+ notOperaFix();
+ incrementals = createIncrementals();
+ slideJump();
+ if (defaultView == 'outline') {
+ toggle();
+ }
+ document.onkeyup = keys;
+ document.onkeypress = trap;
+ document.onclick = clicker;
+ }
+}
+
+window.onload = startup;
+window.onresize = function(){setTimeout('fontScale()', 50);}
diff --git a/test/functional/expected/ui/small-black/blank.gif b/test/functional/expected/ui/small-black/blank.gif
new file mode 100644
index 000000000..75b945d25
--- /dev/null
+++ b/test/functional/expected/ui/small-black/blank.gif
Binary files differ
diff --git a/test/functional/expected/ui/small-black/framing.css b/test/functional/expected/ui/small-black/framing.css
new file mode 100644
index 000000000..70287dd06
--- /dev/null
+++ b/test/functional/expected/ui/small-black/framing.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following styles size, place, and layer the slide components.
+ Edit these if you want to change the overall slide layout.
+ The commented lines can be uncommented (and modified, if necessary)
+ to help you with the rearrangement process. */
+
+/* target = 1024x768 */
+
+div#header, div#footer, .slide {width: 100%; top: 0; left: 0;}
+div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;}
+.slide {top: 0; width: 92%; padding: 1em 4% 0 4%; z-index: 2;}
+div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0;}
+#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em;
+ z-index: 10;}
+html>body #currentSlide {position: fixed;}
+
+/*
+div#header {background: #FCC;}
+div#footer {background: #CCF;}
+div#controls {background: #BBD;}
+div#currentSlide {background: #FFC;}
+*/
diff --git a/test/functional/expected/ui/small-black/iepngfix.htc b/test/functional/expected/ui/small-black/iepngfix.htc
new file mode 100644
index 000000000..fa9f99659
--- /dev/null
+++ b/test/functional/expected/ui/small-black/iepngfix.htc
@@ -0,0 +1,42 @@
+<public:component>
+<public:attach event="onpropertychange" onevent="doFix()" />
+
+<script>
+
+// IE5.5+ PNG Alpha Fix v1.0 by Angus Turnbull http://www.twinhelix.com
+// Free usage permitted as long as this notice remains intact.
+
+// This must be a path to a blank image. That's all the configuration you need here.
+var blankImg = 'ui/small-black/blank.gif';
+
+var f = 'DXImageTransform.Microsoft.AlphaImageLoader';
+
+function filt(s, m) {
+ if (filters[f]) {
+ filters[f].enabled = s ? true : false;
+ if (s) with (filters[f]) { src = s; sizingMethod = m }
+ } else if (s) style.filter = 'progid:'+f+'(src="'+s+'",sizingMethod="'+m+'")';
+}
+
+function doFix() {
+ if ((parseFloat(navigator.userAgent.match(/MSIE (\S+)/)[1]) < 5.5) ||
+ (event && !/(background|src)/.test(event.propertyName))) return;
+
+ if (tagName == 'IMG') {
+ if ((/\.png$/i).test(src)) {
+ filt(src, 'image'); // was 'scale'
+ src = blankImg;
+ } else if (src.indexOf(blankImg) < 0) filt();
+ } else if (style.backgroundImage) {
+ if (style.backgroundImage.match(/^url[("']+(.*\.png)[)"']+$/i)) {
+ var s = RegExp.$1;
+ style.backgroundImage = '';
+ filt(s, 'crop');
+ } else filt();
+ }
+}
+
+doFix();
+
+</script>
+</public:component> \ No newline at end of file
diff --git a/test/functional/expected/ui/small-black/opera.css b/test/functional/expected/ui/small-black/opera.css
new file mode 100644
index 000000000..c9d1148be
--- /dev/null
+++ b/test/functional/expected/ui/small-black/opera.css
@@ -0,0 +1,8 @@
+/* This file has been placed in the public domain. */
+/* DO NOT CHANGE THESE unless you really want to break Opera Show */
+.slide {
+ visibility: visible !important;
+ position: static !important;
+ page-break-before: always;
+}
+#slide0 {page-break-before: avoid;}
diff --git a/test/functional/expected/ui/small-black/outline.css b/test/functional/expected/ui/small-black/outline.css
new file mode 100644
index 000000000..fa767e227
--- /dev/null
+++ b/test/functional/expected/ui/small-black/outline.css
@@ -0,0 +1,16 @@
+/* This file has been placed in the public domain. */
+/* Don't change this unless you want the layout stuff to show up in the
+ outline view! */
+
+.layout div, #footer *, #controlForm * {display: none;}
+#footer, #controls, #controlForm, #navLinks, #toggle {
+ display: block; visibility: visible; margin: 0; padding: 0;}
+#toggle {float: right; padding: 0.5em;}
+html>body #toggle {position: fixed; top: 0; right: 0;}
+
+/* making the outline look pretty-ish */
+
+#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;}
+#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;}
+
+.outline {display: inline ! important;}
diff --git a/test/functional/expected/ui/small-black/pretty.css b/test/functional/expected/ui/small-black/pretty.css
new file mode 100644
index 000000000..5c1932704
--- /dev/null
+++ b/test/functional/expected/ui/small-black/pretty.css
@@ -0,0 +1,116 @@
+/* This file has been placed in the public domain. */
+/* Following are the presentation styles -- edit away! */
+
+html, body {margin: 0; padding: 0;}
+body {background: black; color: white;}
+:link, :visited {text-decoration: none; color: cyan;}
+#controls :active {color: #888 !important;}
+#controls :focus {outline: 1px dotted #CCC;}
+h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;}
+
+blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;}
+blockquote p {margin: 0;}
+
+kbd {font-weight: bold; font-size: 1em;}
+sup {font-size: smaller; line-height: 1px;}
+
+.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;}
+.slide ul ul li {list-style: square;}
+.slide img.leader {display: block; margin: 0 auto;}
+.slide tt {font-size: 90%;}
+
+div#footer {font-family: sans-serif; color: #AAA;
+ font-size: 0.5em; font-weight: bold; padding: 1em 0;}
+#footer h1 {display: block; padding: 0 1em;}
+#footer h2 {display: block; padding: 0.8em 1em 0;}
+
+.slide {font-size: 1.2em;}
+.slide h1 {padding-top: 0; z-index: 1; margin: 0; font: bold 150% sans-serif;}
+.slide h2 {font: bold 120% sans-serif; padding-top: 0.5em;}
+.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;}
+h1 abbr {font-variant: small-caps;}
+
+div#controls {position: absolute; left: 50%; bottom: 0;
+ width: 50%; text-align: right; font: bold 0.9em sans-serif;}
+html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;}
+div#controls form {position: absolute; bottom: 0; right: 0; width: 100%;
+ margin: 0; padding: 0;}
+#controls #navLinks a {padding: 0; margin: 0 0.5em;
+ border: none; color: #888; cursor: pointer;}
+#controls #navList {height: 1em;}
+#controls #navList #jumplist {position: absolute; bottom: 0; right: 0;
+ background: black; color: #CCC;}
+
+#currentSlide {text-align: center; font-size: 0.5em; color: #AAA;
+ font-family: sans-serif; font-weight: bold;}
+
+#slide0 {padding-top: 0em}
+#slide0 h1 {position: static; margin: 1em 0 0; padding: 0;
+ font: bold 2em sans-serif; white-space: normal; background: transparent;}
+#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;}
+#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;}
+#slide0 h4 {margin-top: 0; font-size: 1em;}
+
+ul.urls {list-style: none; display: inline; margin: 0;}
+.urls li {display: inline; margin: 0;}
+.external {border-bottom: 1px dotted gray;}
+html>body .external {border-bottom: none;}
+.external:after {content: " \274F"; font-size: smaller; color: #FCC;}
+
+.incremental, .incremental *, .incremental *:after {
+ color: black; visibility: visible; border: 0;}
+img.incremental {visibility: hidden;}
+.slide .current {color: lime;}
+
+.slide-display {display: inline ! important;}
+
+.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;}
+.big {font-family: sans-serif; font-weight: bold; font-size: 120%;}
+.small {font-size: 75%;}
+.tiny {font-size: 50%;}
+.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;}
+.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;}
+
+.maroon {color: maroon;}
+.red {color: red;}
+.magenta {color: magenta;}
+.fuchsia {color: fuchsia;}
+.pink {color: #FAA;}
+.orange {color: orange;}
+.yellow {color: yellow;}
+.lime {color: lime;}
+.green {color: green;}
+.olive {color: olive;}
+.teal {color: teal;}
+.cyan {color: cyan;}
+.aqua {color: aqua;}
+.blue {color: blue;}
+.navy {color: navy;}
+.purple {color: purple;}
+.black {color: black;}
+.gray {color: gray;}
+.silver {color: silver;}
+.white {color: white;}
+
+.left {text-align: left ! important;}
+.center {text-align: center ! important;}
+.right {text-align: right ! important;}
+
+.animation {position: relative; margin: 1em 0; padding: 0;}
+.animation img {position: absolute;}
+
+/* Docutils-specific overrides */
+
+.slide table.docinfo {margin: 1em 0 0.5em 2em;}
+
+div.sidebar {background-color: black;}
+
+pre.literal-block, pre.doctest-block {background-color: black;}
+
+tt.docutils {background-color: black;}
+
+/* diagnostics */
+/*
+li:after {content: " [" attr(class) "]"; color: #F88;}
+div:before {content: "[" attr(class) "]"; color: #F88;}
+*/
diff --git a/test/functional/expected/ui/small-black/print.css b/test/functional/expected/ui/small-black/print.css
new file mode 100644
index 000000000..9d057cc8c
--- /dev/null
+++ b/test/functional/expected/ui/small-black/print.css
@@ -0,0 +1,24 @@
+/* This file has been placed in the public domain. */
+/* The following rule is necessary to have all slides appear in print!
+ DO NOT REMOVE IT! */
+.slide, ul {page-break-inside: avoid; visibility: visible !important;}
+h1 {page-break-after: avoid;}
+
+body {font-size: 12pt; background: white;}
+* {color: black;}
+
+#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
+#slide0 h3 {margin: 0; padding: 0;}
+#slide0 h4 {margin: 0 0 0.5em; padding: 0;}
+#slide0 {margin-bottom: 3em;}
+
+#header {display: none;}
+#footer h1 {margin: 0; border-bottom: 1px solid; color: gray;
+ font-style: italic;}
+#footer h2, #controls {display: none;}
+
+.print {display: inline ! important;}
+
+/* The following rule keeps the layout stuff out of print.
+ Remove at your own risk! */
+.layout, .layout * {display: none !important;}
diff --git a/test/functional/expected/ui/small-black/s5-core.css b/test/functional/expected/ui/small-black/s5-core.css
new file mode 100644
index 000000000..6965f5e8f
--- /dev/null
+++ b/test/functional/expected/ui/small-black/s5-core.css
@@ -0,0 +1,11 @@
+/* This file has been placed in the public domain. */
+/* Do not edit or override these styles!
+ The system will likely break if you do. */
+
+div#header, div#footer, div#controls, .slide {position: absolute;}
+html>body div#header, html>body div#footer,
+ html>body div#controls, html>body .slide {position: fixed;}
+.handout {display: none;}
+.layout {display: block;}
+.slide, .hideme, .incremental {visibility: hidden;}
+#slide0 {visibility: visible;}
diff --git a/test/functional/expected/ui/small-black/slides.css b/test/functional/expected/ui/small-black/slides.css
new file mode 100644
index 000000000..82bdc0ee0
--- /dev/null
+++ b/test/functional/expected/ui/small-black/slides.css
@@ -0,0 +1,10 @@
+/* This file has been placed in the public domain. */
+
+/* required to make the slide show run at all */
+@import url(s5-core.css);
+
+/* sets basic placement and size of slide components */
+@import url(framing.css);
+
+/* styles that make the slides look good */
+@import url(pretty.css);
diff --git a/test/functional/expected/ui/small-black/slides.js b/test/functional/expected/ui/small-black/slides.js
new file mode 100644
index 000000000..d628dfeaf
--- /dev/null
+++ b/test/functional/expected/ui/small-black/slides.js
@@ -0,0 +1,558 @@
+// S5 v1.1 slides.js -- released into the Public Domain
+// Modified for Docutils (http://docutils.sf.net) by David Goodger
+//
+// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for
+// information about all the wonderful and talented contributors to this code!
+
+var undef;
+var slideCSS = '';
+var snum = 0;
+var smax = 1;
+var slideIDs = new Array();
+var incpos = 0;
+var number = undef;
+var s5mode = true;
+var defaultView = 'slideshow';
+var controlVis = 'visible';
+
+var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0;
+var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0;
+var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0;
+
+function hasClass(object, className) {
+ if (!object.className) return false;
+ return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1);
+}
+
+function hasValue(object, value) {
+ if (!object) return false;
+ return (object.search('(^|\\s)' + value + '(\\s|$)') != -1);
+}
+
+function removeClass(object,className) {
+ if (!object) return;
+ object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2);
+}
+
+function addClass(object,className) {
+ if (!object || hasClass(object, className)) return;
+ if (object.className) {
+ object.className += ' '+className;
+ } else {
+ object.className = className;
+ }
+}
+
+function GetElementsWithClassName(elementName,className) {
+ var allElements = document.getElementsByTagName(elementName);
+ var elemColl = new Array();
+ for (var i = 0; i< allElements.length; i++) {
+ if (hasClass(allElements[i], className)) {
+ elemColl[elemColl.length] = allElements[i];
+ }
+ }
+ return elemColl;
+}
+
+function isParentOrSelf(element, id) {
+ if (element == null || element.nodeName=='BODY') return false;
+ else if (element.id == id) return true;
+ else return isParentOrSelf(element.parentNode, id);
+}
+
+function nodeValue(node) {
+ var result = "";
+ if (node.nodeType == 1) {
+ var children = node.childNodes;
+ for (var i = 0; i < children.length; ++i) {
+ result += nodeValue(children[i]);
+ }
+ }
+ else if (node.nodeType == 3) {
+ result = node.nodeValue;
+ }
+ return(result);
+}
+
+function slideLabel() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var list = document.getElementById('jumplist');
+ smax = slideColl.length;
+ for (var n = 0; n < smax; n++) {
+ var obj = slideColl[n];
+
+ var did = 'slide' + n.toString();
+ if (obj.getAttribute('id')) {
+ slideIDs[n] = obj.getAttribute('id');
+ }
+ else {
+ obj.setAttribute('id',did);
+ slideIDs[n] = did;
+ }
+ if (isOp) continue;
+
+ var otext = '';
+ var menu = obj.firstChild;
+ if (!menu) continue; // to cope with empty slides
+ while (menu && menu.nodeType == 3) {
+ menu = menu.nextSibling;
+ }
+ if (!menu) continue; // to cope with slides with only text nodes
+
+ var menunodes = menu.childNodes;
+ for (var o = 0; o < menunodes.length; o++) {
+ otext += nodeValue(menunodes[o]);
+ }
+ list.options[list.length] = new Option(n + ' : ' + otext, n);
+ }
+}
+
+function currentSlide() {
+ var cs;
+ var footer_nodes;
+ var vis = 'visible';
+ if (document.getElementById) {
+ cs = document.getElementById('currentSlide');
+ footer_nodes = document.getElementById('footer').childNodes;
+ } else {
+ cs = document.currentSlide;
+ footer = document.footer.childNodes;
+ }
+ cs.innerHTML = '<span id="csHere">' + snum + '<\/span> ' +
+ '<span id="csSep">\/<\/span> ' +
+ '<span id="csTotal">' + (smax-1) + '<\/span>';
+ if (snum == 0) {
+ vis = 'hidden';
+ }
+ cs.style.visibility = vis;
+ for (var i = 0; i < footer_nodes.length; i++) {
+ if (footer_nodes[i].nodeType == 1) {
+ footer_nodes[i].style.visibility = vis;
+ }
+ }
+}
+
+function go(step) {
+ if (document.getElementById('slideProj').disabled || step == 0) return;
+ var jl = document.getElementById('jumplist');
+ var cid = slideIDs[snum];
+ var ce = document.getElementById(cid);
+ if (incrementals[snum].length > 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ removeClass(incrementals[snum][i], 'current');
+ removeClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (step != 'j') {
+ snum += step;
+ lmax = smax - 1;
+ if (snum > lmax) snum = lmax;
+ if (snum < 0) snum = 0;
+ } else
+ snum = parseInt(jl.value);
+ var nid = slideIDs[snum];
+ var ne = document.getElementById(nid);
+ if (!ne) {
+ ne = document.getElementById(slideIDs[0]);
+ snum = 0;
+ }
+ if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;}
+ if (incrementals[snum].length > 0 && incpos == 0) {
+ for (var i = 0; i < incrementals[snum].length; i++) {
+ if (hasClass(incrementals[snum][i], 'current'))
+ incpos = i + 1;
+ else
+ addClass(incrementals[snum][i], 'incremental');
+ }
+ }
+ if (incrementals[snum].length > 0 && incpos > 0)
+ addClass(incrementals[snum][incpos - 1], 'current');
+ ce.style.visibility = 'hidden';
+ ne.style.visibility = 'visible';
+ jl.selectedIndex = snum;
+ currentSlide();
+ number = 0;
+}
+
+function goTo(target) {
+ if (target >= smax || target == snum) return;
+ go(target - snum);
+}
+
+function subgo(step) {
+ if (step > 0) {
+ removeClass(incrementals[snum][incpos - 1],'current');
+ removeClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos],'current');
+ incpos++;
+ } else {
+ incpos--;
+ removeClass(incrementals[snum][incpos],'current');
+ addClass(incrementals[snum][incpos], 'incremental');
+ addClass(incrementals[snum][incpos - 1],'current');
+ }
+}
+
+function toggle() {
+ var slideColl = GetElementsWithClassName('*','slide');
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ if (!slides.disabled) {
+ slides.disabled = true;
+ outline.disabled = false;
+ s5mode = false;
+ fontSize('1em');
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'visible';
+ }
+ } else {
+ slides.disabled = false;
+ outline.disabled = true;
+ s5mode = true;
+ fontScale();
+ for (var n = 0; n < smax; n++) {
+ var slide = slideColl[n];
+ slide.style.visibility = 'hidden';
+ }
+ slideColl[snum].style.visibility = 'visible';
+ }
+}
+
+function showHide(action) {
+ var obj = GetElementsWithClassName('*','hideme')[0];
+ switch (action) {
+ case 's': obj.style.visibility = 'visible'; break;
+ case 'h': obj.style.visibility = 'hidden'; break;
+ case 'k':
+ if (obj.style.visibility != 'visible') {
+ obj.style.visibility = 'visible';
+ } else {
+ obj.style.visibility = 'hidden';
+ }
+ break;
+ }
+}
+
+// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/)
+function keys(key) {
+ if (!key) {
+ key = event;
+ key.which = key.keyCode;
+ }
+ if (key.which == 84) {
+ toggle();
+ return;
+ }
+ if (s5mode) {
+ switch (key.which) {
+ case 10: // return
+ case 13: // enter
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ if(number != undef) {
+ goTo(number);
+ break;
+ }
+ case 32: // spacebar
+ case 34: // page down
+ case 39: // rightkey
+ case 40: // downkey
+ if(number != undef) {
+ go(number);
+ } else if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ break;
+ case 33: // page up
+ case 37: // leftkey
+ case 38: // upkey
+ if(number != undef) {
+ go(-1 * number);
+ } else if (!incrementals[snum] || incpos <= 0) {
+ go(-1);
+ } else {
+ subgo(-1);
+ }
+ break;
+ case 36: // home
+ goTo(0);
+ break;
+ case 35: // end
+ goTo(smax-1);
+ break;
+ case 67: // c
+ showHide('k');
+ break;
+ }
+ if (key.which < 48 || key.which > 57) {
+ number = undef;
+ } else {
+ if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return;
+ if (key.target && isParentOrSelf(key.target, 'controls')) return;
+ number = (((number != undef) ? number : 0) * 10) + (key.which - 48);
+ }
+ }
+ return false;
+}
+
+function clicker(e) {
+ number = undef;
+ var target;
+ if (window.event) {
+ target = window.event.srcElement;
+ e = window.event;
+ } else target = e.target;
+ if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target, 'object')) return true;
+ if (!e.which || e.which == 1) {
+ if (!incrementals[snum] || incpos >= incrementals[snum].length) {
+ go(1);
+ } else {
+ subgo(1);
+ }
+ }
+}
+
+function findSlide(hash) {
+ var target = document.getElementById(hash);
+ if (target) {
+ for (var i = 0; i < slideIDs.length; i++) {
+ if (target.id == slideIDs[i]) return i;
+ }
+ }
+ return null;
+}
+
+function slideJump() {
+ if (window.location.hash == null || window.location.hash == '') {
+ currentSlide();
+ return;
+ }
+ if (window.location.hash == null) return;
+ var dest = null;
+ dest = findSlide(window.location.hash.slice(1));
+ if (dest == null) {
+ dest = 0;
+ }
+ go(dest - snum);
+}
+
+function fixLinks() {
+ var thisUri = window.location.href;
+ thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length);
+ var aelements = document.getElementsByTagName('A');
+ for (var i = 0; i < aelements.length; i++) {
+ var a = aelements[i].href;
+ var slideID = a.match('\#.+');
+ if ((slideID) && (slideID[0].slice(0,1) == '#')) {
+ var dest = findSlide(slideID[0].slice(1));
+ if (dest != null) {
+ if (aelements[i].addEventListener) {
+ aelements[i].addEventListener("click", new Function("e",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "if (e.preventDefault) e.preventDefault();"), true);
+ } else if (aelements[i].attachEvent) {
+ aelements[i].attachEvent("onclick", new Function("",
+ "if (document.getElementById('slideProj').disabled) return;" +
+ "go("+dest+" - snum); " +
+ "event.returnValue = false;"));
+ }
+ }
+ }
+ }
+}
+
+function externalLinks() {
+ if (!document.getElementsByTagName) return;
+ var anchors = document.getElementsByTagName('a');
+ for (var i=0; i<anchors.length; i++) {
+ var anchor = anchors[i];
+ if (anchor.getAttribute('href') && hasValue(anchor.rel, 'external')) {
+ anchor.target = '_blank';
+ addClass(anchor,'external');
+ }
+ }
+}
+
+function createControls() {
+ var controlsDiv = document.getElementById("controls");
+ if (!controlsDiv) return;
+ var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"';
+ var hideDiv, hideList = '';
+ if (controlVis == 'hidden') {
+ hideDiv = hider;
+ } else {
+ hideList = hider;
+ }
+ controlsDiv.innerHTML = '<form action="#" id="controlForm"' + hideDiv + '>' +
+ '<div id="navLinks">' +
+ '<a accesskey="t" id="toggle" href="javascript:toggle();">&#216;<\/a>' +
+ '<a accesskey="z" id="prev" href="javascript:go(-1);">&laquo;<\/a>' +
+ '<a accesskey="x" id="next" href="javascript:go(1);">&raquo;<\/a>' +
+ '<div id="navList"' + hideList + '><select id="jumplist" onchange="go(\'j\');"><\/select><\/div>' +
+ '<\/div><\/form>';
+ if (controlVis == 'hidden') {
+ var hidden = document.getElementById('navLinks');
+ } else {
+ var hidden = document.getElementById('jumplist');
+ }
+ addClass(hidden,'hideme');
+}
+
+function fontScale() { // causes layout problems in FireFox that get fixed if browser's Reload is used; same may be true of other Gecko-based browsers
+ if (!s5mode) return false;
+ var vScale = 22; // both yield 32 (after rounding) at 1024x768
+ var hScale = 32; // perhaps should auto-calculate based on theme's declared value?
+ if (window.innerHeight) {
+ var vSize = window.innerHeight;
+ var hSize = window.innerWidth;
+ } else if (document.documentElement.clientHeight) {
+ var vSize = document.documentElement.clientHeight;
+ var hSize = document.documentElement.clientWidth;
+ } else if (document.body.clientHeight) {
+ var vSize = document.body.clientHeight;
+ var hSize = document.body.clientWidth;
+ } else {
+ var vSize = 700; // assuming 1024x768, minus chrome and such
+ var hSize = 1024; // these do not account for kiosk mode or Opera Show
+ }
+ var newSize = Math.min(Math.round(vSize/vScale),Math.round(hSize/hScale));
+ fontSize(newSize + 'px');
+ if (isGe) { // hack to counter incremental reflow bugs
+ var obj = document.getElementsByTagName('body')[0];
+ obj.style.display = 'none';
+ obj.style.display = 'block';
+ }
+}
+
+function fontSize(value) {
+ if (!(s5ss = document.getElementById('s5ss'))) {
+ if (!isIE) {
+ document.getElementsByTagName('head')[0].appendChild(s5ss = document.createElement('style'));
+ s5ss.setAttribute('media','screen, projection');
+ s5ss.setAttribute('id','s5ss');
+ } else {
+ document.createStyleSheet();
+ document.s5ss = document.styleSheets[document.styleSheets.length - 1];
+ }
+ }
+ if (!isIE) {
+ while (s5ss.lastChild) s5ss.removeChild(s5ss.lastChild);
+ s5ss.appendChild(document.createTextNode('body {font-size: ' + value + ' !important;}'));
+ } else {
+ document.s5ss.addRule('body','font-size: ' + value + ' !important;');
+ }
+}
+
+function notOperaFix() {
+ slideCSS = document.getElementById('slideProj').href;
+ var slides = document.getElementById('slideProj');
+ var outline = document.getElementById('outlineStyle');
+ slides.setAttribute('media','screen');
+ outline.disabled = true;
+ if (isGe) {
+ slides.setAttribute('href','null'); // Gecko fix
+ slides.setAttribute('href',slideCSS); // Gecko fix
+ }
+ if (isIE && document.styleSheets && document.styleSheets[0]) {
+ document.styleSheets[0].addRule('img', 'behavior: url(ui/small-black/iepngfix.htc)');
+ document.styleSheets[0].addRule('div', 'behavior: url(ui/small-black/iepngfix.htc)');
+ document.styleSheets[0].addRule('.slide', 'behavior: url(ui/small-black/iepngfix.htc)');
+ }
+}
+
+function getIncrementals(obj) {
+ var incrementals = new Array();
+ if (!obj)
+ return incrementals;
+ var children = obj.childNodes;
+ for (var i = 0; i < children.length; i++) {
+ var child = children[i];
+ if (hasClass(child, 'incremental')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'incremental');
+ for (var j = 0; j < child.childNodes.length; j++) {
+ if (child.childNodes[j].nodeType == 1) {
+ addClass(child.childNodes[j], 'incremental');
+ }
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ removeClass(child,'incremental');
+ }
+ }
+ if (hasClass(child, 'show-first')) {
+ if (child.nodeName == 'OL' || child.nodeName == 'UL') {
+ removeClass(child, 'show-first');
+ if (child.childNodes[isGe].nodeType == 1) {
+ removeClass(child.childNodes[isGe], 'incremental');
+ }
+ } else {
+ incrementals[incrementals.length] = child;
+ }
+ }
+ incrementals = incrementals.concat(getIncrementals(child));
+ }
+ return incrementals;
+}
+
+function createIncrementals() {
+ var incrementals = new Array();
+ for (var i = 0; i < smax; i++) {
+ incrementals[i] = getIncrementals(document.getElementById(slideIDs[i]));
+ }
+ return incrementals;
+}
+
+function defaultCheck() {
+ var allMetas = document.getElementsByTagName('meta');
+ for (var i = 0; i< allMetas.length; i++) {
+ if (allMetas[i].name == 'defaultView') {
+ defaultView = allMetas[i].content;
+ }
+ if (allMetas[i].name == 'controlVis') {
+ controlVis = allMetas[i].content;
+ }
+ }
+}
+
+// Key trap fix, new function body for trap()
+function trap(e) {
+ if (!e) {
+ e = event;
+ e.which = e.keyCode;
+ }
+ try {
+ modifierKey = e.ctrlKey || e.altKey || e.metaKey;
+ }
+ catch(e) {
+ modifierKey = false;
+ }
+ return modifierKey || e.which == 0;
+}
+
+function startup() {
+ defaultCheck();
+ if (!isOp) createControls();
+ slideLabel();
+ fixLinks();
+ externalLinks();
+ fontScale();
+ if (!isOp) {
+ notOperaFix();
+ incrementals = createIncrementals();
+ slideJump();
+ if (defaultView == 'outline') {
+ toggle();
+ }
+ document.onkeyup = keys;
+ document.onkeypress = trap;
+ document.onclick = clicker;
+ }
+}
+
+window.onload = startup;
+window.onresize = function(){setTimeout('fontScale()', 50);}
diff --git a/test/functional/input/compact_lists.txt b/test/functional/input/compact_lists.txt
new file mode 100644
index 000000000..ec13a97be
--- /dev/null
+++ b/test/functional/input/compact_lists.txt
@@ -0,0 +1,39 @@
+* This is an ordinary simple bullet list.
+* It should be made compact (<p> & </p> tags omitted).
+
+**********
+
+* This is a bullet list that is not simple.
+
+ There are multiple paragraphs in some items.
+
+* It should not be made compact.
+
+* Even though some items may have only one paragraph.
+
+**********
+
+.. class:: open
+
+* This is a simple bullet list, but class="open" is set.
+* It should not be made compact.
+
+**********
+
+.. class:: compact
+
+* This is a bullet list that is not simple.
+
+ There are multiple paragraphs in some items.
+
+* However, the class="compact" setting will cause
+ all first paragraph's <p> & </p> tags to be omitted.
+
+* Items with multiple paragraphs will not appear changed.
+
+* Items may have one paragraph, or multiple.
+
+ Items with multiple paragraphs will still be followed
+ by vertical whitespace because of the later paragraphs.
+
+* The effect is interesting.
diff --git a/test/functional/input/dangerous.txt b/test/functional/input/dangerous.txt
new file mode 100644
index 000000000..8f75386c8
--- /dev/null
+++ b/test/functional/input/dangerous.txt
@@ -0,0 +1,16 @@
+Potentially dangerous features (security holes):
+
+.. include:: /etc/passwd
+.. raw:: html
+ :file: /etc/passwd
+.. raw:: html
+ :url: file:///etc/passwd
+.. raw:: html
+
+ <script>
+ that does something really nasty
+ </script>
+.. csv-table:: :file: /etc/passwd
+.. csv-table:: :url: file:///etc/passwd
+.. figure:: picture.png
+ :figwidth: image
diff --git a/test/functional/input/data/custom_roles.txt b/test/functional/input/data/custom_roles.txt
new file mode 100644
index 000000000..0f209d61e
--- /dev/null
+++ b/test/functional/input/data/custom_roles.txt
@@ -0,0 +1,6 @@
+Custom Roles
+------------
+
+.. role:: custom(literal)
+
+:custom:`one` :custom:`two` :custom:`three`
diff --git a/test/functional/input/data/errors.txt b/test/functional/input/data/errors.txt
new file mode 100644
index 000000000..557f479d3
--- /dev/null
+++ b/test/functional/input/data/errors.txt
@@ -0,0 +1,9 @@
+Error Handling
+==============
+
+Any errors caught during processing will generate system messages.
+
+There should be five messages in the following, auto-generated
+section, "Docutils System Messages":
+
+.. section should be added by Docutils automatically
diff --git a/test/functional/input/data/header_footer.txt b/test/functional/input/data/header_footer.txt
new file mode 100644
index 000000000..875c9fac0
--- /dev/null
+++ b/test/functional/input/data/header_footer.txt
@@ -0,0 +1,2 @@
+.. header:: Document header
+.. footer:: Document footer
diff --git a/test/functional/input/data/latex.txt b/test/functional/input/data/latex.txt
new file mode 100644
index 000000000..20d59db1e
--- /dev/null
+++ b/test/functional/input/data/latex.txt
@@ -0,0 +1,201 @@
+Some Tests for the LaTeX Writer
+===============================
+
+These tests have been written to exercise some unusual combinations of
+syntax elements which may cause trouble for the LaTeX writer but do
+not need to be tested with other writers (e.g. the HTML writer).
+
+This file is not yet used by any automated test. It is currently only
+used to control the visual appearance of the output.
+
+
+Block Quotes
+------------
+
+ This block quote comes directly after the section heading and is
+ followed by a paragraph.
+
+ This is the second paragraph of the block quote and it contains
+ some more text filling up some space which would otherwise be
+ empty.
+
+ -- Attribution
+
+This is a paragraph.
+
+ This block quote does not have an attribution.
+
+This is another paragraph.
+
+ Another block quote at the end of the section.
+
+
+More Block Quotes
+-----------------
+
+ Block quote followed by a transition.
+
+----------
+
+ Another block quote.
+
+
+Sidebars
+--------
+
+This paragraph precedes the sidebar. This is some text. This is some
+text. This is some text. This is some text. This is some text.
+This is some text. This is some text. This is some text.
+
+.. sidebar:: Sidebar Title
+
+ These are the sidebar contents. These are the sidebar contents.
+
+ These are the sidebar contents. These are the sidebar contents.
+
+ These are the sidebar contents. These are the sidebar contents.
+ These are the sidebar contents. These are the sidebar contents.
+
+This paragraph follows the sidebar. This is some text. This is some
+text. This is some text.
+
+This is some text. This is some text. This is some text. This is
+some text. This is some text. This is some text. This is some text.
+
+
+Next Section
+------------
+
+This section comes after the sidebar, and this text should float
+around the sidebar as well. This is some text. This is some text.
+This is some text. This is some text. This is some text. This is
+some text. This is some text. This is some text. This is some text.
+This is some text. This is some text. This is some text. This is
+some text. This is some text.
+
+This is some text. This is some text. This is some text. This is
+some text. This is some text. This is some text. This is some text.
+This is some text. This is some text. This is some text.
+
+
+Nested Elements
+---------------
+
+:Field list: | Line
+ | Block
+:Field 2: * Bullet
+ * list
+:Another (longer) field: * Bullet
+ * list
+:Yet another long field:
+ * .. comment
+
+ Bullet
+
+ .. comment
+
+ * .. comment
+
+ list
+
+ .. comment
+
+:Field: * This
+
+ is
+
+ a
+
+ * bullet
+
+ list
+
+:Field: * | This is
+ | a bullet
+ * | list with
+ | line blocks
+:Last field: Last field.
+
+* * * * * * * * Deeply nested list.
+
+1. 2. 3. 4. 5. 6. 7. 8. Deeply nested list.
+
++-----------------+
+| | Line block |
+| |
+| * Bullet list |
+| |
+| :: |
+| |
+| Literal |
+| block |
++-----------------+
+| :Field 1: |
+| Text. |
+| :Field 2: |
+| More text. |
++-----------------+
+| +-------+-----+ |
+| | A |* foo| |
+| | nested| | |
+| | table.|* bar| |
+| +-------+-----+ |
++-----------------+
+| This is a |
+| paragraph. |
+| |
+| +-------+-----+ |
+| | A |* foo| |
+| | nested| | |
+| | table.|* bar| |
+| +-------+-----+ |
+| |
+| Another longer |
+| paragraph. |
++-----------------+
+| * A list. |
+| * A list. |
+| |
+| +-------+-----+ |
+| | A |* foo| |
+| | nested| | |
+| | table.|* bar| |
+| +-------+-----+ |
+| |
+| * Another list. |
+| * Another list. |
++-----------------+
+| Foo |
+| |
+| Bar |
++-----------------+
+| * Foo |
+| |
+| * Bar |
++-----------------+
+| * This is a |
+| paragraph. |
+| |
+| This is a |
+| paragraph. |
+| |
+| * This is a |
+| paragraph. |
+| |
+| This is a |
+| paragraph. |
++-----------------+
+
+
+Images
+======
+
+Image with 20% width:
+
+.. image:: ../../../docs/user/rst/images/title.png
+ :width: 20%
+
+Image with 100% width:
+
+.. image:: ../../../docs/user/rst/images/title.png
+ :width: 100%
diff --git a/test/functional/input/data/list_table.txt b/test/functional/input/data/list_table.txt
new file mode 100644
index 000000000..632285e36
--- /dev/null
+++ b/test/functional/input/data/list_table.txt
@@ -0,0 +1,24 @@
+List Tables
+-----------
+
+Here's a list table exercising all features:
+
+.. list-table:: list table with integral header
+ :class: test
+ :widths: 10 20 30
+ :header-rows: 1
+ :stub-columns: 1
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
diff --git a/test/functional/input/data/nonalphanumeric.txt b/test/functional/input/data/nonalphanumeric.txt
new file mode 100644
index 000000000..4c4ee7343
--- /dev/null
+++ b/test/functional/input/data/nonalphanumeric.txt
@@ -0,0 +1,13 @@
+Monospaced non-alphanumeric characters
+--------------------------------------
+
+These are all ASCII characters except a-zA-Z0-9 and space:
+
+``!!!"""###$$$%%%&&&'''((()))***+++,,,---...///:::``
+
+``;;;<<<===>>>???@@@[[[\\\]]]^^^___```{{{|||}}}~~~``
+
+``xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx``
+
+The two lines of non-alphanumeric characters should both have the same
+width as the third line.
diff --git a/test/functional/input/data/standard.txt b/test/functional/input/data/standard.txt
new file mode 100644
index 000000000..a0d1570ed
--- /dev/null
+++ b/test/functional/input/data/standard.txt
@@ -0,0 +1,753 @@
+.. This is a comment. Note how any initial comments are moved by
+ transforms to after the document title, subtitle, and docinfo.
+
+.. _doctitle:
+
+================================
+ reStructuredText Test Document
+================================
+
+.. Above is the document title, and below is the subtitle.
+ They are transformed from section titles after parsing.
+
+.. _subtitle:
+
+--------------------------------
+ Examples of Syntax Constructs
+--------------------------------
+
+.. bibliographic fields (which also require a transform):
+
+:Author: David Goodger
+:Address: 123 Example Street
+ Example, EX Canada
+ A1B 2C3
+:Contact: goodger@users.sourceforge.net
+:Authors: Me; Myself; I
+:organization: humankind
+:date: Now, or yesterday. Or maybe even *before* yesterday.
+:status: This is a "work in progress"
+:revision: is managed by a version control system.
+:version: 1
+:copyright: This document has been placed in the public domain. You
+ may do with it as you wish. You may copy, modify,
+ redistribute, reattribute, sell, buy, rent, lease,
+ destroy, or improve it, quote it at length, excerpt,
+ incorporate, collate, fold, staple, or mutilate it, or do
+ anything else to it that your or anyone else's heart
+ desires.
+:field name: This is a "generic bibliographic field".
+:field name "2":
+ Generic bibliographic fields may contain multiple body elements.
+
+ Like this.
+
+:Dedication:
+
+ For Docutils users & co-developers.
+
+:abstract:
+
+ This is a test document, containing at least one example of each
+ reStructuredText construct.
+
+.. meta::
+ :keywords: reStructuredText, test, parser
+ :description lang=en: A test document, containing at least one
+ example of each reStructuredText construct.
+
+.. contents:: Table of Contents
+.. section-numbering::
+
+
+Structural Elements
+===================
+
+Section Title
+-------------
+Section Subtitle
+````````````````
+
+That's it, the text just above this line.
+
+Empty Section
+-------------
+
+Transitions
+-----------
+
+Here's a transition:
+
+---------
+
+It divides the section. Transitions may also occur between sections:
+
+---------
+
+Body Elements
+=============
+
+Paragraphs
+----------
+
+A paragraph.
+
+Inline Markup
+`````````````
+
+Paragraphs contain text and may contain inline markup: *emphasis*,
+**strong emphasis**, ``inline literals``, standalone hyperlinks
+(http://www.python.org), external hyperlinks (Python_), internal
+cross-references (example_), external hyperlinks with embedded URIs
+(`Python web site <http://www.python.org>`__), `anonymous hyperlink
+references`__ (`a second reference`__), footnote references (manually
+numbered [1]_, anonymous auto-numbered [#]_, labeled auto-numbered
+[#label]_, or symbolic [*]_), citation references ([CIT2002]_),
+substitution references (|example|), and _`inline hyperlink targets`
+(see Targets_ below for a reference back to here). Character-level
+inline markup is also possible (although exceedingly ugly!) in *re*\
+``Structured``\ *Text*. Problems are indicated by |problematic| text
+(generated by processing errors; this one is intentional). Here is a
+reference to the doctitle_ and the subtitle_.
+
+__ http://www.python.org/
+__ http://docutils.sourceforge.net/
+
+The default role for interpreted text is `Title Reference`. Here are
+some explicit interpreted text roles: a PEP reference (:PEP:`287`); an
+RFC reference (:RFC:`2822`); a :sub:`subscript`; a :sup:`superscript`;
+and explicit roles for :emphasis:`standard` :strong:`inline`
+:literal:`markup`.
+
+.. DO NOT RE-WRAP THE FOLLOWING PARAGRAPH!
+
+Let's test wrapping and whitespace significance in inline literals:
+``This is an example of --inline-literal --text, --including some--
+strangely--hyphenated-words. Adjust-the-width-of-your-browser-window
+to see how the text is wrapped. -- ---- -------- Now note the
+spacing between the words of this sentence (words
+should be grouped in pairs).``
+
+If the ``--pep-references`` option was supplied, there should be a
+live link to PEP 258 here.
+
+Bullet Lists
+------------
+
+- A bullet list
+
+ + Nested bullet list.
+ + Nested item 2.
+
+- Item 2.
+
+ Paragraph 2 of item 2.
+
+ * Nested bullet list.
+ * Nested item 2.
+
+ - Third level.
+ - Item 2.
+
+ * Nested item 3.
+
+ * This nested list should be compacted by the HTML writer.
+
+ .. _target:
+
+ .. Even if this item contains a target and a comment.
+
+Enumerated Lists
+----------------
+
+1. Arabic numerals.
+
+ a) lower alpha)
+
+ (i) (lower roman)
+
+ A. upper alpha.
+
+ I) upper roman)
+
+2. Lists that don't start at 1:
+
+ 3. Three
+
+ 4. Four
+
+ C. C
+
+ D. D
+
+ iii. iii
+
+ iv. iv
+
+Definition Lists
+----------------
+
+Term
+ Definition
+Term : classifier
+ Definition paragraph 1.
+
+ Definition paragraph 2.
+Term
+ Definition
+Term : classifier one : classifier two
+ Definition
+
+Field Lists
+-----------
+
+:what: Field lists map field names to field bodies, like database
+ records. They are often part of an extension syntax. They are
+ an unambiguous variant of RFC 2822 fields.
+
+:how arg1 arg2:
+
+ The field marker is a colon, the field name, and a colon.
+
+ The field body may contain one or more body elements, indented
+ relative to the field marker.
+
+:credits:
+
+ .. class:: credits
+
+ This paragraph has the `credits` class set. (This is actually not
+ about credits but just for ensuring that the class attribute
+ doesn't get stripped away.)
+
+Option Lists
+------------
+
+For listing command-line options:
+
+-a command-line option "a"
+-b file options can have arguments
+ and long descriptions
+--long options can be long also
+--input=file long options can also have
+ arguments
+
+--very-long-option
+ The description can also start on the next line.
+
+ The description may contain multiple body elements,
+ regardless of where it starts.
+
+-x, -y, -z Multiple options are an "option group".
+-v, --verbose Commonly-seen: short & long options.
+-1 file, --one=file, --two file
+ Multiple options with arguments.
+/V DOS/VMS-style options too
+
+There must be at least two spaces between the option and the
+description.
+
+Literal Blocks
+--------------
+
+Literal blocks are indicated with a double-colon ("::") at the end of
+the preceding paragraph (over there ``-->``). They can be indented::
+
+ if literal_block:
+ text = 'is left as-is'
+ spaces_and_linebreaks = 'are preserved'
+ markup_processing = None
+
+Or they can be quoted without indentation::
+
+>> Great idea!
+>
+> Why didn't I think of that?
+
+Line Blocks
+-----------
+
+This section tests line blocks. Line blocks are body elements which
+consist of lines and other line blocks. Nested line blocks cause
+indentation.
+
+| This is a line block. It ends with a blank line.
+| New lines begin with a vertical bar ("|").
+| Line breaks and initial indent are significant, and preserved.
+| Continuation lines are also possible. A long line that is intended
+ to wrap should begin with a space in place of the vertical bar.
+| The left edge of a continuation line need not be aligned with
+ the left edge of the text above it.
+
+| This is a second line block.
+|
+| Blank lines are permitted internally, but they must begin with a "|".
+
+Another line block, surrounded by paragraphs:
+
+| And it's no good waiting by the window
+| It's no good waiting for the sun
+| Please believe me, the things you dream of
+| They don't fall in the lap of no-one
+
+Take it away, Eric the Orchestra Leader!
+
+ | A one, two, a one two three four
+ |
+ | Half a bee, philosophically,
+ | must, *ipso facto*, half not be.
+ | But half the bee has got to be,
+ | *vis a vis* its entity. D'you see?
+ |
+ | But can a bee be said to be
+ | or not to be an entire bee,
+ | when half the bee is not a bee,
+ | due to some ancient injury?
+ |
+ | Singing...
+
+Block Quotes
+------------
+
+Block quotes consist of indented body elements:
+
+ My theory by A. Elk. Brackets Miss, brackets. This theory goes
+ as follows and begins now. All brontosauruses are thin at one
+ end, much much thicker in the middle and then thin again at the
+ far end. That is my theory, it is mine, and belongs to me and I
+ own it, and what it is too.
+
+ -- Anne Elk (Miss)
+
+Doctest Blocks
+--------------
+
+>>> print 'Python-specific usage examples; begun with ">>>"'
+Python-specific usage examples; begun with ">>>"
+>>> print '(cut and pasted from interactive Python sessions)'
+(cut and pasted from interactive Python sessions)
+
+Footnotes
+---------
+
+.. [1] A footnote contains body elements, consistently indented by at
+ least 3 spaces.
+
+ This is the footnote's second paragraph.
+
+.. [#label] Footnotes may be numbered, either manually (as in [1]_) or
+ automatically using a "#"-prefixed label. This footnote has a
+ label so it can be referred to from multiple places, both as a
+ footnote reference ([#label]_) and as a hyperlink reference
+ (label_).
+
+.. [#] This footnote is numbered automatically and anonymously using a
+ label of "#" only.
+
+ This is the second paragraph.
+
+ And this is the third paragraph.
+
+.. [*] Footnotes may also use symbols, specified with a "*" label.
+ Here's a reference to the next footnote: [*]_.
+
+.. [*] This footnote shows the next symbol in the sequence.
+
+.. [4] Here's an unreferenced footnote, with a reference to a
+ nonexistent footnote: [5]_.
+
+Citations
+---------
+
+.. [CIT2002] Citations are text-labeled footnotes. They may be
+ rendered separately and differently from footnotes.
+
+Here's a reference to the above, [CIT2002]_, and a [nonexistent]_
+citation.
+
+.. _Another Target:
+
+Targets
+-------
+
+.. _example:
+
+This paragraph is pointed to by the explicit "example" target. A
+reference can be found under `Inline Markup`_, above. `Inline
+hyperlink targets`_ are also possible.
+
+Section headers are implicit targets, referred to by name. See
+Targets_, which is a subsection of `Body Elements`_.
+
+Explicit external targets are interpolated into references such as
+"Python_".
+
+.. _Python: http://www.python.org/
+
+Targets may be indirect and anonymous. Thus `this phrase`__ may also
+refer to the Targets_ section.
+
+__ Targets_
+
+Here's a `hyperlink reference without a target`_, which generates an
+error.
+
+Duplicate Target Names
+``````````````````````
+
+Duplicate names in section headers or other implicit targets will
+generate "info" (level-1) system messages. Duplicate names in
+explicit targets will generate "warning" (level-2) system messages.
+
+Duplicate Target Names
+``````````````````````
+
+Since there are two "Duplicate Target Names" section headers, we
+cannot uniquely refer to either of them by name. If we try to (like
+this: `Duplicate Target Names`_), an error is generated.
+
+Directives
+----------
+
+.. contents:: :local:
+
+These are just a sample of the many reStructuredText Directives. For
+others, please see
+http://docutils.sourceforge.net/docs/ref/rst/directives.html.
+
+Document Parts
+``````````````
+
+An example of the "contents" directive can be seen above this section
+(a local, untitled table of contents_) and at the beginning of the
+document (a document-wide `table of contents`_).
+
+Images
+``````
+
+An image directive (also clickable -- a hyperlink reference):
+
+.. image:: ../../../docs/user/rst/images/title.png
+ :class: class1 class2
+ :target: directives_
+
+Image with multiple IDs:
+
+.. _image target 1:
+.. _image target 2:
+.. _image target 3:
+.. image:: ../../../docs/user/rst/images/title.png
+
+A centered image:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :align: center
+
+A left-aligned image:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :align: left
+
+A right-aligned image:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :align: right
+
+A figure directive:
+
+.. figure:: ../../../docs/user/rst/images/biohazard.png
+ :figclass: figclass1 figclass2
+ :class: class1 class2
+ :alt: reStructuredText, the markup syntax
+ :align: right
+ :width: 50
+
+ A figure is an image with a caption and/or a legend:
+
+ +------------+-----------------------------------------------+
+ | re | Revised, revisited, based on 're' module. |
+ +------------+-----------------------------------------------+
+ | Structured | Structure-enhanced text, structuredtext. |
+ +------------+-----------------------------------------------+
+ | Text | Well it is, isn't it? |
+ +------------+-----------------------------------------------+
+
+ This paragraph is also part of the legend.
+
+.. figure:: ../../../docs/user/rst/images/biohazard.png
+ :figclass: figclass1 figclass2
+ :class: class1 class2
+ :alt: reStructuredText, the markup syntax
+ :align: left
+ :width: 50
+
+ A left-aligned figure.
+
+ This is the legend.
+
+This paragraph might flow around the figure...
+
+A centered figure:
+
+.. figure:: ../../../docs/user/rst/images/biohazard.png
+ :align: center
+ :width: 50
+
+ This is the caption.
+
+ This is the legend.
+
+ The legend may consist of several paragraphs.
+
+This paragraph might flow around the figure...
+
+A left-aligned figure:
+
+.. figure:: ../../../docs/user/rst/images/biohazard.png
+ :align: left
+ :width: 50
+
+ This is the caption.
+
+ This is the legend.
+
+ The legend may consist of several paragraphs.
+
+This paragraph might flow around the figure...
+
+Now widths:
+
+An image 2 em wide:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :width: 2 em
+
+An image 2 em wide and 30 pixel high:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :width: 2em
+ :height: 30 px
+
+An image occupying 70% of the line width:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :width: 70%
+
+An image 3 cm high:
+
+.. image:: ../../../docs/user/rst/images/biohazard.png
+ :height: 3 cm
+
+
+Admonitions
+```````````
+
+.. Attention:: Directives at large.
+
+.. Caution::
+
+ Don't take any wooden nickels.
+
+.. DANGER:: Mad scientist at work!
+
+.. Error:: Does not compute.
+
+.. Hint:: It's bigger than a bread box.
+
+.. Important::
+ - Wash behind your ears.
+ - Clean up your room.
+ - Call your mother.
+ - Back up your data.
+
+.. Note:: This is a note.
+
+.. Tip:: 15% if the service is good.
+
+.. WARNING:: Strong prose may provoke extreme mental exertion.
+ Reader discretion is strongly advised.
+
+.. admonition:: And, by the way...
+
+ You can make up your own admonition too.
+
+ .. _Docutils: http://docutils.sourceforge.net/
+
+Topics, Sidebars, and Rubrics
+`````````````````````````````
+
+.. sidebar:: Sidebar Title
+ :subtitle: Optional Subtitle
+
+ This is a sidebar. It is for text outside the flow of the main
+ text.
+
+ .. rubric:: This is a rubric inside a sidebar
+
+ Sidebars often appears beside the main text with a border and
+ background color.
+
+.. topic:: Topic Title
+
+ This is a topic.
+
+.. rubric:: This is a rubric
+
+Target Footnotes
+````````````````
+
+.. target-notes::
+
+
+Replacement Text
+````````````````
+
+I recommend you try |Python|_.
+
+.. |Python| replace:: Python, *the* best language around
+
+Compound Paragraph
+``````````````````
+
+.. compound::
+ :class: some-class
+
+ Compound 1, paragraph 1.
+
+ Compound 1, paragraph 2.
+
+ * Compound 1, list item one.
+ * Compound 1, list item two.
+
+Another compound statement:
+
+.. compound::
+
+ Compound 2, a literal block::
+
+ Compound 2, literal.
+
+ Compound 2, this is a test.
+
+.. compound::
+
+ Compound 3, only consisting of one paragraph.
+
+.. compound::
+
+ ::
+
+ Compound 4.
+ This one starts with a literal block.
+
+ Compound 4, a paragraph.
+
+Now something *really* perverted -- a nested compound block. This is
+just to test that it works at all; the results don't have to be
+meaningful.
+
+.. compound::
+
+ Compound 5, block 1 (a paragraph).
+
+ .. compound::
+
+ Compound 6, block 2 in compound 5.
+
+ Compound 6, another paragraph.
+
+ Compound 5, block 3 (a paragraph).
+
+.. compound::
+
+ Compound 7, with a table inside:
+
+ +--------------------+--------------------+--------------------+
+ | Left cell, first | Middle cell, | Right cell. |
+ | paragraph. | consisting of | |
+ | | exactly one | Paragraph 2. |
+ | Left cell, second | paragraph. | |
+ | paragraph. | | Paragraph 3. |
+ +--------------------+--------------------+--------------------+
+
+ Compound 7, a paragraph after the table.
+
+ Compound 7, another paragraph.
+
+Parsed Literal Blocks
+`````````````````````
+
+.. parsed-literal::
+
+ This is a parsed literal block.
+ This line is indented. The next line is blank.
+
+ Inline markup is supported, e.g. *emphasis*, **strong**, ``literal
+ text``, footnotes [1]_, _`targets`, and `references
+ <http://www.python.org/>`_.
+
+Substitution Definitions
+------------------------
+
+An inline image (|example|) example:
+
+.. |EXAMPLE| image:: ../../../docs/user/rst/images/biohazard.png
+
+(Substitution definitions are not visible in the HTML source.)
+
+Comments
+--------
+
+Here's one:
+
+.. Comments begin with two dots and a space. Anything may
+ follow, except for the syntax of footnotes, hyperlink
+ targets, directives, or substitution definitions.
+
+ Double-dashes -- "--" -- must be escaped somehow in HTML output.
+
+(View the HTML source to see the comment.)
+
+Raw text
+--------
+
+This does not necessarily look nice, because there may be missing white space.
+
+It's just there to freeze the behavior.
+
+.. raw:: html latex
+
+ A test.
+
+.. raw:: html latex
+
+ Second test.
+
+.. class:: myclass
+
+.. raw:: html latex
+
+ Another test with myclass set.
+
+.. role:: raw-role(raw)
+ :format: html latex
+ :class: myrawroleclass
+
+This is the :raw-role:`fourth test` with myrawroleclass set.
+
+.. raw:: html
+
+ Fifth test in HTML.<br />Line two.
+
+.. raw:: latex
+
+ Fifth test in LaTeX.\\Line two.
+
+Container
+---------
+
+.. container:: custom
+
+ paragraph 1
+
+ paragraph 2
diff --git a/test/functional/input/data/table_colspan.txt b/test/functional/input/data/table_colspan.txt
new file mode 100644
index 000000000..54294fdd2
--- /dev/null
+++ b/test/functional/input/data/table_colspan.txt
@@ -0,0 +1,15 @@
+Colspanning tables
+------------------
+
+This table has a cell spanning two columns:
+
+===== ===== ======
+ Inputs Output
+------------ ------
+ A B A or B
+===== ===== ======
+False False False
+True False True
+False True True
+True True True
+===== ===== ======
diff --git a/test/functional/input/data/table_complex.txt b/test/functional/input/data/table_complex.txt
new file mode 100644
index 000000000..8ff37180e
--- /dev/null
+++ b/test/functional/input/data/table_complex.txt
@@ -0,0 +1,21 @@
+Complex tables
+--------------
+
+Here's a complex table, which should test all features.
+
++------------------------+------------+----------+----------+
+| Header row, column 1 | Header 2 | Header 3 | Header 4 |
+| (header rows optional) | | | |
++========================+============+==========+==========+
+| body row 1, column 1 | column 2 | column 3 | column 4 |
++------------------------+------------+----------+----------+
+| body row 2 | Cells may span columns. |
++------------------------+------------+---------------------+
+| body row 3 | Cells may | - Table cells |
++------------------------+ span rows. | - contain |
+| body row 4 | | - body elements. |
+| | Paragraph. | |
++------------------------+------------+----------+----------+
+| body row 5 | Cells may also be | |
+| | empty: ``-->`` | |
++------------------------+-----------------------+----------+
diff --git a/test/functional/input/data/table_rowspan.txt b/test/functional/input/data/table_rowspan.txt
new file mode 100644
index 000000000..5df3109c4
--- /dev/null
+++ b/test/functional/input/data/table_rowspan.txt
@@ -0,0 +1,15 @@
+Rowspanning tables
+------------------
+
+Here's a table with cells spanning several rows:
+
++------------------------+------------+------------------+
+| Header row, column 1 | Header 2 | Header 3 |
+| (header rows optional) | | |
++========================+============+==================+
+| body row 1, column 1 | column 2 | column 3 |
++------------------------+------------+------------------+
+| body row 2 | Cells may | Another |
++------------------------+ span rows. | rowspanning |
+| body row 3 | | cell. |
++------------------------+------------+------------------+
diff --git a/test/functional/input/data/unicode.txt b/test/functional/input/data/unicode.txt
new file mode 100644
index 000000000..4bdd57653
--- /dev/null
+++ b/test/functional/input/data/unicode.txt
@@ -0,0 +1,27 @@
+Various non-ASCII characters
+----------------------------
+
+= ===================================
+© copyright sign
+® registered sign
+« left pointing guillemet
+» right pointing guillemet
+– en-dash
+— em-dash
+‘ single turned comma quotation mark
+’ single comma quotation mark
+‚ low single comma quotation mark
+“ double turned comma quotation mark
+†double comma quotation mark
+„ low double comma quotation mark
+† dagger
+‡ double dagger
+… ellipsis
+â„¢ trade mark sign
+⇔ left-right double arrow
+= ===================================
+
+The following line should not be wrapped, because it uses
+non-breakable spaces:
+
+X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
diff --git a/test/functional/input/field_list.txt b/test/functional/input/field_list.txt
new file mode 100644
index 000000000..fa04ba6ca
--- /dev/null
+++ b/test/functional/input/field_list.txt
@@ -0,0 +1,5 @@
+:short: This field's name is short.
+:medium-length: This field's name is medium-length.
+:long field name: This field's name is long.
+:very very long field name:
+ This field's name is quite long.
diff --git a/test/functional/input/latex_docinfo.txt b/test/functional/input/latex_docinfo.txt
new file mode 100644
index 000000000..f6c9ba2e4
--- /dev/null
+++ b/test/functional/input/latex_docinfo.txt
@@ -0,0 +1,10 @@
+:Author: Foo Fred
+:Organization: Food Foomatics & Friends
+:Contact: foo@food.example.info
+:Address: Fox St 13
+ Foowood
+:Author: Bar Barney
+:Organization: Bar-BQ Bar
+:Contact: 1-800-BARBQBAR
+:Address: Barbara St 16
+ South Barwell
diff --git a/test/functional/input/pep_html.txt b/test/functional/input/pep_html.txt
new file mode 100644
index 000000000..483077131
--- /dev/null
+++ b/test/functional/input/pep_html.txt
@@ -0,0 +1,32 @@
+PEP: 100
+Title: Test PEP
+Version: 42
+Last-Modified: A long time ago.
+Author: John Doe <john@example.org>
+Discussions-To: <devnull@example.org>
+Status: Draft
+Type: Standards Track
+Content-Type: text/x-rst
+Created: 01-Jun-2001
+Post-History: 13-Jun-2001
+
+
+Abstract
+========
+
+This is just a test [#]_. See the `PEP repository`_ for the real
+thing.
+
+.. _PEP repository: http://www.python.org/peps/
+
+
+Copyright
+=========
+
+This document has been placed in the public domain.
+
+
+References and Footnotes
+========================
+
+.. [#] PEP editors: peps@python.org
diff --git a/test/functional/input/simple.txt b/test/functional/input/simple.txt
new file mode 100644
index 000000000..492e4233b
--- /dev/null
+++ b/test/functional/input/simple.txt
@@ -0,0 +1 @@
+simple input
diff --git a/test/functional/input/standalone_rst_html4css1.txt b/test/functional/input/standalone_rst_html4css1.txt
new file mode 100644
index 000000000..3c2cf80c6
--- /dev/null
+++ b/test/functional/input/standalone_rst_html4css1.txt
@@ -0,0 +1,8 @@
+.. include:: data/standard.txt
+.. include:: data/header_footer.txt
+.. include:: data/table_colspan.txt
+.. include:: data/table_rowspan.txt
+.. include:: data/table_complex.txt
+.. include:: data/list_table.txt
+.. include:: data/custom_roles.txt
+.. include:: data/errors.txt
diff --git a/test/functional/input/standalone_rst_latex.txt b/test/functional/input/standalone_rst_latex.txt
new file mode 100644
index 000000000..09a4f8890
--- /dev/null
+++ b/test/functional/input/standalone_rst_latex.txt
@@ -0,0 +1,12 @@
+.. include:: data/standard.txt
+.. include:: data/table_colspan.txt
+.. include:: data/table_rowspan.txt
+
+
+Tests for the LaTeX writer
+==========================
+
+.. include:: data/nonalphanumeric.txt
+.. include:: data/unicode.txt
+
+.. include:: data/errors.txt
diff --git a/test/functional/input/standalone_rst_newlatex.txt b/test/functional/input/standalone_rst_newlatex.txt
new file mode 100644
index 000000000..81b4e5ea6
--- /dev/null
+++ b/test/functional/input/standalone_rst_newlatex.txt
@@ -0,0 +1,12 @@
+.. include:: data/standard.txt
+.. include:: data/table_colspan.txt
+.. include:: data/latex.txt
+
+
+Tests for the LaTeX writer
+==========================
+
+.. include:: data/nonalphanumeric.txt
+.. include:: data/unicode.txt
+
+.. include:: data/errors.txt
diff --git a/test/functional/input/standalone_rst_pseudoxml.txt b/test/functional/input/standalone_rst_pseudoxml.txt
new file mode 100644
index 000000000..05f0287d0
--- /dev/null
+++ b/test/functional/input/standalone_rst_pseudoxml.txt
@@ -0,0 +1,7 @@
+.. include:: data/standard.txt
+.. include:: data/header_footer.txt
+.. include:: data/table_colspan.txt
+.. include:: data/table_rowspan.txt
+.. include:: data/table_complex.txt
+.. include:: data/list_table.txt
+.. include:: data/errors.txt
diff --git a/test/functional/input/standalone_rst_s5_html.txt b/test/functional/input/standalone_rst_s5_html.txt
new file mode 100644
index 000000000..863cc77b6
--- /dev/null
+++ b/test/functional/input/standalone_rst_s5_html.txt
@@ -0,0 +1,126 @@
+.. include:: <s5defs.txt>
+
+=============
+ Slide Shows
+=============
+
+:Author: David Goodger
+:Date: 2005-11-28
+
+.. contents::
+ :class: handout
+
+.. class:: handout
+
+ This is a test. This is only a test. If this were a real slide
+ show, there would be a projector handy.
+
+Let's test the S5/HTML writer!
+
+.. class:: small
+
+* Use the arrow keys to navigate.
+
+* Click the "|mode|" button to switch between presentation &
+ handout/outline modes.
+
+.. container:: handout
+
+ In presentation mode, mouse over to the lower right-hand corner to
+ display the controls.
+
+.. |bullet| unicode:: U+02022
+.. |mode| unicode:: U+00D8 .. capital o with stroke
+.. footer:: Location |bullet| Date
+
+
+Introduction
+============
+
+.. class:: compact
+
+* reStructuredText
+
+ .. class:: handout
+
+ Uses normal reStructuredText as input.
+
+* One section per slide
+
+ .. class:: handout
+
+ Each first-level section is converted into a single slide.
+
+* (X)HTML output
+
+ .. class:: handout
+
+ Presentations can be viewed using any modern graphical web browser.
+ The browser must support CSS, JavaScript, and XHTML. S5 even works
+ with IE!
+
+* Themes
+
+ .. class:: handout
+
+ A variety of themes are available.
+
+* ``rst2s5.py``
+
+ .. class:: handout
+
+ The front-end tool to generate S5 slide shows.
+
+
+Features (1)
+============
+
+.. class:: left
+
+A flush-left paragraph
+
+.. class:: center
+
+A centered paragraph
+
+.. class:: right
+
+A flush-right paragraph
+
+Some colours: :black:`black` [black], :gray:`gray`, :silver:`silver`,
+:white:`white` [white], :maroon:`maroon`, :red:`red`,
+:magenta:`magenta`, :fuchsia:`fuchsia`, :pink:`pink`,
+:orange:`orange`, :yellow:`yellow`, :lime:`lime`, :green:`green`,
+:olive:`olive`, :teal:`teal`, :cyan:`cyan`, :aqua:`aqua`,
+:blue:`blue`, :navy:`navy`, :purple:`purple`
+
+Features (2)
+============
+
+`Some` `incremental` `text.`
+
+.. class:: incremental open
+
+ * :tiny:`tiny` (class & role name: "tiny", e.g. "``:tiny:`text```")
+ * :small:`small` ("small")
+ * normal (unstyled)
+ * :big:`big` ("big")
+ * :huge:`huge` ("huge")
+
+
+Checklist
+=========
+
+* The document title should be duplicated on each slide in the footer
+ (except for the first slide, ``slide0``, where the entire footer is
+ disabled).
+
+* The footer also contains a second line, "Location |bullet| Date"
+
+* There's no table of contents on the first slide, although it does
+ appear in the handout/outline.
+
+* Handout material is not displayed in presentation mode.
+
+* The theme directories should be created, and the theme files copied
+ over.
diff --git a/test/functional/output/README.txt b/test/functional/output/README.txt
new file mode 100644
index 000000000..ce6dc9861
--- /dev/null
+++ b/test/functional/output/README.txt
@@ -0,0 +1,3 @@
+This is the directory where the actual output is stored.
+
+This README.txt is just a placeholder to make CVS create the directory.
diff --git a/test/functional/tests/_default.py b/test/functional/tests/_default.py
new file mode 100644
index 000000000..2835c5b2e
--- /dev/null
+++ b/test/functional/tests/_default.py
@@ -0,0 +1,7 @@
+# Default settings for all tests.
+
+settings_overrides['report_level'] = 2
+settings_overrides['halt_level'] = 5
+settings_overrides['warning_stream'] = ''
+settings_overrides['input_encoding'] = 'utf-8'
+settings_overrides['embed_stylesheet'] = 0
diff --git a/test/functional/tests/_standalone_rst_defaults.py b/test/functional/tests/_standalone_rst_defaults.py
new file mode 100644
index 000000000..b51704929
--- /dev/null
+++ b/test/functional/tests/_standalone_rst_defaults.py
@@ -0,0 +1,6 @@
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+
+# Settings.
+settings_overrides['sectsubtitle_xform'] = 1
diff --git a/test/functional/tests/compact_lists.py b/test/functional/tests/compact_lists.py
new file mode 100644
index 000000000..3ac4c3f8b
--- /dev/null
+++ b/test/functional/tests/compact_lists.py
@@ -0,0 +1,11 @@
+# Source and destination file names.
+test_source = "compact_lists.txt"
+test_destination = "compact_lists.html"
+
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+writer_name = "html"
+
+# Settings
+#settings_overrides['key'] =
diff --git a/test/functional/tests/dangerous.py b/test/functional/tests/dangerous.py
new file mode 100644
index 000000000..620a927ba
--- /dev/null
+++ b/test/functional/tests/dangerous.py
@@ -0,0 +1,12 @@
+# Source and destination file names.
+test_source = "dangerous.txt"
+test_destination = "dangerous.html"
+
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+writer_name = "html"
+
+# Settings
+settings_overrides['file_insertion_enabled'] = 0
+settings_overrides['raw_enabled'] = 0
diff --git a/test/functional/tests/field_name_limit.py b/test/functional/tests/field_name_limit.py
new file mode 100644
index 000000000..db79d4c67
--- /dev/null
+++ b/test/functional/tests/field_name_limit.py
@@ -0,0 +1,12 @@
+# Source and destination file names.
+test_source = "field_list.txt"
+test_destination = "field_name_limit.html"
+
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+writer_name = "html"
+
+# Settings
+settings_overrides['field_name_limit'] = 0 # no limit
+settings_overrides['docinfo_xform'] = 0
diff --git a/test/functional/tests/latex_docinfo.py b/test/functional/tests/latex_docinfo.py
new file mode 100644
index 000000000..3f9c34455
--- /dev/null
+++ b/test/functional/tests/latex_docinfo.py
@@ -0,0 +1,12 @@
+# Source and destination file names.
+test_source = "latex_docinfo.txt"
+test_destination = "latex_docinfo.tex"
+
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+writer_name = "latex"
+
+# Extra setting we need
+
+settings_overrides['use_latex_docinfo'] = 1
diff --git a/test/functional/tests/misc_rst_html4css1.py b/test/functional/tests/misc_rst_html4css1.py
new file mode 100644
index 000000000..861a9e9c5
--- /dev/null
+++ b/test/functional/tests/misc_rst_html4css1.py
@@ -0,0 +1,14 @@
+# Source and destination file names.
+test_source = "simple.txt"
+test_destination = "misc_rst_html4css1.html"
+
+# Keyword parameters passed to publish_file.
+reader_name = "standalone"
+parser_name = "rst"
+writer_name = "html4css1"
+
+# Settings
+# test for encoded attribute value:
+settings_overrides['stylesheet'] = 'foo&bar.css'
+settings_overrides['stylesheet_path'] = ''
+settings_overrides['embed_stylesheet'] = 0
diff --git a/test/functional/tests/pep_html.py b/test/functional/tests/pep_html.py
new file mode 100644
index 000000000..00e127ba7
--- /dev/null
+++ b/test/functional/tests/pep_html.py
@@ -0,0 +1,14 @@
+# Source and destination file names.
+test_source = "pep_html.txt"
+test_destination = "pep_html.html"
+
+# Keyword parameters passed to publish_file.
+reader_name = "pep"
+parser_name = "rst"
+writer_name = "pep_html"
+
+# Settings
+settings_overrides['python_home'] = "http://www.python.org"
+settings_overrides['pep_home'] = "http://www.python.org/peps"
+settings_overrides['no_random'] = 1
+settings_overrides['cloak_email_addresses'] = 1
diff --git a/test/functional/tests/standalone_rst_html4css1.py b/test/functional/tests/standalone_rst_html4css1.py
new file mode 100644
index 000000000..c34298eab
--- /dev/null
+++ b/test/functional/tests/standalone_rst_html4css1.py
@@ -0,0 +1,10 @@
+execfile('functional/tests/_standalone_rst_defaults.py')
+
+# Source and destination file names.
+test_source = "standalone_rst_html4css1.txt"
+test_destination = "standalone_rst_html4css1.html"
+
+# Keyword parameters passed to publish_file.
+writer_name = "html4css1"
+
+# Settings: settings_overrides['setting'] = value
diff --git a/test/functional/tests/standalone_rst_latex.py b/test/functional/tests/standalone_rst_latex.py
new file mode 100644
index 000000000..f0c40b75a
--- /dev/null
+++ b/test/functional/tests/standalone_rst_latex.py
@@ -0,0 +1,8 @@
+execfile('functional/tests/_standalone_rst_defaults.py')
+
+# Source and destination file names.
+test_source = "standalone_rst_latex.txt"
+test_destination = "standalone_rst_latex.tex"
+
+# Keyword parameters passed to publish_file.
+writer_name = "latex"
diff --git a/test/functional/tests/standalone_rst_pseudoxml.py b/test/functional/tests/standalone_rst_pseudoxml.py
new file mode 100644
index 000000000..b9b2df309
--- /dev/null
+++ b/test/functional/tests/standalone_rst_pseudoxml.py
@@ -0,0 +1,8 @@
+execfile('functional/tests/_standalone_rst_defaults.py')
+
+# Source and destination file names.
+test_source = "standalone_rst_pseudoxml.txt"
+test_destination = "standalone_rst_pseudoxml.txt"
+
+# Keyword parameters passed to publish_file.
+writer_name = "pseudoxml"
diff --git a/test/functional/tests/standalone_rst_s5_html_1.py b/test/functional/tests/standalone_rst_s5_html_1.py
new file mode 100755
index 000000000..ce27f687a
--- /dev/null
+++ b/test/functional/tests/standalone_rst_s5_html_1.py
@@ -0,0 +1,56 @@
+execfile('functional/tests/_standalone_rst_defaults.py')
+
+# Source and destination file names:
+test_source = 'standalone_rst_s5_html.txt'
+test_destination = 'standalone_rst_s5_html_1.html'
+
+# Keyword parameters passed to publish_file:
+writer_name = 's5_html'
+
+# Settings:
+settings_overrides['theme'] = 'small-black'
+
+
+# Extra functional tests.
+# Prefix all names with '_' to avoid confusing `docutils.core.publish_file`.
+
+import filecmp as _filecmp
+
+def _test_more(expected_dir, output_dir, test_case, parameters):
+ """Compare ``ui/<theme>`` directories."""
+ theme = settings_overrides.get('theme', 'default')
+ expected = '%s/%s/%s' % (expected_dir, 'ui', theme)
+ output = '%s/%s/%s' % (output_dir, 'ui', theme)
+ differences, uniques = _compare_directories(expected, output)
+ parts = []
+ if differences:
+ parts.append('The following files differ from the expected output:')
+ parts.extend(differences)
+ expected = [path.replace('functional/output/', 'functional/expected/')
+ for path in differences]
+ parts.append('Please compare the expected and actual output files:')
+ parts.extend([' diff %s %s' % tup
+ for tup in zip(expected, differences)])
+ parts.append('If the actual output is correct, please replace the '
+ 'expected output files:')
+ parts.extend([' mv %s %s' % tup
+ for tup in zip(differences, expected)])
+ parts.append('and check them in to Subversion:')
+ parts.extend([' svn commit -m "<comment>" %s' % path
+ for path in expected])
+ if uniques:
+ parts.append('The following paths are unique:')
+ parts.extend(uniques)
+ test_case.assert_(not parts, '\n'.join(parts))
+
+def _compare_directories(expected, output):
+ dircmp = _filecmp.dircmp(expected, output, ['.svn', 'CVS'])
+ differences = ['%s/%s' % (output, name) for name in dircmp.diff_files]
+ uniques = (['%s/%s' % (expected, name) for name in dircmp.left_only]
+ + ['%s/%s' % (output, name) for name in dircmp.right_only])
+ for subdir in dircmp.common_dirs:
+ diffs, uniqs = _compare_directories('%s/%s' % (expected, subdir),
+ '%s/%s' % (output, subdir))
+ differences.extend(diffs)
+ uniques.extend(uniqs)
+ return differences, uniques
diff --git a/test/functional/tests/standalone_rst_s5_html_2.py b/test/functional/tests/standalone_rst_s5_html_2.py
new file mode 100755
index 000000000..aea7a9207
--- /dev/null
+++ b/test/functional/tests/standalone_rst_s5_html_2.py
@@ -0,0 +1,7 @@
+# initialize with the settings & definitions from test 1:
+execfile('functional/tests/standalone_rst_s5_html_1.py')
+
+# overrides specific to this test:
+test_destination = 'standalone_rst_s5_html_2.html'
+del settings_overrides['theme'] # use the default
+settings_overrides['current_slide'] = 1
diff --git a/test/package_unittest.py b/test/package_unittest.py
new file mode 100644
index 000000000..43d724cd1
--- /dev/null
+++ b/test/package_unittest.py
@@ -0,0 +1,161 @@
+#! /usr/bin/env python
+
+# Author: Garth Kidd
+# Contact: garth@deadlybloodyserious.com
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+This module extends unittest.py with `loadTestModules()`, by loading multiple
+test modules from a directory. Optionally, test packages are also loaded,
+recursively.
+"""
+
+import sys
+import os
+import getopt
+import types
+import unittest
+import re
+
+
+# So that individual test modules can share a bit of state,
+# `package_unittest` acts as an intermediary for the following
+# variables:
+debug = 0
+verbosity = 1
+
+USAGE = """\
+Usage: test_whatever [options]
+
+Options:
+ -h, --help Show this message
+ -v, --verbose Verbose output
+ -q, --quiet Minimal output
+ -d, --debug Debug mode
+"""
+
+def usageExit(msg=None):
+ """Print usage and exit."""
+ if msg:
+ print msg
+ print USAGE
+ sys.exit(2)
+
+def parseArgs(argv=sys.argv):
+ """Parse command line arguments and set TestFramework state.
+
+ State is to be acquired by test_* modules by a grotty hack:
+ ``from TestFramework import *``. For this stylistic
+ transgression, I expect to be first up against the wall
+ when the revolution comes. --Garth"""
+ global verbosity, debug
+ try:
+ options, args = getopt.getopt(argv[1:], 'hHvqd',
+ ['help', 'verbose', 'quiet', 'debug'])
+ for opt, value in options:
+ if opt in ('-h', '-H', '--help'):
+ usageExit()
+ if opt in ('-q', '--quiet'):
+ verbosity = 0
+ if opt in ('-v', '--verbose'):
+ verbosity = 2
+ if opt in ('-d', '--debug'):
+ debug =1
+ if len(args) != 0:
+ usageExit("No command-line arguments supported yet.")
+ except getopt.error, msg:
+ usageExit(msg)
+
+def loadTestModules(path, name='', packages=None):
+ """
+ Return a test suite composed of all the tests from modules in a directory.
+
+ Search for modules in directory `path`, beginning with `name`. If
+ `packages` is true, search subdirectories (also beginning with `name`)
+ recursively. Subdirectories must be Python packages; they must contain an
+ '__init__.py' module.
+ """
+ testLoader = unittest.defaultTestLoader
+ testSuite = unittest.TestSuite()
+ testModules = []
+ path = os.path.abspath(path) # current working dir if `path` empty
+ paths = [path]
+ while paths:
+ p = paths.pop(0)
+ files = os.listdir(p)
+ for filename in files:
+ if filename.startswith(name):
+ fullpath = os.path.join(p, filename)
+ if filename.endswith('.py'):
+ fullpath = fullpath[len(path)+1:]
+ testModules.append(path2mod(fullpath))
+ elif packages and os.path.isdir(fullpath) and \
+ os.path.isfile(os.path.join(fullpath, '__init__.py')):
+ paths.append(fullpath)
+ # Import modules and add their tests to the suite.
+ sys.path.insert(0, path)
+ for mod in testModules:
+ if debug:
+ print >>sys.stderr, "importing %s" % mod
+ try:
+ module = import_module(mod)
+ except ImportError:
+ print >>sys.stderr, "ERROR: Can't import %s, skipping its tests:" % mod
+ sys.excepthook(*sys.exc_info())
+ else:
+ # if there's a suite defined, incorporate its contents
+ try:
+ suite = getattr(module, 'suite')
+ except AttributeError:
+ # Look for individual tests
+ moduleTests = testLoader.loadTestsFromModule(module)
+ # unittest.TestSuite.addTests() doesn't work as advertised,
+ # as it can't load tests from another TestSuite, so we have
+ # to cheat:
+ testSuite.addTest(moduleTests)
+ continue
+ if type(suite) == types.FunctionType:
+ testSuite.addTest(suite())
+ elif type(suite) == types.InstanceType \
+ and isinstance(suite, unittest.TestSuite):
+ testSuite.addTest(suite)
+ else:
+ raise AssertionError, "don't understand suite (%s)" % mod
+ sys.path.pop(0)
+ return testSuite
+
+def path2mod(path):
+ """Convert a file path to a dotted module name."""
+ return path[:-3].replace(os.sep, '.')
+
+def import_module(name):
+ """Import a dotted-path module name, and return the final component."""
+ mod = __import__(name)
+ components = name.split('.')
+ for comp in components[1:]:
+ mod = getattr(mod, comp)
+ return mod
+
+def main(suite=None):
+ """
+ Shared `main` for any individual test_* file.
+
+ suite -- TestSuite to run. If not specified, look for any globally defined
+ tests and run them.
+ """
+ parseArgs()
+ if suite is None:
+ # Load any globally defined tests.
+ suite = unittest.defaultTestLoader.loadTestsFromModule(
+ __import__('__main__'))
+ if debug:
+ print >>sys.stderr, "Debug: Suite=%s" % suite
+ testRunner = unittest.TextTestRunner(verbosity=verbosity)
+ # run suites (if we were called from test_all) or suite...
+ if type(suite) == type([]):
+ for s in suite:
+ testRunner.run(s)
+ else:
+ testRunner.run(suite)
diff --git a/test/test_dependencies.py b/test/test_dependencies.py
new file mode 100755
index 000000000..46e8ff846
--- /dev/null
+++ b/test/test_dependencies.py
@@ -0,0 +1,78 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for the --record-dependencies option.
+"""
+
+import os.path
+import unittest
+import sys
+import DocutilsTestSupport # must be imported before docutils
+import docutils.core
+import docutils.utils
+
+
+class RecordDependenciesTests(unittest.TestCase):
+
+ def setUp(self):
+ os.chdir(os.path.join(DocutilsTestSupport.testroot, 'data'))
+
+ def get_record(self, inputfile=None, **settings):
+
+ recordfile = 'record.txt'
+ settings.setdefault('source_path', 'dependencies.txt')
+ settings.setdefault('settings_overrides', {})
+ settings['settings_overrides'] = settings['settings_overrides'].copy()
+ settings['settings_overrides']['_disable_config'] = 1
+ if not settings['settings_overrides'].has_key('record_dependencies'):
+ settings['settings_overrides']['record_dependencies'] = \
+ docutils.utils.DependencyList(recordfile)
+ docutils.core.publish_file(destination=DocutilsTestSupport.DevNull(),
+ **settings)
+ settings['settings_overrides']['record_dependencies'].close()
+ return open(recordfile).read().splitlines()
+
+ def test_dependencies(self):
+ self.assertEqual(self.get_record(),
+ ['include.txt',
+ 'raw.txt'])
+ self.assertEqual(self.get_record(writer_name='latex'),
+ ['include.txt',
+ 'raw.txt',
+ 'some_image.png'])
+
+ def test_csv_dependencies(self):
+ try:
+ import csv
+ self.assertEqual(self.get_record(source_path='csv_dep.txt'),
+ ['csv_data.txt'])
+ except ImportError:
+ pass
+
+ def test_stylesheet_dependencies(self):
+ # Parameters to publish_file.
+ s = {'settings_overrides': {}}
+ so = s['settings_overrides']
+ so['embed_stylesheet'] = 0
+ so['stylesheet_path'] = 'stylesheet.txt'
+ so['stylesheet'] = None
+ s['writer_name'] = 'html'
+ self.assert_('stylesheet.txt' not in
+ self.get_record(**s))
+ so['embed_stylesheet'] = 1
+ self.assert_('stylesheet.txt' in
+ self.get_record(**s))
+ del so['embed_stylesheet']
+ s['writer_name'] = 'latex'
+ self.assert_('stylesheet.txt' in
+ self.get_record(**s))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_functional.py b/test/test_functional.py
new file mode 100755
index 000000000..dcec9cf45
--- /dev/null
+++ b/test/test_functional.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Perform tests with the data in the functional/ directory.
+
+Read README.txt for details on how this is done.
+"""
+
+import sys
+import os
+import os.path
+import shutil
+import unittest
+import difflib
+import DocutilsTestSupport # must be imported before docutils
+import docutils
+import docutils.core
+
+
+datadir = 'functional'
+"""The directory to store the data needed for the functional tests."""
+
+
+def join_path(*args):
+ return '/'.join(args) or '.'
+
+
+class FunctionalTestSuite(DocutilsTestSupport.CustomTestSuite):
+
+ """Test suite containing test cases for all config files."""
+
+ def __init__(self):
+ """Process all config files in functional/tests/."""
+ DocutilsTestSupport.CustomTestSuite.__init__(self)
+ os.chdir(DocutilsTestSupport.testroot)
+ self.clear_output_directory()
+ self.added = 0
+ os.path.walk(join_path(datadir, 'tests'), self.walker, None)
+ assert self.added, 'No functional tests found.'
+
+ def clear_output_directory(self):
+ files = os.listdir(os.path.join('functional', 'output'))
+ for f in files:
+ if f in ('README.txt', '.svn', 'CVS'):
+ continue # don't touch the infrastructure
+ path = os.path.join('functional', 'output', f)
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+ else:
+ os.remove(path)
+
+ def walker(self, dummy, dirname, names):
+ """
+ Process all config files among `names` in `dirname`.
+
+ This is a helper function for os.path.walk. A config file is
+ a Python file (*.py) which sets several variables.
+ """
+ for name in names:
+ if name.endswith('.py') and not name.startswith('_'):
+ config_file_full_path = join_path(dirname, name)
+ self.addTestCase(FunctionalTestCase, 'test', None, None,
+ id=config_file_full_path,
+ configfile=config_file_full_path)
+ self.added += 1
+
+
+class FunctionalTestCase(DocutilsTestSupport.CustomTestCase):
+
+ """Test case for one config file."""
+
+ def __init__(self, *args, **kwargs):
+ """Set self.configfile, pass arguments to parent __init__."""
+ self.configfile = kwargs['configfile']
+ del kwargs['configfile']
+ DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
+
+ def shortDescription(self):
+ return 'test_functional.py: ' + self.configfile
+
+ def test(self):
+ """Process self.configfile."""
+ os.chdir(DocutilsTestSupport.testroot)
+ # Keyword parameters for publish_file:
+ namespace = {}
+ # Initialize 'settings_overrides' for test settings scripts,
+ # and disable configuration files:
+ namespace['settings_overrides'] = {'_disable_config': 1}
+ # Read the variables set in the default config file and in
+ # the current config file into namespace:
+ execfile(join_path(datadir, 'tests', '_default.py'), namespace)
+ execfile(self.configfile, namespace)
+ # Check for required settings:
+ assert namespace.has_key('test_source'),\
+ "No 'test_source' supplied in " + self.configfile
+ assert namespace.has_key('test_destination'),\
+ "No 'test_destination' supplied in " + self.configfile
+ # Set source_path and destination_path if not given:
+ namespace.setdefault('source_path',
+ join_path(datadir, 'input',
+ namespace['test_source']))
+ # Path for actual output:
+ namespace.setdefault('destination_path',
+ join_path(datadir, 'output',
+ namespace['test_destination']))
+ # Path for expected output:
+ expected_path = join_path(datadir, 'expected',
+ namespace['test_destination'])
+ # shallow copy of namespace to minimize:
+ params = namespace.copy()
+ # remove unneeded parameters:
+ del params['test_source']
+ del params['test_destination']
+ # Delete private stuff like params['__builtins__']:
+ for key in params.keys():
+ if key.startswith('_'):
+ del params[key]
+ # Get output (automatically written to the output/ directory
+ # by publish_file):
+ output = docutils.core.publish_file(**params)
+ # Get the expected output *after* writing the actual output.
+ self.assert_(os.access(expected_path, os.R_OK),\
+ 'Cannot find expected output at\n' + expected_path)
+ f = open(expected_path, 'rU')
+ expected = f.read()
+ f.close()
+ diff = ('The expected and actual output differs.\n'
+ 'Please compare the expected and actual output files:\n'
+ ' diff %s %s\n'
+ 'If the actual output is correct, please replace the\n'
+ 'expected output and check it in to Subversion:\n'
+ ' mv %s %s\n'
+ ' svn commit -m "<comment>" %s'
+ % (expected_path, params['destination_path'],
+ params['destination_path'], expected_path, expected_path))
+ try:
+ self.assertEquals(output, expected, diff)
+ except AssertionError:
+ if hasattr(difflib, 'unified_diff'):
+ # Generate diff if unified_diff available:
+ diff = ''.join(
+ difflib.unified_diff(expected.splitlines(1),
+ output.splitlines(1),
+ expected_path,
+ params['destination_path']))
+ print >>sys.stderr, '\n%s:' % (self,)
+ print >>sys.stderr, diff
+ raise
+ # Execute optional function containing extra tests:
+ if namespace.has_key('_test_more'):
+ namespace['_test_more'](join_path(datadir, 'expected'),
+ join_path(datadir, 'output'),
+ self, namespace)
+
+
+def suite():
+ return FunctionalTestSuite()
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/test/test_io.py b/test/test_io.py
new file mode 100755
index 000000000..b82911e44
--- /dev/null
+++ b/test/test_io.py
@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for io.py.
+"""
+
+import unittest
+import DocutilsTestSupport # must be imported before docutils
+from docutils import io
+
+
+class InputTests(unittest.TestCase):
+
+ def test_bom(self):
+ input = io.StringInput(source='\xef\xbb\xbf foo \xef\xbb\xbf bar',
+ encoding='utf8')
+ # Assert BOMs are gone.
+ self.assertEquals(input.read(), u' foo bar')
+ # With unicode input:
+ input = io.StringInput(source=u'\ufeff foo \ufeff bar')
+ # Assert BOMs are still there.
+ self.assertEquals(input.read(), u'\ufeff foo \ufeff bar')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_language.py b/test/test_language.py
new file mode 100755
index 000000000..0571275e7
--- /dev/null
+++ b/test/test_language.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+
+# Authors: Engelbert Gruber; David Goodger
+# Contact: grubert@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for language module completeness.
+
+Specify a language code (e.g. "de") as a command-line parameter to test only
+that language.
+"""
+
+import sys
+import os
+import re
+from types import UnicodeType
+import DocutilsTestSupport # must be imported before docutils
+import docutils.languages
+import docutils.parsers.rst.languages
+from docutils.parsers.rst import states, directives, roles
+
+
+reference_language = 'en'
+
+
+class LanguageTestSuite(DocutilsTestSupport.CustomTestSuite):
+
+ language_module_pattern = re.compile('^([a-z]{2,3}(_[a-z]{2,8})*)\.py$')
+
+ def __init__(self, languages=None):
+ DocutilsTestSupport.CustomTestSuite.__init__(self)
+ if languages:
+ self.languages = languages
+ else:
+ self.get_languages()
+
+ def get_languages(self):
+ """
+ Get installed language translations from docutils.languages and from
+ docutils.parsers.rst.languages.
+ """
+ languages = {}
+ for mod in (os.listdir(docutils.languages.__path__[0])
+ + os.listdir(docutils.parsers.rst.languages.__path__[0])):
+ match = self.language_module_pattern.match(mod)
+ if match:
+ languages[match.group(1)] = 1
+ self.languages = languages.keys()
+
+ def generateTests(self):
+ for language in self.languages:
+ for method in LanguageTestCase.test_methods:
+ self.addTestCase(LanguageTestCase, method, None, None,
+ id=language+'.py', language=language)
+
+
+class LanguageTestCase(DocutilsTestSupport.CustomTestCase):
+
+ test_methods = ['test_labels', 'test_bibliographic_fields',
+ 'test_directives', 'test_roles']
+ """Names of methods used to test each language."""
+
+ def __init__(self, *args, **kwargs):
+ self.ref = docutils.languages.get_language(reference_language)
+ self.language = kwargs['language']
+ del kwargs['language'] # only wanted here
+ DocutilsTestSupport.CustomTestCase.__init__(self, *args, **kwargs)
+
+ def _xor(self, ref_dict, l_dict):
+ """
+ Returns entries that are only in one dictionary.
+ (missing_in_lang, more_than_in_ref).
+ """
+ missing = [] # in ref but not in l.
+ too_much = [] # in l but not in ref.
+ for label in ref_dict.keys():
+ if not l_dict.has_key(label):
+ missing.append(label)
+ for label in l_dict.keys():
+ if not ref_dict.has_key(label):
+ too_much.append(label)
+ return (missing, too_much)
+
+ def _invert(self, adict):
+ """Return an inverted (keys & values swapped) dictionary."""
+ inverted = {}
+ for key, value in adict.items():
+ inverted[value] = key
+ return inverted
+
+ def test_labels(self):
+ try:
+ module = docutils.languages.get_language(self.language)
+ if not module:
+ raise ImportError
+ except ImportError:
+ self.fail('No docutils.languages.%s module.' % self.language)
+ missed, unknown = self._xor(self.ref.labels, module.labels)
+ if missed or unknown:
+ self.fail('Module docutils.languages.%s.labels:\n'
+ ' Missed: %s; Unknown: %s'
+ % (self.language, str(missed), str(unknown)))
+
+ def test_bibliographic_fields(self):
+ try:
+ module = docutils.languages.get_language(self.language)
+ if not module:
+ raise ImportError
+ except ImportError:
+ self.fail('No docutils.languages.%s module.' % self.language)
+ missed, unknown = self._xor(
+ self._invert(self.ref.bibliographic_fields),
+ self._invert(module.bibliographic_fields))
+ if missed or unknown:
+ self.fail('Module docutils.languages.%s.bibliographic_fields:\n'
+ ' Missed: %s; Unknown: %s'
+ % (self.language, str(missed), str(unknown)))
+
+ def test_directives(self):
+ try:
+ module = docutils.parsers.rst.languages.get_language(
+ self.language)
+ if not module:
+ raise ImportError
+ except ImportError:
+ self.fail('No docutils.parsers.rst.languages.%s module.'
+ % self.language)
+ failures = []
+ for d in module.directives.keys():
+ try:
+ func, msg = directives.directive(d, module, None)
+ if not func:
+ failures.append('"%s": unknown directive' % d)
+ except Exception, error:
+ failures.append('"%s": %s' % (d, error))
+ inverted = self._invert(module.directives)
+ canonical = directives._directive_registry.keys()
+ canonical.sort()
+ canonical.remove('restructuredtext-test-directive')
+ for name in canonical:
+ if not inverted.has_key(name):
+ failures.append('"%s": translation missing' % name)
+ if failures:
+ text = ('Module docutils.parsers.rst.languages.%s:\n %s'
+ % (self.language, '\n '.join(failures)))
+ if type(text) == UnicodeType:
+ text = text.encode('raw_unicode_escape')
+ self.fail(text)
+
+ def test_roles(self):
+ try:
+ module = docutils.parsers.rst.languages.get_language(
+ self.language)
+ if not module:
+ raise ImportError
+ module.roles
+ except ImportError:
+ self.fail('No docutils.parsers.rst.languages.%s module.'
+ % self.language)
+ except AttributeError:
+ self.fail('No "roles" mapping in docutils.parsers.rst.languages.'
+ '%s module.' % self.language)
+ failures = []
+ for d in module.roles.values():
+ try:
+ method = roles._role_registry[d]
+ #if not method:
+ # failures.append('"%s": unknown role' % d)
+ except KeyError, error:
+ failures.append('"%s": %s' % (d, error))
+ inverted = self._invert(module.roles)
+ canonical = roles._role_registry.keys()
+ canonical.sort()
+ canonical.remove('restructuredtext-unimplemented-role')
+ for name in canonical:
+ if not inverted.has_key(name):
+ failures.append('"%s": translation missing' % name)
+ if failures:
+ text = ('Module docutils.parsers.rst.languages.%s:\n %s'
+ % (self.language, '\n '.join(failures)))
+ if type(text) == UnicodeType:
+ text = text.encode('raw_unicode_escape')
+ self.fail(text)
+
+
+languages_to_test = []
+
+def suite():
+ s = LanguageTestSuite(languages_to_test)
+ s.generateTests()
+ return s
+
+def get_language_arguments():
+ while len(sys.argv) > 1:
+ last = sys.argv[-1]
+ if last.startswith('-'):
+ break
+ languages_to_test.append(last)
+ sys.argv.pop()
+ languages_to_test.reverse()
+
+
+if __name__ == '__main__':
+ get_language_arguments()
+ import unittest
+ unittest.main(defaultTest='suite')
+
+# vim: set et ts=4 ai :
diff --git a/test/test_nodes.py b/test/test_nodes.py
new file mode 100755
index 000000000..5467c5490
--- /dev/null
+++ b/test/test_nodes.py
@@ -0,0 +1,338 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for nodes.py.
+"""
+
+import unittest
+from types import ClassType
+import DocutilsTestSupport # must be imported before docutils
+from DocutilsTestSupport import nodes, utils
+
+debug = 0
+
+
+class TextTests(unittest.TestCase):
+
+ def setUp(self):
+ self.text = nodes.Text('Line 1.\nLine 2.')
+
+ def test_repr(self):
+ self.assertEquals(repr(self.text), r"<#text: 'Line 1.\nLine 2.'>")
+
+ def test_str(self):
+ self.assertEquals(str(self.text), 'Line 1.\nLine 2.')
+
+ def test_astext(self):
+ self.assertEquals(self.text.astext(), 'Line 1.\nLine 2.')
+
+ def test_pformat(self):
+ self.assertEquals(self.text.pformat(), 'Line 1.\nLine 2.\n')
+
+
+class ElementTests(unittest.TestCase):
+
+ def test_empty(self):
+ element = nodes.Element()
+ self.assertEquals(repr(element), '<Element: >')
+ self.assertEquals(str(element), '<Element/>')
+ dom = element.asdom()
+ self.assertEquals(dom.toxml(), '<Element/>')
+ dom.unlink()
+ element['attr'] = '1'
+ self.assertEquals(repr(element), '<Element: >')
+ self.assertEquals(str(element), '<Element attr="1"/>')
+ dom = element.asdom()
+ self.assertEquals(dom.toxml(), '<Element attr="1"/>')
+ dom.unlink()
+ self.assertEquals(element.pformat(), '<Element attr="1">\n')
+ del element['attr']
+ element['mark'] = u'\u2022'
+ self.assertEquals(repr(element), '<Element: >')
+ self.assertEquals(str(element), '<Element mark="\\u2022"/>')
+ dom = element.asdom()
+ self.assertEquals(dom.toxml(), u'<Element mark="\u2022"/>')
+ dom.unlink()
+
+ def test_withtext(self):
+ element = nodes.Element('text\nmore', nodes.Text('text\nmore'))
+ self.assertEquals(repr(element), r"<Element: <#text: 'text\nmore'>>")
+ self.assertEquals(str(element), '<Element>text\nmore</Element>')
+ dom = element.asdom()
+ self.assertEquals(dom.toxml(), '<Element>text\nmore</Element>')
+ dom.unlink()
+ element['attr'] = '1'
+ self.assertEquals(repr(element), r"<Element: <#text: 'text\nmore'>>")
+ self.assertEquals(str(element),
+ '<Element attr="1">text\nmore</Element>')
+ dom = element.asdom()
+ self.assertEquals(dom.toxml(),
+ '<Element attr="1">text\nmore</Element>')
+ dom.unlink()
+ self.assertEquals(element.pformat(),
+ '<Element attr="1">\n text\n more\n')
+
+ def test_clear(self):
+ element = nodes.Element()
+ element += nodes.Element()
+ self.assert_(len(element))
+ element.clear()
+ self.assert_(not len(element))
+
+ def test_normal_attributes(self):
+ element = nodes.Element()
+ self.assert_(not element.has_key('foo'))
+ self.assertRaises(KeyError, element.__getitem__, 'foo')
+ element['foo'] = 'sometext'
+ self.assertEquals(element['foo'], 'sometext')
+ del element['foo']
+ self.assertRaises(KeyError, element.__getitem__, 'foo')
+
+ def test_default_attributes(self):
+ element = nodes.Element()
+ self.assertEquals(element['ids'], [])
+ self.assertEquals(element.non_default_attributes(), {})
+ self.assert_(not element.is_not_default('ids'))
+ self.assert_(element['ids'] is not nodes.Element()['ids'])
+ element['ids'].append('someid')
+ self.assertEquals(element['ids'], ['someid'])
+ self.assertEquals(element.non_default_attributes(),
+ {'ids': ['someid']})
+ self.assert_(element.is_not_default('ids'))
+
+ def test_update_basic_atts(self):
+ element1 = nodes.Element(ids=['foo', 'bar'], test=['test1'])
+ element2 = nodes.Element(ids=['baz', 'qux'], test=['test2'])
+ element1.update_basic_atts(element2)
+ # 'ids' are appended because 'ids' is a basic attribute.
+ self.assertEquals(element1['ids'], ['foo', 'bar', 'baz', 'qux'])
+ # 'test' is not overwritten because it is not a basic attribute.
+ self.assertEquals(element1['test'], ['test1'])
+
+ def test_replace_self(self):
+ parent = nodes.Element(ids=['parent'])
+ child1 = nodes.Element(ids=['child1'])
+ grandchild = nodes.Element(ids=['grandchild'])
+ child1 += grandchild
+ child2 = nodes.Element(ids=['child2'])
+ twins = [nodes.Element(ids=['twin%s' % i]) for i in (1, 2)]
+ child2 += twins
+ child3 = nodes.Element(ids=['child3'])
+ child4 = nodes.Element(ids=['child4'])
+ parent += [child1, child2, child3, child4]
+ self.assertEquals(parent.pformat(), """\
+<Element ids="parent">
+ <Element ids="child1">
+ <Element ids="grandchild">
+ <Element ids="child2">
+ <Element ids="twin1">
+ <Element ids="twin2">
+ <Element ids="child3">
+ <Element ids="child4">
+""")
+ # Replace child1 with the grandchild.
+ child1.replace_self(child1[0])
+ self.assertEquals(parent[0], grandchild)
+ # Assert that 'ids' have been updated.
+ self.assertEquals(grandchild['ids'], ['grandchild', 'child1'])
+ # Replace child2 with its children.
+ child2.replace_self(child2[:])
+ self.assertEquals(parent[1:3], twins)
+ # Assert that 'ids' have been propagated to first child.
+ self.assertEquals(twins[0]['ids'], ['twin1', 'child2'])
+ self.assertEquals(twins[1]['ids'], ['twin2'])
+ # Replace child3 with new child.
+ newchild = nodes.Element(ids=['newchild'])
+ child3.replace_self(newchild)
+ self.assertEquals(parent[3], newchild)
+ self.assertEquals(newchild['ids'], ['newchild', 'child3'])
+ # Crazy but possible case: Substitute child4 for itself.
+ child4.replace_self(child4)
+ # Make sure the 'child4' ID hasn't been duplicated.
+ self.assertEquals(child4['ids'], ['child4'])
+ self.assertEquals(len(parent), 5)
+
+
+class MiscTests(unittest.TestCase):
+
+ def test_node_class_names(self):
+ node_class_names = []
+ for x in dir(nodes):
+ c = getattr(nodes, x)
+ if isinstance(c, ClassType) and issubclass(c, nodes.Node) \
+ and len(c.__bases__) > 1:
+ node_class_names.append(x)
+ node_class_names.sort()
+ nodes.node_class_names.sort()
+ self.assertEquals(node_class_names, nodes.node_class_names)
+
+ ids = [('a', 'a'), ('A', 'a'), ('', ''), ('a b \n c', 'a-b-c'),
+ ('a.b.c', 'a-b-c'), (' - a - b - c - ', 'a-b-c'), (' - ', ''),
+ (u'\u2020\u2066', ''), (u'a \xa7 b \u2020 c', 'a-b-c'),
+ ('1', ''), ('1abc', 'abc')]
+
+ def test_make_id(self):
+ for input, output in self.ids:
+ normed = nodes.make_id(input)
+ self.assertEquals(normed, output)
+
+ def test_traverse(self):
+ e = nodes.Element()
+ e += nodes.Element()
+ e[0] += nodes.Element()
+ e[0] += nodes.TextElement()
+ e[0][1] += nodes.Text('some text')
+ e += nodes.Element()
+ e += nodes.Element()
+ self.assertEquals(list(e.traverse()),
+ [e, e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
+ self.assertEquals(list(e.traverse(include_self=0)),
+ [e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
+ self.assertEquals(list(e.traverse(descend=0)),
+ [e])
+ self.assertEquals(list(e[0].traverse(descend=0, ascend=1)),
+ [e[0], e[1], e[2]])
+ self.assertEquals(list(e[0][0].traverse(descend=0, ascend=1)),
+ [e[0][0], e[0][1], e[1], e[2]])
+ self.assertEquals(list(e[0][0].traverse(descend=0, siblings=1)),
+ [e[0][0], e[0][1]])
+ self.testlist = e[0:2]
+ self.assertEquals(list(e.traverse(condition=self.not_in_testlist)),
+ [e, e[0][0], e[0][1], e[0][1][0], e[2]])
+ # Return siblings despite siblings=0 because ascend is true.
+ self.assertEquals(list(e[1].traverse(ascend=1, siblings=0)),
+ [e[1], e[2]])
+ self.assertEquals(list(e[0].traverse()),
+ [e[0], e[0][0], e[0][1], e[0][1][0]])
+ self.testlist = [e[0][0], e[0][1]]
+ self.assertEquals(list(e[0].traverse(condition=self.not_in_testlist)),
+ [e[0], e[0][1][0]])
+ self.testlist.append(e[0][1][0])
+ self.assertEquals(list(e[0].traverse(condition=self.not_in_testlist)),
+ [e[0]])
+ self.assertEquals(list(e.traverse(nodes.TextElement)), [e[0][1]])
+
+ def test_next_node(self):
+ e = nodes.Element()
+ e += nodes.Element()
+ e[0] += nodes.Element()
+ e[0] += nodes.TextElement()
+ e[0][1] += nodes.Text('some text')
+ e += nodes.Element()
+ e += nodes.Element()
+ self.testlist = [e[0], e[0][1], e[1]]
+ compare = [(e, e[0][0]),
+ (e[0], e[0][0]),
+ (e[0][0], e[0][1][0]),
+ (e[0][1], e[0][1][0]),
+ (e[0][1][0], e[2]),
+ (e[1], e[2]),
+ (e[2], None)]
+ for node, next_node in compare:
+ self.assertEquals(node.next_node(self.not_in_testlist, ascend=1),
+ next_node)
+ self.assertEquals(e[0][0].next_node(ascend=1), e[0][1])
+ self.assertEquals(e[2].next_node(), None)
+
+ def not_in_testlist(self, x):
+ return x not in self.testlist
+
+ def test_copy(self):
+ grandchild = nodes.Text('rawsource')
+ child = nodes.emphasis('rawsource', grandchild, att='child')
+ e = nodes.Element('rawsource', child, att='e')
+ # Shallow copy:
+ e_copy = e.copy()
+ self.assert_(e is not e_copy)
+ # Internal attributes (like `rawsource`) are not copied.
+ self.assertEquals(e.rawsource, 'rawsource')
+ self.assertEquals(e_copy.rawsource, '')
+ self.assertEquals(e_copy['att'], 'e')
+ # Children are not copied.
+ self.assertEquals(len(e_copy), 0)
+ # Deep copy:
+ e_deepcopy = e.deepcopy()
+ self.assertEquals(e_deepcopy.rawsource, '')
+ self.assertEquals(e_deepcopy['att'], 'e')
+ # Children are copied recursively.
+ self.assertEquals(e_deepcopy[0][0], grandchild)
+ self.assert_(e_deepcopy[0][0] is not grandchild)
+ self.assertEquals(e_deepcopy[0]['att'], 'child')
+
+
+class TreeCopyVisitorTests(unittest.TestCase):
+
+ def setUp(self):
+ document = utils.new_document('test data')
+ document += nodes.paragraph('', 'Paragraph 1.')
+ blist = nodes.bullet_list()
+ for i in range(1, 6):
+ item = nodes.list_item()
+ for j in range(1, 4):
+ item += nodes.paragraph('', 'Item %s, paragraph %s.' % (i, j))
+ blist += item
+ document += blist
+ self.document = document
+
+ def compare_trees(self, one, two):
+ self.assertEquals(one.__class__, two.__class__)
+ self.assertNotEquals(id(one), id(two))
+ self.assertEquals(len(one.children), len(two.children))
+ for i in range(len(one.children)):
+ self.compare_trees(one.children[i], two.children[i])
+
+ def test_copy_whole(self):
+ visitor = nodes.TreeCopyVisitor(self.document)
+ self.document.walkabout(visitor)
+ newtree = visitor.get_tree_copy()
+ self.assertEquals(self.document.pformat(), newtree.pformat())
+ self.compare_trees(self.document, newtree)
+
+
+class MiscFunctionTests(unittest.TestCase):
+
+ names = [('a', 'a'), ('A', 'a'), ('A a A', 'a a a'),
+ ('A a A a', 'a a a a'),
+ (' AaA\n\r\naAa\tAaA\t\t', 'aaa aaa aaa')]
+
+ def test_normalize_name(self):
+ for input, output in self.names:
+ normed = nodes.fully_normalize_name(input)
+ self.assertEquals(normed, output)
+
+ def test_set_id_default(self):
+ # Default prefixes.
+ document = utils.new_document('test')
+ # From name.
+ element = nodes.Element(names=['test'])
+ document.set_id(element)
+ self.assertEquals(element['ids'], ['test'])
+ # Auto-generated.
+ element = nodes.Element()
+ document.set_id(element)
+ self.assertEquals(element['ids'], ['id1'])
+
+ def test_set_id_custom(self):
+ # Custom prefixes.
+ document = utils.new_document('test')
+ # Change settings.
+ document.settings.id_prefix = 'prefix'
+ document.settings.auto_id_prefix = 'auto'
+ # From name.
+ element = nodes.Element(names=['test'])
+ document.set_id(element)
+ self.assertEquals(element['ids'], ['prefixtest'])
+ # Auto-generated.
+ element = nodes.Element()
+ document.set_id(element)
+ self.assertEquals(element['ids'], ['prefixauto1'])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_parsers/__init__.py b/test/test_parsers/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_parsers/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_parsers/test_rst/__init__.py b/test/test_parsers/test_rst/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_parsers/test_rst/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_parsers/test_rst/includes/include9.txt b/test/test_parsers/test_rst/includes/include9.txt
new file mode 100644
index 000000000..9164722b3
--- /dev/null
+++ b/test/test_parsers/test_rst/includes/include9.txt
@@ -0,0 +1,3 @@
+In ../includes/include9.txt.
+
+.. include:: ../test_directives/include2.txt
diff --git a/test/test_parsers/test_rst/test_SimpleTableParser.py b/test/test_parsers/test_rst/test_SimpleTableParser.py
new file mode 100755
index 000000000..aee037206
--- /dev/null
+++ b/test/test_parsers/test_rst/test_SimpleTableParser.py
@@ -0,0 +1,123 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.SimpleTableParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['simple_tables'] = [
+["""\
+============ ============
+A table with two columns.
+============ ============
+""",
+([12, 12],
+ [],
+ [[[0, 0, 1, ['A table with']],
+ [0, 0, 1, ['two columns.']]]])],
+["""\
+============ ============
+A table with two columns
+and two rows.
+============ ============
+""",
+([12, 12],
+ [],
+ [[[0, 0, 1, ['A table with']],
+ [0, 0, 1, ['two columns']]],
+ [[0, 0, 2, ['and']],
+ [0, 0, 2, ['two rows.']]]])],
+["""\
+========== ===========
+A table with four rows,
+-----------------------
+and two columns.
+First and last rows
+contain column spans.
+=======================
+""",
+([10, 11],
+ [],
+ [[[0, 1, 1, ['A table with four rows,']]],
+ [[0, 0, 3, ['and two']],
+ [0, 0, 3, ['columns.']]],
+ [[0, 0, 4, ['First and']],
+ [0, 0, 4, ['last rows']]],
+ [[0, 1, 5, ['contain column spans.']]]])],
+["""\
+======= ===== ======
+A bad table cell 2
+cell 3 cell 4
+============ ======
+""",
+'TableMarkupError: Text in column margin at line offset 1.'],
+["""\
+=========== ================
+A table with two header rows,
+-----------------------------
+the first with a span.
+=========== ================
+Two body rows,
+the second with a span.
+=============================
+""",
+([11, 16],
+ [[[0, 1, 1, ['A table with two header rows,']]],
+ [[0, 0, 3, ['the first']],
+ [0, 0, 3, ['with a span.']]]],
+ [[[0, 0, 5, ['Two body']],
+ [0, 0, 5, ['rows,']]],
+ [[0, 1, 6, ['the second with a span.']]]])],
+["""\
+============ =============
+A table with two head/body
+============ =============
+row separators.
+============ =============
+That's bad.
+============ =============
+""",
+'TableMarkupError: Multiple head/body row separators in table '
+'(at line offset 2 and 4); only one allowed.'],
+["""\
+============ ============
+============ ============
+""",
+([12, 12],
+ [],
+ [[[0, 0, 1, []],
+ [0, 0, 1, []]]])],
+# ["""\
+# ============== ==========
+# Table with row separators
+# ============== ==========
+# and blank
+# -------------- ----------
+# entries
+# -------------- ----------
+# in first
+# -------------- ----------
+# columns.
+# ============== ==========
+# """,
+# '']
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_TableParser.py b/test/test_parsers/test_rst/test_TableParser.py
new file mode 100755
index 000000000..84e4b7563
--- /dev/null
+++ b/test/test_parsers/test_rst/test_TableParser.py
@@ -0,0 +1,207 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.GridTableParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['grid_tables'] = [
+["""\
++-------------------------------------+
+| A table with one cell and one line. |
++-------------------------------------+
+""",
+[(0, 0, 2, 38, ['A table with one cell and one line.'])],
+([37],
+ [],
+ [[(0, 0, 1, ['A table with one cell and one line.'])]])],
+["""\
++--------------+--------------+
+| A table with | two columns. |
++--------------+--------------+
+""",
+[(0, 0, 2, 15, ['A table with']),
+ (0, 15, 2, 30, ['two columns.'])],
+([14, 14],
+ [],
+ [[(0, 0, 1, ['A table with']),
+ (0, 0, 1, ['two columns.'])]])],
+["""\
++--------------+-------------+
+| A table with | two columns |
++--------------+-------------+
+| and | two rows. |
++--------------+-------------+
+""",
+[(0, 0, 2, 15, ['A table with']),
+ (0, 15, 2, 29, ['two columns']),
+ (2, 0, 4, 15, ['and']),
+ (2, 15, 4, 29, ['two rows.'])],
+([14, 13],
+ [],
+ [[(0, 0, 1, ['A table with']),
+ (0, 0, 1, ['two columns'])],
+ [(0, 0, 3, ['and']),
+ (0, 0, 3, ['two rows.'])]])],
+["""\
++--------------------------+
+| A table with three rows, |
++------------+-------------+
+| and two | columns. |
++------------+-------------+
+| First and last rows |
+| contain column spans. |
++--------------------------+
+""",
+[(0, 0, 2, 27, ['A table with three rows,']),
+ (2, 0, 4, 13, ['and two']),
+ (2, 13, 4, 27, ['columns.']),
+ (4, 0, 7, 27, ['First and last rows', 'contain column spans.'])],
+([12, 13],
+ [],
+ [[(0, 1, 1, ['A table with three rows,']),
+ None],
+ [(0, 0, 3, ['and two']),
+ (0, 0, 3, ['columns.'])],
+ [(0, 1, 5, ['First and last rows', 'contain column spans.']),
+ None]])],
+["""\
++------------+-------------+---------------+
+| A table | two rows in | and row spans |
+| with three +-------------+ to left and |
+| columns, | the middle, | right. |
++------------+-------------+---------------+
+""",
+[(0, 0, 4, 13, ['A table', 'with three', 'columns,']),
+ (0, 13, 2, 27, ['two rows in']),
+ (0, 27, 4, 43, ['and row spans', 'to left and', 'right.']),
+ (2, 13, 4, 27, ['the middle,'])],
+([12, 13, 15],
+ [],
+ [[(1, 0, 1, ['A table', 'with three', 'columns,']),
+ (0, 0, 1, ['two rows in']),
+ (1, 0, 1, ['and row spans', 'to left and', 'right.'])],
+ [None,
+ (0, 0, 3, ['the middle,']),
+ None]])],
+["""\
++------------+-------------+---------------+
+| A table | | two rows in | and funny |
+| with 3 +--+-------------+-+ stuff. |
+| columns, | the middle, | | |
++------------+-------------+---------------+
+""",
+[(0, 0, 4, 13, ['A table |', 'with 3 +--', 'columns,']),
+ (0, 13, 2, 27, ['two rows in']),
+ (0, 27, 4, 43, [' and funny', '-+ stuff.', ' |']),
+ (2, 13, 4, 27, ['the middle,'])],
+([12, 13, 15],
+ [],
+ [[(1, 0, 1, ['A table |', 'with 3 +--', 'columns,']),
+ (0, 0, 1, ['two rows in']),
+ (1, 0, 1, [' and funny', '-+ stuff.', ' |'])],
+ [None,
+ (0, 0, 3, ['the middle,']),
+ None]])],
+["""\
++-----------+-------------------------+
+| W/NW cell | N/NE cell |
+| +-------------+-----------+
+| | Middle cell | E/SE cell |
++-----------+-------------+ |
+| S/SE cell | |
++-------------------------+-----------+
+""",
+[(0, 0, 4, 12, ['W/NW cell', '', '']),
+ (0, 12, 2, 38, ['N/NE cell']),
+ (2, 12, 4, 26, ['Middle cell']),
+ (2, 26, 6, 38, ['E/SE cell', '', '']),
+ (4, 0, 6, 26, ['S/SE cell'])],
+([11, 13, 11],
+ [],
+ [[(1, 0, 1, ['W/NW cell', '', '']),
+ (0, 1, 1, ['N/NE cell']),
+ None],
+ [None,
+ (0, 0, 3, ['Middle cell']),
+ (1, 0, 3, ['E/SE cell', '', ''])],
+ [(0, 1, 5, ['S/SE cell']),
+ None,
+ None]])],
+["""\
++--------------+-------------+
+| A bad table. | |
++--------------+ |
+| Cells must be rectangles. |
++----------------------------+
+""",
+'TableMarkupError: Malformed table; parse incomplete.',
+'TableMarkupError: Malformed table; parse incomplete.'],
+["""\
++-------------------------------+
+| A table with two header rows, |
++------------+------------------+
+| the first | with a span. |
++============+==================+
+| Two body | rows, |
++------------+------------------+
+| the second with a span. |
++-------------------------------+
+""",
+[(0, 0, 2, 32, ['A table with two header rows,']),
+ (2, 0, 4, 13, ['the first']),
+ (2, 13, 4, 32, ['with a span.']),
+ (4, 0, 6, 13, ['Two body']),
+ (4, 13, 6, 32, ['rows,']),
+ (6, 0, 8, 32, ['the second with a span.'])],
+([12, 18],
+ [[(0, 1, 1, ['A table with two header rows,']),
+ None],
+ [(0, 0, 3, ['the first']),
+ (0, 0, 3, ['with a span.'])]],
+ [[(0, 0, 5, ['Two body']),
+ (0, 0, 5, ['rows,'])],
+ [(0, 1, 7, ['the second with a span.']),
+ None]])],
+["""\
++-------------------------------+
+| A table with two head/body |
++=============+=================+
+| row | separators. |
++=============+=================+
+| That's bad. | |
++-------------+-----------------+
+""",
+'TableMarkupError: Multiple head/body row separators in table '
+'(at line offset 2 and 4); only one allowed.',
+'TableMarkupError: Multiple head/body row separators in table '
+'(at line offset 2 and 4); only one allowed.'],
+["""\
++-------------------------------------+
+| |
++-------------------------------------+
+""",
+[(0, 0, 2, 38, [''])],
+([37],
+ [],
+ [[(0, 0, 1, [''])]])],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_block_quotes.py b/test/test_parsers/test_rst/test_block_quotes.py
new file mode 100755
index 000000000..dd7561723
--- /dev/null
+++ b/test/test_parsers/test_rst/test_block_quotes.py
@@ -0,0 +1,273 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['block_quotes'] = [
+["""\
+Line 1.
+Line 2.
+
+ Indented.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Line 1.
+ Line 2.
+ <block_quote>
+ <paragraph>
+ Indented.
+"""],
+["""\
+Line 1.
+Line 2.
+
+ Indented 1.
+
+ Indented 2.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Line 1.
+ Line 2.
+ <block_quote>
+ <paragraph>
+ Indented 1.
+ <block_quote>
+ <paragraph>
+ Indented 2.
+"""],
+["""\
+Line 1.
+Line 2.
+ Unexpectedly indented.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Line 1.
+ Line 2.
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Unexpected indentation.
+ <block_quote>
+ <paragraph>
+ Unexpectedly indented.
+"""],
+["""\
+Line 1.
+Line 2.
+
+ Indented.
+no blank line
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Line 1.
+ Line 2.
+ <block_quote>
+ <paragraph>
+ Indented.
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Block quote ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+"""],
+["""\
+Here is a paragraph.
+
+ Indent 8 spaces.
+
+ Indent 4 spaces.
+
+Is this correct? Should it generate a warning?
+Yes, it is correct, no warning necessary.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here is a paragraph.
+ <block_quote>
+ <block_quote>
+ <paragraph>
+ Indent 8 spaces.
+ <paragraph>
+ Indent 4 spaces.
+ <paragraph>
+ Is this correct? Should it generate a warning?
+ Yes, it is correct, no warning necessary.
+"""],
+["""\
+Paragraph.
+
+ Block quote.
+
+ -- Attribution
+
+Paragraph.
+
+ Block quote.
+
+ --Attribution
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution
+"""],
+[u"""\
+Alternative: true em-dash.
+
+ Block quote.
+
+ \u2014 Attribution
+
+Alternative: three hyphens.
+
+ Block quote.
+
+ --- Attribution
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Alternative: true em-dash.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution
+ <paragraph>
+ Alternative: three hyphens.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution
+"""],
+["""\
+Paragraph.
+
+ Block quote.
+
+ -- Attribution line one
+ and line two
+
+Paragraph.
+
+ Block quote.
+
+ -- Attribution line one
+ and line two
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution line one
+ and line two
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <attribution>
+ Attribution line one
+ and line two
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Paragraph.
+
+ -- Not an attribution
+
+Paragraph.
+
+ Block quote.
+
+ \-- Not an attribution
+
+Paragraph.
+
+ Block quote.
+
+ -- Not an attribution line one
+ and line two
+ and line three
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ -- Not an attribution
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <paragraph>
+ -- Not an attribution
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <definition_list>
+ <definition_list_item>
+ <term>
+ -- Not an attribution line one
+ <definition>
+ <definition_list>
+ <definition_list_item>
+ <term>
+ and line two
+ <definition>
+ <paragraph>
+ and line three
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_bullet_lists.py b/test/test_parsers/test_rst/test_bullet_lists.py
new file mode 100755
index 000000000..12ede6cf1
--- /dev/null
+++ b/test/test_parsers/test_rst/test_bullet_lists.py
@@ -0,0 +1,181 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['bullet_lists'] = [
+["""\
+- item
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item
+"""],
+["""\
+* item 1
+
+* item 2
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ item 1
+ <list_item>
+ <paragraph>
+ item 2
+"""],
+["""\
+No blank line between:
+
++ item 1
++ item 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ No blank line between:
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ item 1
+ <list_item>
+ <paragraph>
+ item 2
+"""],
+["""\
+- item 1, para 1.
+
+ item 1, para 2.
+
+- item 2
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item 1, para 1.
+ <paragraph>
+ item 1, para 2.
+ <list_item>
+ <paragraph>
+ item 2
+"""],
+["""\
+- item 1, line 1
+ item 1, line 2
+- item 2
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item 1, line 1
+ item 1, line 2
+ <list_item>
+ <paragraph>
+ item 2
+"""],
+["""\
+Different bullets:
+
+- item 1
+
++ item 2
+
+* item 3
+- item 4
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Different bullets:
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item 1
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ item 2
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ item 3
+ <system_message level="2" line="8" source="test data" type="WARNING">
+ <paragraph>
+ Bullet list ends without a blank line; unexpected unindent.
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item 4
+"""],
+["""\
+- item
+no blank line
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ item
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Bullet list ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+"""],
+["""\
+-
+
+empty item above
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ empty item above
+"""],
+["""\
+-
+empty item above, no blank line
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="-">
+ <list_item>
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Bullet list ends without a blank line; unexpected unindent.
+ <paragraph>
+ empty item above, no blank line
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_citations.py b/test/test_parsers/test_rst/test_citations.py
new file mode 100755
index 000000000..c50e28e0b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_citations.py
@@ -0,0 +1,139 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['citations'] = [
+["""\
+.. [citation] This is a citation.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation" names="citation">
+ <label>
+ citation
+ <paragraph>
+ This is a citation.
+"""],
+["""\
+.. [citation1234] This is a citation with year.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation1234" names="citation1234">
+ <label>
+ citation1234
+ <paragraph>
+ This is a citation with year.
+"""],
+["""\
+.. [citation] This is a citation
+ on multiple lines.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation" names="citation">
+ <label>
+ citation
+ <paragraph>
+ This is a citation
+ on multiple lines.
+"""],
+["""\
+.. [citation1] This is a citation
+ on multiple lines with more space.
+
+.. [citation2] This is a citation
+ on multiple lines with less space.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation1" names="citation1">
+ <label>
+ citation1
+ <paragraph>
+ This is a citation
+ on multiple lines with more space.
+ <citation ids="citation2" names="citation2">
+ <label>
+ citation2
+ <paragraph>
+ This is a citation
+ on multiple lines with less space.
+"""],
+["""\
+.. [citation]
+ This is a citation on multiple lines
+ whose block starts on line 2.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation" names="citation">
+ <label>
+ citation
+ <paragraph>
+ This is a citation on multiple lines
+ whose block starts on line 2.
+"""],
+["""\
+.. [citation]
+
+That was an empty citation.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation" names="citation">
+ <label>
+ citation
+ <paragraph>
+ That was an empty citation.
+"""],
+["""\
+.. [citation]
+No blank line.
+""",
+"""\
+<document source="test data">
+ <citation ids="citation" names="citation">
+ <label>
+ citation
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ No blank line.
+"""],
+["""\
+.. [citation label with spaces] this isn't a citation
+
+.. [*citationlabelwithmarkup*] this isn't a citation
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ [citation label with spaces] this isn't a citation
+ <comment xml:space="preserve">
+ [*citationlabelwithmarkup*] this isn't a citation
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_comments.py b/test/test_parsers/test_rst/test_comments.py
new file mode 100755
index 000000000..a90135ec5
--- /dev/null
+++ b/test/test_parsers/test_rst/test_comments.py
@@ -0,0 +1,319 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['comments'] = [
+["""\
+.. A comment
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. A comment
+ block.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment
+ block.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+..
+ A comment consisting of multiple lines
+ starting on the line after the
+ explicit markup start.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment consisting of multiple lines
+ starting on the line after the
+ explicit markup start.
+"""],
+["""\
+.. A comment.
+.. Another.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment.
+ <comment xml:space="preserve">
+ Another.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. A comment
+no blank line
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. A comment.
+.. Another.
+no blank line
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment.
+ <comment xml:space="preserve">
+ Another.
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. A comment::
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment::
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+..
+ comment::
+
+The extra newline before the comment text prevents
+the parser from recognizing a directive.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ comment::
+ <paragraph>
+ The extra newline before the comment text prevents
+ the parser from recognizing a directive.
+"""],
+["""\
+..
+ _comment: http://example.org
+
+The extra newline before the comment text prevents
+the parser from recognizing a hyperlink target.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ _comment: http://example.org
+ <paragraph>
+ The extra newline before the comment text prevents
+ the parser from recognizing a hyperlink target.
+"""],
+["""\
+..
+ [comment] Not a citation.
+
+The extra newline before the comment text prevents
+the parser from recognizing a citation.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ [comment] Not a citation.
+ <paragraph>
+ The extra newline before the comment text prevents
+ the parser from recognizing a citation.
+"""],
+["""\
+..
+ |comment| image:: bogus.png
+
+The extra newline before the comment text prevents
+the parser from recognizing a substitution definition.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ |comment| image:: bogus.png
+ <paragraph>
+ The extra newline before the comment text prevents
+ the parser from recognizing a substitution definition.
+"""],
+["""\
+.. Next is an empty comment, which serves to end this comment and
+ prevents the following block quote being swallowed up.
+
+..
+
+ A block quote.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ Next is an empty comment, which serves to end this comment and
+ prevents the following block quote being swallowed up.
+ <comment xml:space="preserve">
+ <block_quote>
+ <paragraph>
+ A block quote.
+"""],
+["""\
+term 1
+ definition 1
+
+ .. a comment
+
+term 2
+ definition 2
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1
+ <comment xml:space="preserve">
+ a comment
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+"""],
+["""\
+term 1
+ definition 1
+
+.. a comment
+
+term 2
+ definition 2
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1
+ <comment xml:space="preserve">
+ a comment
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+"""],
+["""\
++ bullet paragraph 1
+
+ bullet paragraph 2
+
+ .. comment between bullet paragraphs 2 and 3
+
+ bullet paragraph 3
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ bullet paragraph 1
+ <paragraph>
+ bullet paragraph 2
+ <comment xml:space="preserve">
+ comment between bullet paragraphs 2 and 3
+ <paragraph>
+ bullet paragraph 3
+"""],
+["""\
++ bullet paragraph 1
+
+ .. comment between bullet paragraphs 1 (leader) and 2
+
+ bullet paragraph 2
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ bullet paragraph 1
+ <comment xml:space="preserve">
+ comment between bullet paragraphs 1 (leader) and 2
+ <paragraph>
+ bullet paragraph 2
+"""],
+["""\
++ bullet
+
+ .. trailing comment
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ bullet
+ <comment xml:space="preserve">
+ trailing comment
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_definition_lists.py b/test/test_parsers/test_rst/test_definition_lists.py
new file mode 100755
index 000000000..d9f3211c0
--- /dev/null
+++ b/test/test_parsers/test_rst/test_definition_lists.py
@@ -0,0 +1,395 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['definition_lists'] = [
+["""\
+term
+ definition
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term
+ <definition>
+ <paragraph>
+ definition
+"""],
+["""\
+term
+ definition
+
+paragraph
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term
+ <definition>
+ <paragraph>
+ definition
+ <paragraph>
+ paragraph
+"""],
+["""\
+term
+ definition
+no blank line
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term
+ <definition>
+ <paragraph>
+ definition
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Definition list ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+"""],
+["""\
+A paragraph::
+ A literal block without a blank line first?
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ A paragraph::
+ <definition>
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Blank line missing before literal block (after the "::")? Interpreted as a definition list item.
+ <paragraph>
+ A literal block without a blank line first?
+"""],
+["""\
+this is not a term;
+a term may only be one line long
+ this is not a definition
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ this is not a term;
+ a term may only be one line long
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Unexpected indentation.
+ <block_quote>
+ <paragraph>
+ this is not a definition
+"""],
+["""\
+term 1
+ definition 1
+
+term 2
+ definition 2
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+"""],
+["""\
+term 1
+ definition 1 (no blank line below)
+term 2
+ definition 2
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1 (no blank line below)
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+"""],
+["""\
+term 1
+ definition 1 (no blank line below)
+term 2
+ definition 2
+No blank line after the definition list.
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1 (no blank line below)
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Definition list ends without a blank line; unexpected unindent.
+ <paragraph>
+ No blank line after the definition list.
+"""],
+["""\
+term 1
+ definition 1
+
+ term 1a
+ definition 1a
+
+ term 1b
+ definition 1b
+
+term 2
+ definition 2
+
+paragraph
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1
+ <definition>
+ <paragraph>
+ definition 1
+ <definition_list>
+ <definition_list_item>
+ <term>
+ term 1a
+ <definition>
+ <paragraph>
+ definition 1a
+ <definition_list_item>
+ <term>
+ term 1b
+ <definition>
+ <paragraph>
+ definition 1b
+ <definition_list_item>
+ <term>
+ term 2
+ <definition>
+ <paragraph>
+ definition 2
+ <paragraph>
+ paragraph
+"""],
+["""\
+Term : classifier
+ The ' : ' indicates a classifier in
+ definition list item terms only.
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ Term
+ <classifier>
+ classifier
+ <definition>
+ <paragraph>
+ The ' : ' indicates a classifier in
+ definition list item terms only.
+"""],
+["""\
+Term: not a classifier
+ Because there's no space before the colon.
+Term :not a classifier
+ Because there's no space after the colon.
+Term \: not a classifier
+ Because the colon is escaped.
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ Term: not a classifier
+ <definition>
+ <paragraph>
+ Because there's no space before the colon.
+ <definition_list_item>
+ <term>
+ Term :not a classifier
+ <definition>
+ <paragraph>
+ Because there's no space after the colon.
+ <definition_list_item>
+ <term>
+ Term : not a classifier
+ <definition>
+ <paragraph>
+ Because the colon is escaped.
+"""],
+["""\
+``Term : not a classifier``
+ Because the ' : ' is inside an inline literal.
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ <literal>
+ Term : not a classifier
+ <definition>
+ <paragraph>
+ Because the ' : ' is inside an inline literal.
+"""],
+["""\
+Term `with *inline ``text **errors : classifier `with *errors ``too
+ Definition `with *inline ``text **markup errors.
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ Term \n\
+ <problematic ids="id2" refid="id1">
+ `
+ with \n\
+ <problematic ids="id4" refid="id3">
+ *
+ inline \n\
+ <problematic ids="id6" refid="id5">
+ ``
+ text \n\
+ <problematic ids="id8" refid="id7">
+ **
+ errors
+ <classifier>
+ classifier \n\
+ <problematic ids="id10" refid="id9">
+ `
+ with \n\
+ <problematic ids="id12" refid="id11">
+ *
+ errors \n\
+ <problematic ids="id14" refid="id13">
+ ``
+ too
+ <definition>
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+ <system_message backrefs="id4" ids="id3" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <system_message backrefs="id6" ids="id5" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+ <system_message backrefs="id8" ids="id7" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline strong start-string without end-string.
+ <system_message backrefs="id10" ids="id9" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+ <system_message backrefs="id12" ids="id11" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <system_message backrefs="id14" ids="id13" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+ <paragraph>
+ Definition \n\
+ <problematic ids="id16" refid="id15">
+ `
+ with \n\
+ <problematic ids="id18" refid="id17">
+ *
+ inline \n\
+ <problematic ids="id20" refid="id19">
+ ``
+ text \n\
+ <problematic ids="id22" refid="id21">
+ **
+ markup errors.
+ <system_message backrefs="id16" ids="id15" level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+ <system_message backrefs="id18" ids="id17" level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <system_message backrefs="id20" ids="id19" level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+ <system_message backrefs="id22" ids="id21" level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Inline strong start-string without end-string.
+"""],
+["""\
+Term : classifier one : classifier two
+ Definition
+""",
+"""\
+<document source="test data">
+ <definition_list>
+ <definition_list_item>
+ <term>
+ Term
+ <classifier>
+ classifier one
+ <classifier>
+ classifier two
+ <definition>
+ <paragraph>
+ Definition
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/__init__.py b/test/test_parsers/test_rst/test_directives/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_parsers/test_rst/test_directives/empty.txt b/test/test_parsers/test_rst/test_directives/empty.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/empty.txt
diff --git a/test/test_parsers/test_rst/test_directives/include 11.txt b/test/test_parsers/test_rst/test_directives/include 11.txt
new file mode 100644
index 000000000..7b57bd29e
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include 11.txt
@@ -0,0 +1 @@
+some text
diff --git a/test/test_parsers/test_rst/test_directives/include1.txt b/test/test_parsers/test_rst/test_directives/include1.txt
new file mode 100644
index 000000000..82f605320
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include1.txt
@@ -0,0 +1,4 @@
+Inclusion 1
+-----------
+
+This file is used by ``test_include.py``.
diff --git a/test/test_parsers/test_rst/test_directives/include10.txt b/test/test_parsers/test_rst/test_directives/include10.txt
new file mode 100644
index 000000000..8eb5b1720
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include10.txt
@@ -0,0 +1,7 @@
+.. |bad| unicode:: 0xFFFFFFFFF
+
+hi
+-----
+
+hi
+-----
diff --git a/test/test_parsers/test_rst/test_directives/include2.txt b/test/test_parsers/test_rst/test_directives/include2.txt
new file mode 100644
index 000000000..3149a7bf6
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include2.txt
@@ -0,0 +1,5 @@
+Here are some paragraphs
+that can appear at any level.
+
+This file (include2.txt) is used by
+``test_include.py``.
diff --git a/test/test_parsers/test_rst/test_directives/include3.txt b/test/test_parsers/test_rst/test_directives/include3.txt
new file mode 100644
index 000000000..9996a4452
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include3.txt
@@ -0,0 +1,3 @@
+In include3.txt
+
+.. include:: includes/include4.txt
diff --git a/test/test_parsers/test_rst/test_directives/include8.txt b/test/test_parsers/test_rst/test_directives/include8.txt
new file mode 100644
index 000000000..e7fc57a3d
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/include8.txt
@@ -0,0 +1,3 @@
+In include8.txt
+
+.. include:: ../includes/include9.txt
diff --git a/test/test_parsers/test_rst/test_directives/includes/include4.txt b/test/test_parsers/test_rst/test_directives/includes/include4.txt
new file mode 100644
index 000000000..384772a77
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/includes/include4.txt
@@ -0,0 +1,3 @@
+In includes/include4.txt
+
+.. include:: include5.txt
diff --git a/test/test_parsers/test_rst/test_directives/includes/include5.txt b/test/test_parsers/test_rst/test_directives/includes/include5.txt
new file mode 100644
index 000000000..64b3e3aa2
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/includes/include5.txt
@@ -0,0 +1,3 @@
+In includes/include5.txt
+
+.. include:: more/include6.txt
diff --git a/test/test_parsers/test_rst/test_directives/includes/more/include6.txt b/test/test_parsers/test_rst/test_directives/includes/more/include6.txt
new file mode 100644
index 000000000..8ac403b01
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/includes/more/include6.txt
@@ -0,0 +1,3 @@
+In includes/more/include6.txt
+
+.. include:: ../sibling/include7.txt
diff --git a/test/test_parsers/test_rst/test_directives/includes/sibling/include7.txt b/test/test_parsers/test_rst/test_directives/includes/sibling/include7.txt
new file mode 100644
index 000000000..fe85aa963
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/includes/sibling/include7.txt
@@ -0,0 +1 @@
+In includes/sibling/include7.txt
diff --git a/test/test_parsers/test_rst/test_directives/raw1.txt b/test/test_parsers/test_rst/test_directives/raw1.txt
new file mode 100644
index 000000000..7ea03651b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/raw1.txt
@@ -0,0 +1 @@
+<p>This file is used by <tt>test_raw.py</tt>.</p>
diff --git a/test/test_parsers/test_rst/test_directives/test_admonitions.py b/test/test_parsers/test_rst/test_directives/test_admonitions.py
new file mode 100755
index 000000000..aaa5aa8d3
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_admonitions.py
@@ -0,0 +1,184 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for admonitions.py directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['admonitions'] = [
+["""\
+.. Attention:: Directives at large.
+
+.. Note:: This is a note.
+
+.. Tip:: 15% if the
+ service is good.
+
+.. Hint:: It's bigger than a bread box.
+
+- .. WARNING:: Strong prose may provoke extreme mental exertion.
+ Reader discretion is strongly advised.
+- .. Error:: Does not compute.
+
+.. Caution::
+
+ Don't take any wooden nickels.
+
+.. DANGER:: Mad scientist at work!
+
+.. Important::
+ - Wash behind your ears.
+ - Clean up your room.
+ - Call your mother.
+ - Back up your data.
+""",
+"""\
+<document source="test data">
+ <attention>
+ <paragraph>
+ Directives at large.
+ <note>
+ <paragraph>
+ This is a note.
+ <tip>
+ <paragraph>
+ 15% if the
+ service is good.
+ <hint>
+ <paragraph>
+ It's bigger than a bread box.
+ <bullet_list bullet="-">
+ <list_item>
+ <warning>
+ <paragraph>
+ Strong prose may provoke extreme mental exertion.
+ Reader discretion is strongly advised.
+ <list_item>
+ <error>
+ <paragraph>
+ Does not compute.
+ <caution>
+ <paragraph>
+ Don't take any wooden nickels.
+ <danger>
+ <paragraph>
+ Mad scientist at work!
+ <important>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Wash behind your ears.
+ <list_item>
+ <paragraph>
+ Clean up your room.
+ <list_item>
+ <paragraph>
+ Call your mother.
+ <list_item>
+ <paragraph>
+ Back up your data.
+"""],
+["""\
+.. note:: One-line notes.
+.. note:: One after the other.
+.. note:: No blank lines in-between.
+""",
+"""\
+<document source="test data">
+ <note>
+ <paragraph>
+ One-line notes.
+ <note>
+ <paragraph>
+ One after the other.
+ <note>
+ <paragraph>
+ No blank lines in-between.
+"""],
+["""\
+.. note::
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ The "note" admonition is empty; content required.
+ <literal_block xml:space="preserve">
+ .. note::
+"""],
+["""\
+.. admonition:: Admonition
+
+ This is a generic admonition.
+""",
+"""\
+<document source="test data">
+ <admonition classes="admonition-admonition">
+ <title>
+ Admonition
+ <paragraph>
+ This is a generic admonition.
+"""],
+["""\
+.. admonition:: And, by the way...
+
+ You can make up your own admonition too.
+""",
+"""\
+<document source="test data">
+ <admonition classes="admonition-and-by-the-way">
+ <title>
+ And, by the way...
+ <paragraph>
+ You can make up your own admonition too.
+"""],
+["""\
+.. admonition:: Admonition
+ :class: emergency
+
+ Test the "class" override.
+""",
+"""\
+<document source="test data">
+ <admonition classes="emergency">
+ <title>
+ Admonition
+ <paragraph>
+ Test the "class" override.
+"""],
+["""\
+.. admonition::
+
+ Generic admonitions require a title.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "admonition" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. admonition::
+
+ Generic admonitions require a title.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_compound.py b/test/test_parsers/test_rst/test_directives/test_compound.py
new file mode 100755
index 000000000..eea4dd53b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_compound.py
@@ -0,0 +1,106 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the 'compound' directive from body.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['compound'] = [
+["""\
+.. compound::
+
+ Compound paragraphs are single logical paragraphs
+ which contain embedded
+
+ * lists
+ * tables
+ * literal blocks
+ * and other body elements
+
+ and are split into multiple physical paragraphs.
+""",
+"""\
+<document source="test data">
+ <compound>
+ <paragraph>
+ Compound paragraphs are single logical paragraphs
+ which contain embedded
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ lists
+ <list_item>
+ <paragraph>
+ tables
+ <list_item>
+ <paragraph>
+ literal blocks
+ <list_item>
+ <paragraph>
+ and other body elements
+ <paragraph>
+ and are split into multiple physical paragraphs.
+"""],
+["""\
+.. compound::
+
+ This is an extremely interesting compound paragraph containing a
+ simple paragraph, a literal block with some useless log messages::
+
+ Connecting... OK
+ Transmitting data... OK
+ Disconnecting... OK
+
+ and another simple paragraph which is actually just a continuation
+ of the first simple paragraph, with the literal block in between.
+""",
+"""\
+<document source="test data">
+ <compound>
+ <paragraph>
+ This is an extremely interesting compound paragraph containing a
+ simple paragraph, a literal block with some useless log messages:
+ <literal_block xml:space="preserve">
+ Connecting... OK
+ Transmitting data... OK
+ Disconnecting... OK
+ <paragraph>
+ and another simple paragraph which is actually just a continuation
+ of the first simple paragraph, with the literal block in between.
+"""],
+["""\
+.. compound:: arg1 arg2
+
+ text
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "compound" directive:
+ no arguments permitted; blank line required before content block.
+ <literal_block xml:space="preserve">
+ .. compound:: arg1 arg2
+ \n\
+ text
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_container.py b/test/test_parsers/test_rst/test_directives/test_container.py
new file mode 100755
index 000000000..3c740611a
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_container.py
@@ -0,0 +1,76 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the 'container' directive from body.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['container'] = [
+["""\
+.. container::
+
+ "container" is a generic element, an extension mechanism for
+ users & applications.
+
+ Containers may contain arbitrary body elements.
+""",
+"""\
+<document source="test data">
+ <container>
+ <paragraph>
+ "container" is a generic element, an extension mechanism for
+ users & applications.
+ <paragraph>
+ Containers may contain arbitrary body elements.
+"""],
+["""\
+.. container:: custom
+
+ Some text.
+""",
+"""\
+<document source="test data">
+ <container classes="custom">
+ <paragraph>
+ Some text.
+"""],
+["""\
+.. container:: one two three
+ four
+
+ Multiple classes.
+
+ Multi-line argument.
+
+ Multiple paragraphs in the container.
+""",
+"""\
+<document source="test data">
+ <container classes="one two three four">
+ <paragraph>
+ Multiple classes.
+ <paragraph>
+ Multi-line argument.
+ <paragraph>
+ Multiple paragraphs in the container.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_contents.py b/test/test_parsers/test_rst/test_directives/test_contents.py
new file mode 100755
index 000000000..cb7bbec0f
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_contents.py
@@ -0,0 +1,241 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for parts.py contents directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['contents'] = [
+["""\
+.. contents::
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+["""\
+.. contents:: Table of Contents
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+["""\
+.. contents::
+ Table of Contents
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+["""\
+.. contents:: Table
+ of
+ Contents
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table
+ of
+ Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+["""\
+.. contents:: *Table* of ``Contents``
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ <emphasis>
+ Table
+ of
+ <literal>
+ Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+["""\
+.. contents::
+ :depth: 2
+ :local:
+""",
+"""\
+<document source="test data">
+ <topic classes="contents local" ids="contents" names="contents">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+ depth: 2
+ local: None
+"""],
+["""\
+.. contents::
+ :local: arg
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "contents" directive:
+ invalid option value: (option: "local"; value: 'arg')
+ no argument is allowed; "arg" supplied.
+ <literal_block xml:space="preserve">
+ .. contents::
+ :local: arg
+"""],
+["""\
+.. contents:: Table of Contents
+ :local:
+ :depth: 2
+ :backlinks: none
+""",
+"""\
+<document source="test data">
+ <topic classes="contents local" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+ backlinks: None
+ depth: 2
+ local: None
+"""],
+["""\
+.. contents::
+ :depth: two
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "contents" directive:
+ invalid option value: (option: "depth"; value: 'two')
+ invalid literal for int(): two.
+ <literal_block xml:space="preserve">
+ .. contents::
+ :depth: two
+"""],
+["""\
+.. contents::
+ :width: 2
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "contents" directive:
+ unknown option: "width".
+ <literal_block xml:space="preserve">
+ .. contents::
+ :width: 2
+"""],
+["""\
+.. contents::
+ :backlinks: no way!
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "contents" directive:
+ invalid option value: (option: "backlinks"; value: 'no way!')
+ "no way!" unknown; choose from "top", "entry", or "none".
+ <literal_block xml:space="preserve">
+ .. contents::
+ :backlinks: no way!
+"""],
+["""\
+.. contents::
+ :backlinks:
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "contents" directive:
+ invalid option value: (option: "backlinks"; value: None)
+ must supply an argument; choose from "top", "entry", or "none".
+ <literal_block xml:space="preserve">
+ .. contents::
+ :backlinks:
+"""],
+["""\
+* .. contents::
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="*">
+ <list_item>
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ The "contents" directive may not be used within topics or body elements.
+ <literal_block xml:space="preserve">
+ .. contents::
+"""],
+["""\
+.. sidebar:: containing contents
+
+ .. contents::
+""",
+"""\
+<document source="test data">
+ <sidebar>
+ <title>
+ containing contents
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.parts.Contents
+ .details:
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_date.py b/test/test_parsers/test_rst/test_directives/test_date.py
new file mode 100755
index 000000000..0364331b1
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_date.py
@@ -0,0 +1,53 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the misc.py "date" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+import time
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['date'] = [
+["""\
+.. |date| date::
+
+Today's date is |date|.
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="date">
+ %s
+ <paragraph>
+ Today's date is \n\
+ <substitution_reference refname="date">
+ date
+ .
+""" % time.strftime('%Y-%m-%d')],
+["""\
+.. |date| date:: %a, %d %b %Y
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="date">
+ %s
+""" % time.strftime('%a, %d %b %Y')],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_decorations.py b/test/test_parsers/test_rst/test_directives/test_decorations.py
new file mode 100755
index 000000000..c770c6a49
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_decorations.py
@@ -0,0 +1,93 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the "header" & "footer" directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['headers'] = [
+["""\
+.. header:: a paragraph for the header
+""",
+"""\
+<document source="test data">
+ <decoration>
+ <header>
+ <paragraph>
+ a paragraph for the header
+"""],
+["""\
+.. header::
+""",
+"""\
+<document source="test data">
+ <decoration>
+ <header>
+ <paragraph>
+ Problem with the "header" directive: no content supplied.
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Content block expected for the "header" directive; none found.
+ <literal_block xml:space="preserve">
+ .. header::
+"""],
+["""\
+.. header:: first part of the header
+.. header:: second part of the header
+""",
+"""\
+<document source="test data">
+ <decoration>
+ <header>
+ <paragraph>
+ first part of the header
+ <paragraph>
+ second part of the header
+"""],
+]
+
+totest['footers'] = [
+["""\
+.. footer:: a paragraph for the footer
+""",
+"""\
+<document source="test data">
+ <decoration>
+ <footer>
+ <paragraph>
+ a paragraph for the footer
+"""],
+["""\
+.. footer:: even if a footer is declared first
+.. header:: the header appears first
+""",
+"""\
+<document source="test data">
+ <decoration>
+ <header>
+ <paragraph>
+ the header appears first
+ <footer>
+ <paragraph>
+ even if a footer is declared first
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_default_role.py b/test/test_parsers/test_rst/test_directives/test_default_role.py
new file mode 100755
index 000000000..fc9343247
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_default_role.py
@@ -0,0 +1,84 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "default-role" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['default-role'] = [
+["""\
+.. default-role:: subscript
+
+This is a `subscript`.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ This is a \n\
+ <subscript>
+ subscript
+ .
+"""],
+["""\
+Must define a custom role before using it.
+
+.. default-role:: custom
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Must define a custom role before using it.
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "custom" in module "docutils.parsers.rst.languages.en".
+ Trying "custom" as canonical role name.
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "custom".
+ <literal_block xml:space="preserve">
+ .. default-role:: custom
+"""],
+["""\
+.. role:: custom
+.. default-role:: custom
+
+This text uses the `default role`.
+
+.. default-role::
+
+Returned the `default role` to its standard default.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ This text uses the \n\
+ <inline classes="custom">
+ default role
+ .
+ <paragraph>
+ Returned the \n\
+ <title_reference>
+ default role
+ to its standard default.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_figures.py b/test/test_parsers/test_rst/test_directives/test_figures.py
new file mode 100755
index 000000000..91fd91596
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_figures.py
@@ -0,0 +1,294 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for images.py figure directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['figures'] = [
+["""\
+.. figure:: picture.png
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+"""],
+["""\
+.. figure:: picture.png
+
+ A picture with a caption.
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+"""],
+["""\
+.. figure:: picture.png
+
+ - A picture with an invalid caption.
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Figure caption must be a paragraph or empty comment.
+ <literal_block xml:space="preserve">
+ .. figure:: picture.png
+ \n\
+ - A picture with an invalid caption.
+"""],
+["""\
+.. figure:: picture.png
+
+ ..
+
+ A picture with a legend but no caption.
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+ <legend>
+ <paragraph>
+ A picture with a legend but no caption.
+"""],
+["""\
+.. Figure:: picture.png
+ :height: 100
+ :width: 200
+ :scale: 50
+
+ A picture with image options and a caption.
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image height="100" scale="50" uri="picture.png" width="200">
+ <caption>
+ A picture with image options and a caption.
+"""],
+["""\
+.. Figure:: picture.png
+ :height: 100
+ :alt: alternate text
+ :width: 200
+ :scale: 50
+ :figwidth: 300
+ :figclass: class1 class2
+
+ A picture with image options on individual lines, and this caption.
+""",
+"""\
+<document source="test data">
+ <figure classes="class1 class2" width="300">
+ <image alt="alternate text" height="100" scale="50" uri="picture.png" width="200">
+ <caption>
+ A picture with image options on individual lines, and this caption.
+"""],
+["""\
+.. figure:: picture.png
+ :align: center
+
+ A figure with explicit alignment.
+""",
+"""\
+<document source="test data">
+ <figure align="center">
+ <image uri="picture.png">
+ <caption>
+ A figure with explicit alignment.
+"""],
+["""\
+.. figure:: picture.png
+ :align: top
+
+ A figure with wrong alignment.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "figure" directive:
+ invalid option value: (option: "align"; value: 'top')
+ "top" unknown; choose from "left", "center", or "right".
+ <literal_block xml:space="preserve">
+ .. figure:: picture.png
+ :align: top
+
+ A figure with wrong alignment.
+"""],
+["""\
+This figure lacks a caption. It may still have a
+"Figure 1."-style caption appended in the output.
+
+.. figure:: picture.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ This figure lacks a caption. It may still have a
+ "Figure 1."-style caption appended in the output.
+ <figure>
+ <image uri="picture.png">
+"""],
+["""\
+.. figure:: picture.png
+
+ A picture with a caption and a legend.
+
+ +-----------------------+-----------------------+
+ | Symbol | Meaning |
+ +=======================+=======================+
+ | .. image:: tent.png | Campground |
+ +-----------------------+-----------------------+
+ | .. image:: waves.png | Lake |
+ +-----------------------+-----------------------+
+ | .. image:: peak.png | Mountain |
+ +-----------------------+-----------------------+
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption and a legend.
+ <legend>
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="23">
+ <colspec colwidth="23">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Symbol
+ <entry>
+ <paragraph>
+ Meaning
+ <tbody>
+ <row>
+ <entry>
+ <image uri="tent.png">
+ <entry>
+ <paragraph>
+ Campground
+ <row>
+ <entry>
+ <image uri="waves.png">
+ <entry>
+ <paragraph>
+ Lake
+ <row>
+ <entry>
+ <image uri="peak.png">
+ <entry>
+ <paragraph>
+ Mountain
+"""],
+["""\
+.. figure:: picture.png
+
+ ..
+
+ A picture with a legend but no caption.
+ (The empty comment replaces the caption, which must
+ be a single paragraph.)
+""",
+"""\
+<document source="test data">
+ <figure>
+ <image uri="picture.png">
+ <legend>
+ <paragraph>
+ A picture with a legend but no caption.
+ (The empty comment replaces the caption, which must
+ be a single paragraph.)
+"""],
+["""\
+Testing for line-leaks:
+
+.. figure:: picture.png
+
+ A picture with a caption.
+.. figure:: picture.png
+
+ A picture with a caption.
+.. figure:: picture.png
+
+ A picture with a caption.
+.. figure:: picture.png
+.. figure:: picture.png
+.. figure:: picture.png
+.. figure:: picture.png
+
+ A picture with a caption.
+
+.. figure:: picture.png
+
+.. figure:: picture.png
+
+ A picture with a caption.
+
+.. figure:: picture.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Testing for line-leaks:
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+ <figure>
+ <image uri="picture.png">
+ <figure>
+ <image uri="picture.png">
+ <figure>
+ <image uri="picture.png">
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+ <figure>
+ <image uri="picture.png">
+ <figure>
+ <image uri="picture.png">
+ <caption>
+ A picture with a caption.
+ <figure>
+ <image uri="picture.png">
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_images.py b/test/test_parsers/test_rst/test_directives/test_images.py
new file mode 100755
index 000000000..50f555ba1
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_images.py
@@ -0,0 +1,413 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for images.py image directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['images'] = [
+["""\
+.. image:: picture.png
+""",
+"""\
+<document source="test data">
+ <image uri="picture.png">
+"""],
+["""\
+.. image::
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. image::
+"""],
+["""\
+.. image:: one two three.png
+""",
+"""\
+<document source="test data">
+ <image uri="onetwothree.png">
+"""],
+["""\
+.. image:: picture.png
+ :height: 100
+ :width: 200
+ :scale: 50
+""",
+"""\
+<document source="test data">
+ <image height="100" scale="50" uri="picture.png" width="200">
+"""],
+["""\
+.. image::
+ picture.png
+ :height: 100
+ :width: 200
+ :scale: 50
+""",
+"""\
+<document source="test data">
+ <image height="100" scale="50" uri="picture.png" width="200">
+"""],
+["""\
+.. image::
+ :height: 100
+ :width: 200
+ :scale: 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. image::
+ :height: 100
+ :width: 200
+ :scale: 50
+"""],
+["""\
+.. image:: a/very/long/path/to/
+ picture.png
+ :height: 100
+ :width: 200
+ :scale: 50
+""",
+"""\
+<document source="test data">
+ <image height="100" scale="50" uri="a/very/long/path/to/picture.png" width="200">
+"""],
+["""\
+.. image:: picture.png
+ :width: 200px
+ :height: 100 em
+""",
+"""\
+<document source="test data">
+ <image height="100em" uri="picture.png" width="200px">
+"""],
+["""\
+.. image:: picture.png
+ :width: 50%
+ :height: 10mm
+""",
+"""\
+<document source="test data">
+ <image height="10mm" uri="picture.png" width="50%">
+"""],
+["""\
+.. image:: picture.png
+ :width: 50%
+ :height: 40%
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "height"; value: \'40%\')
+ not a positive measure of one of the following units:
+ "em" "ex" "px" "in" "cm" "mm" "pt" "pc" "".
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :width: 50%
+ :height: 40%
+"""],
+["""\
+.. image:: picture.png
+ :height: 100
+ :width: 200
+ :scale: 50
+ :alt: Alternate text for the picture
+""",
+"""\
+<document source="test data">
+ <image alt="Alternate text for the picture" height="100" scale="50" uri="picture.png" width="200">
+"""],
+["""\
+.. image:: picture.png
+ :scale: - 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "scale"; value: '- 50')
+ negative value; must be positive or zero.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale: - 50
+"""],
+["""\
+.. image:: picture.png
+ :scale:
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "scale"; value: None)
+ %s.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale:
+""" % DocutilsTestSupport.exception_data('int(None)')[1][0]],
+["""\
+.. image:: picture.png
+ :scale 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option block.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale 50
+"""],
+["""\
+.. image:: picture.png
+ scale: 50
+""",
+"""\
+<document source="test data">
+ <image uri="picture.pngscale:50">
+"""],
+["""\
+.. image:: picture.png
+ :: 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option block.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :: 50
+"""],
+["""\
+.. image:: picture.png
+ :sale: 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ unknown option: "sale".
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :sale: 50
+"""],
+["""\
+.. image:: picture.png
+ :scale is: 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option data: extension option field name may not contain multiple words.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale is: 50
+"""],
+["""\
+.. image:: picture.png
+ :scale: fifty
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "scale"; value: 'fifty')
+ invalid literal for int(): fifty.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale: fifty
+"""],
+["""\
+.. image:: picture.png
+ :scale: 50
+ :scale: 50
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option data: duplicate option "scale".
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :scale: 50
+ :scale: 50
+"""],
+["""\
+.. image:: picture.png
+ :alt:
+
+(Empty "alt" option.)
+""",
+"""\
+<document source="test data">
+ <image alt="" uri="picture.png">
+ <paragraph>
+ (Empty "alt" option.)
+"""],
+["""\
+.. image:: picture.png
+ :target: bigpicture.png
+""",
+"""\
+<document source="test data">
+ <reference refuri="bigpicture.png">
+ <image uri="picture.png">
+"""],
+["""\
+.. image:: picture.png
+ :target: indirect_
+""",
+"""\
+<document source="test data">
+ <reference name="indirect" refname="indirect">
+ <image uri="picture.png">
+"""],
+["""\
+.. image:: picture.png
+ :target: a/multi/
+ line/uri
+
+.. image:: picture.png
+ :target: `a multi line
+ internal reference`_
+""",
+"""\
+<document source="test data">
+ <reference refuri="a/multi/line/uri">
+ <image uri="picture.png">
+ <reference name="a multi line internal reference" refname="a multi line internal reference">
+ <image uri="picture.png">
+"""],
+["""\
+.. image:: picture.png
+ :target:
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "target"; value: None)
+ argument required but none supplied.
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :target:
+"""],
+["""\
+.. image:: picture.png
+ :align: left
+""",
+"""\
+<document source="test data">
+ <image align="left" uri="picture.png">
+"""],
+["""\
+.. image:: picture.png
+ :align: top
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive: "top" is not a valid value for the "align" option. Valid values for "align" are: "left", "center", "right".
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :align: top
+"""],
+["""\
+.. |img| image:: picture.png
+ :align: top
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="img">
+ <image align="top" alt="img" uri="picture.png">
+"""],
+["""\
+.. |img| image:: picture.png
+ :align: left
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive: "left" is not a valid value for the "align" option within a substitution definition. Valid values for "align" are: "top", "middle", "bottom".
+ <literal_block xml:space="preserve">
+ image:: picture.png
+ :align: left
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "img" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |img| image:: picture.png
+ :align: left
+"""],
+[u"""\
+.. image:: picture.png
+ :align: \xe4
+""",
+u"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ invalid option value: (option: "align"; value: u\'\\xe4\')
+ "\xe4" unknown; choose from "top", "middle", "bottom", "left", "center", or "right".
+ <literal_block xml:space="preserve">
+ .. image:: picture.png
+ :align: \xe4
+"""],
+["""
+.. image:: test.png
+ :target: Uppercase_
+
+.. _Uppercase: http://docutils.sourceforge.net/
+""",
+"""\
+<document source="test data">
+ <reference name="Uppercase" refname="uppercase">
+ <image uri="test.png">
+ <target ids="uppercase" names="uppercase" refuri="http://docutils.sourceforge.net/">
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_include.py b/test/test_parsers/test_rst/test_directives/test_include.py
new file mode 100755
index 000000000..c9b5f7378
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_include.py
@@ -0,0 +1,412 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "include" directive.
+"""
+
+import os.path
+import sys
+from __init__ import DocutilsTestSupport
+from docutils.parsers.rst import states
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+mydir = 'test_parsers/test_rst/test_directives/'
+include1 = os.path.join(mydir, 'include1.txt')
+include1rel = DocutilsTestSupport.utils.relative_path(None, include1)
+include2 = os.path.join(mydir, 'include2.txt')
+include3 = os.path.join(mydir, 'include3.txt')
+include8 = os.path.join(mydir, 'include8.txt')
+include10 = os.path.join(mydir, 'include10.txt')
+include10rel = DocutilsTestSupport.utils.relative_path(None, include10)
+include11 = os.path.join(mydir, 'include 11.txt')
+include11rel = DocutilsTestSupport.utils.relative_path(None, include11)
+utf_16_file = os.path.join(mydir, 'utf-16.csv')
+utf_16_file_rel = DocutilsTestSupport.utils.relative_path(None, utf_16_file)
+nonexistent = os.path.join(os.path.dirname(states.__file__),
+ 'include', 'nonexistent')
+nonexistent_rel = DocutilsTestSupport.utils.relative_path(
+ os.path.join(DocutilsTestSupport.testroot, 'dummy'), nonexistent)
+
+totest = {}
+
+totest['include'] = [
+["""\
+Include Test
+============
+
+.. include:: %s
+
+A paragraph.
+""" % include1,
+"""\
+<document source="test data">
+ <section ids="include-test" names="include\ test">
+ <title>
+ Include Test
+ <section ids="inclusion-1" names="inclusion\ 1">
+ <title>
+ Inclusion 1
+ <paragraph>
+ This file is used by \n\
+ <literal>
+ test_include.py
+ .
+ <paragraph>
+ A paragraph.
+"""],
+["""\
+Include Test
+============
+
+.. include:: %s
+ :literal:
+
+A paragraph.
+""" % include1,
+"""\
+<document source="test data">
+ <section ids="include-test" names="include\ test">
+ <title>
+ Include Test
+ <literal_block source="%s" xml:space="preserve">
+ Inclusion 1
+ -----------
+ \n\
+ This file is used by ``test_include.py``.
+ <paragraph>
+ A paragraph.
+""" % include1rel],
+["""\
+Let's test the parse context.
+
+ This paragraph is in a block quote.
+
+ .. include:: %s
+
+The included paragraphs should also be in the block quote.
+""" % include2,
+"""\
+<document source="test data">
+ <paragraph>
+ Let's test the parse context.
+ <block_quote>
+ <paragraph>
+ This paragraph is in a block quote.
+ <paragraph>
+ Here are some paragraphs
+ that can appear at any level.
+ <paragraph>
+ This file (include2.txt) is used by
+ <literal>
+ test_include.py
+ .
+ <paragraph>
+ The included paragraphs should also be in the block quote.
+"""],
+["""\
+Include Test
+============
+
+.. include:: nonexistent.txt
+
+A paragraph.
+""",
+"""\
+<document source="test data">
+ <section ids="include-test" names="include\ test">
+ <title>
+ Include Test
+ <system_message level="4" line="4" source="test data" type="SEVERE">
+ <paragraph>
+ Problems with "include" directive path:
+ IOError: [Errno 2] No such file or directory: 'nonexistent.txt'.
+ <literal_block xml:space="preserve">
+ .. include:: nonexistent.txt
+ <paragraph>
+ A paragraph.
+"""],
+["""\
+Include Test
+============
+
+.. include:: %s
+
+.. include:: %s
+
+A paragraph.
+""" % (include1, include1),
+"""\
+<document source="test data">
+ <section ids="include-test" names="include\ test">
+ <title>
+ Include Test
+ <section dupnames="inclusion\ 1" ids="inclusion-1">
+ <title>
+ Inclusion 1
+ <paragraph>
+ This file is used by
+ <literal>
+ test_include.py
+ .
+ <section dupnames="inclusion\ 1" ids="id1">
+ <title>
+ Inclusion 1
+ <system_message backrefs="id1" level="1" line="2" source="%s" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "inclusion 1".
+ <paragraph>
+ This file is used by
+ <literal>
+ test_include.py
+ .
+ <paragraph>
+ A paragraph.
+""" % include1rel],
+["""\
+Include Test
+============
+
+.. include:: %s
+
+----------
+
+.. include:: %s
+
+A paragraph.
+""" % (include1, include1),
+"""\
+<document source="test data">
+ <section ids="include-test" names="include\ test">
+ <title>
+ Include Test
+ <section dupnames="inclusion\ 1" ids="inclusion-1">
+ <title>
+ Inclusion 1
+ <paragraph>
+ This file is used by \n\
+ <literal>
+ test_include.py
+ .
+ <transition>
+ <section dupnames="inclusion\ 1" ids="id1">
+ <title>
+ Inclusion 1
+ <system_message backrefs="id1" level="1" line="2" source="%s" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "inclusion 1".
+ <paragraph>
+ This file is used by \n\
+ <literal>
+ test_include.py
+ .
+ <paragraph>
+ A paragraph.
+""" % include1rel],
+["""\
+In test data
+
+.. include:: %s
+""" % include3,
+"""\
+<document source="test data">
+ <paragraph>
+ In test data
+ <paragraph>
+ In include3.txt
+ <paragraph>
+ In includes/include4.txt
+ <paragraph>
+ In includes/include5.txt
+ <paragraph>
+ In includes/more/include6.txt
+ <paragraph>
+ In includes/sibling/include7.txt
+"""],
+["""\
+In test data
+
+Section
+=======
+
+(Section contents in nested parse; slice of input_lines ViewList.)
+
+.. include:: %s
+""" % include3,
+"""\
+<document source="test data">
+ <paragraph>
+ In test data
+ <section ids="section" names="section">
+ <title>
+ Section
+ <paragraph>
+ (Section contents in nested parse; slice of input_lines ViewList.)
+ <paragraph>
+ In include3.txt
+ <paragraph>
+ In includes/include4.txt
+ <paragraph>
+ In includes/include5.txt
+ <paragraph>
+ In includes/more/include6.txt
+ <paragraph>
+ In includes/sibling/include7.txt
+"""],
+["""\
+Testing relative includes:
+
+.. include:: %s
+""" % include8,
+"""\
+<document source="test data">
+ <paragraph>
+ Testing relative includes:
+ <paragraph>
+ In include8.txt
+ <paragraph>
+ In ../includes/include9.txt.
+ <paragraph>
+ Here are some paragraphs
+ that can appear at any level.
+ <paragraph>
+ This file (include2.txt) is used by
+ <literal>
+ test_include.py
+ .
+"""],
+["""\
+Encoding:
+
+.. include:: %s
+ :encoding: utf-16
+""" % utf_16_file_rel,
+u"""\
+<document source="test data">
+ <paragraph>
+ Encoding:
+ <paragraph>
+ "Treat", "Quantity", "Description"
+ "Albatr\xb0\xdf", 2.99, "\xa1On a \\u03c3\\u03c4\\u03b9\\u03ba!"
+ "Crunchy Frog", 1.49, "If we took the b\xf6nes out, it wouldn\\u2019t be
+ crunchy, now would it?"
+ "Gannet Ripple", 1.99, "\xbfOn a \\u03c3\\u03c4\\u03b9\\u03ba?"
+"""],
+["""\
+Include file is UTF-16-encoded, and is not valid ASCII.
+
+.. include:: %s
+ :encoding: ascii
+""" % utf_16_file_rel,
+"""\
+<document source="test data">
+ <paragraph>
+ Include file is UTF-16-encoded, and is not valid ASCII.
+ <system_message level="4" line="3" source="test data" type="SEVERE">
+ <paragraph>
+ Problem with "include" directive:
+ UnicodeError: Unable to decode input data. Tried the following encodings: 'ascii'.
+ (UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128))
+ <literal_block xml:space="preserve">
+ .. include:: %s
+ :encoding: ascii
+""" % utf_16_file_rel],
+# @@@ BUG with errors reported with incorrect "source" & "line":
+# ["""\
+# Testing bad charent includes:
+#
+# .. include:: %s
+# """ % include10,
+# """\
+# <document source="test data">
+# <paragraph>
+# Testing bad charent includes:
+# <system_message level="3" line="1" source="%s" type="ERROR">
+# <paragraph>
+# Invalid character code: 0xFFFFFFFFF
+# int() literal too large: FFFFFFFFF
+# <literal_block xml:space="preserve">
+# unicode:: 0xFFFFFFFFF
+# <system_message level="2" line="1" source="%s" type="WARNING">
+# <paragraph>
+# Substitution definition "bad" empty or invalid.
+# <literal_block xml:space="preserve">
+# .. |bad| unicode:: 0xFFFFFFFFF
+# """ % (include10rel, include10rel)],
+["""\
+Include file with whitespace in the path:
+
+.. include:: %s
+""" % include11rel,
+"""\
+<document source="test data">
+ <paragraph>
+ Include file with whitespace in the path:
+ <paragraph>
+ some text
+"""],
+["""\
+Standard include data file:
+
+.. include:: <isogrk4.txt>
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Standard include data file:
+ <comment xml:space="preserve">
+ This data file has been placed in the public domain.
+ <comment xml:space="preserve">
+ Derived from the Unicode character mappings available from
+ <http://www.w3.org/2003/entities/xml/>.
+ Processed by unicode2rstsubs.py, part of Docutils:
+ <http://docutils.sourceforge.net>.
+ <substitution_definition names="b.Gammad">
+ \\u03dc
+ <substitution_definition names="b.gammad">
+ \\u03dd
+"""],
+["""\
+Nonexistent standard include data file:
+
+.. include:: <nonexistent>
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Nonexistent standard include data file:
+ <system_message level="4" line="3" source="test data" type="SEVERE">
+ <paragraph>
+ Problems with "include" directive path:
+ IOError: [Errno 2] No such file or directory: '%s'.
+ <literal_block xml:space="preserve">
+ .. include:: <nonexistent>
+""" % nonexistent_rel],
+]
+
+
+# Skip tests whose output contains "UnicodeDecodeError" if we are not
+# using Python 2.3 or higher.
+if sys.version_info < (2, 3):
+ for i in range(len(totest['include'])):
+ if totest['include'][i][1].find('UnicodeDecodeError') != -1:
+ del totest['include'][i]
+ print ("Test totest['include'][%s] skipped; "
+ "Python 2.3+ required for expected output." % i)
+ # Assume we have only one of these tests.
+ break
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_line_blocks.py b/test/test_parsers/test_rst/test_directives/test_line_blocks.py
new file mode 100755
index 000000000..131ceaa05
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_line_blocks.py
@@ -0,0 +1,81 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the body.py 'line-block' directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['line_blocks'] = [
+["""\
+.. line-block::
+
+ This is a line block.
+ Newlines are *preserved*.
+ As is initial whitespace.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ This is a line block.
+ <line>
+ Newlines are \n\
+ <emphasis>
+ preserved
+ .
+ <line_block>
+ <line>
+ As is initial whitespace.
+"""],
+["""\
+.. line-block::
+
+ Inline markup *may not span
+ multiple lines* of a line block.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ Inline markup \n\
+ <problematic ids="id2" refid="id1">
+ *
+ may not span
+ <line_block>
+ <line>
+ multiple lines* of a line block.
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+"""],
+["""\
+.. line-block::
+""",
+"""\
+<document source="test data">
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Content block expected for the "line-block" directive; none found.
+ <literal_block xml:space="preserve">
+ .. line-block::
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_meta.py b/test/test_parsers/test_rst/test_directives/test_meta.py
new file mode 100755
index 000000000..7c8b34002
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_meta.py
@@ -0,0 +1,232 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for html meta directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['meta'] = [
+["""\
+.. meta::
+ :description: The reStructuredText plaintext markup language
+ :keywords: plaintext,markup language
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="The reStructuredText plaintext markup language" name="description">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="plaintext,markup language" name="keywords">
+"""],
+["""\
+.. meta::
+ :description lang=en: An amusing story
+ :description lang=fr: Un histoire amusant
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="An amusing story" lang="en" name="description">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="Un histoire amusant" lang="fr" name="description">
+"""],
+["""\
+.. meta::
+ :http-equiv=Content-Type: text/html; charset=ISO-8859-1
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type">
+"""],
+["""\
+.. meta::
+ :name: content
+ over multiple lines
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="content over multiple lines" name="name">
+"""],
+["""\
+Paragraph
+
+.. meta::
+ :name: content
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="content" name="name">
+"""],
+["""\
+.. meta::
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Empty meta directive.
+ <literal_block xml:space="preserve">
+ .. meta::
+"""],
+["""\
+.. meta::
+ :empty:
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ No content for meta tag "empty".
+ <literal_block xml:space="preserve">
+ :empty:
+"""],
+["""\
+.. meta::
+ not a field list
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid meta directive.
+ <literal_block xml:space="preserve">
+ .. meta::
+ not a field list
+"""],
+["""\
+.. meta::
+ :name: content
+ not a field
+ :name: content
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="content" name="name">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid meta directive.
+ <literal_block xml:space="preserve">
+ .. meta::
+ :name: content
+ not a field
+ :name: content
+"""],
+["""\
+.. meta::
+ :name: content
+ :name: content
+ not a field
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="content" name="name">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.components.Filter
+ .details:
+ component: 'writer'
+ format: 'html'
+ nodes:
+ <meta content="content" name="name">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid meta directive.
+ <literal_block xml:space="preserve">
+ .. meta::
+ :name: content
+ :name: content
+ not a field
+"""],
+["""\
+.. meta::
+ :name notattval: content
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="2" source="test data" type="ERROR">
+ <paragraph>
+ Error parsing meta tag attribute "notattval": missing "=".
+ <literal_block xml:space="preserve">
+ :name notattval: content
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_raw.py b/test/test_parsers/test_rst/test_directives/test_raw.py
new file mode 100755
index 000000000..9e1a17974
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_raw.py
@@ -0,0 +1,154 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "raw" directive.
+"""
+
+import os.path
+import sys
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+mydir = 'test_parsers/test_rst/test_directives/'
+raw1 = os.path.join(mydir, 'raw1.txt')
+utf_16_file = os.path.join(mydir, 'utf-16.csv')
+utf_16_file_rel = DocutilsTestSupport.utils.relative_path(None, utf_16_file)
+
+totest = {}
+
+totest['raw'] = [
+["""\
+.. raw:: html
+
+ <span>This is some plain old raw text.</span>
+""",
+"""\
+<document source="test data">
+ <raw format="html" xml:space="preserve">
+ <span>This is some plain old raw text.</span>
+"""],
+["""\
+.. raw:: html
+ :file: %s
+""" % raw1,
+"""\
+<document source="test data">
+ <raw format="html" source="%s" xml:space="preserve">
+ <p>This file is used by <tt>test_raw.py</tt>.</p>
+""" % DocutilsTestSupport.utils.relative_path(None, raw1)],
+["""\
+.. raw:: html
+ :file: rawfile.html
+ :url: http://example.org/
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ The "file" and "url" options may not be simultaneously specified for the "raw" directive.
+ <literal_block xml:space="preserve">
+ .. raw:: html
+ :file: rawfile.html
+ :url: http://example.org/
+"""],
+["""\
+.. raw:: html
+ :file: rawfile.html
+
+ <p>Can't have both content and file attribute.</p>
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ "raw" directive may not both specify an external file and have content.
+ <literal_block xml:space="preserve">
+ .. raw:: html
+ :file: rawfile.html
+
+ <p>Can't have both content and file attribute.</p>
+"""],
+[r"""
+.. raw:: latex html
+
+ \[ \sum_{n=1}^\infty \frac{1}{n} \text{ etc.} \]
+""",
+"""\
+<document source="test data">
+ <raw format="latex html" xml:space="preserve">
+ \\[ \\sum_{n=1}^\\infty \\frac{1}{n} \\text{ etc.} \\]
+"""],
+["""\
+.. raw:: html
+ :file: %s
+ :encoding: utf-16
+""" % utf_16_file_rel,
+"""\
+<document source="test data">
+ <raw format="html" source="%s" xml:space="preserve">
+ "Treat", "Quantity", "Description"
+ "Albatr\xb0\xdf", 2.99, "\xa1On a \\u03c3\\u03c4\\u03b9\\u03ba!"
+ "Crunchy Frog", 1.49, "If we took the b\xf6nes out, it wouldn\\u2019t be
+ crunchy, now would it?"
+ "Gannet Ripple", 1.99, "\xbfOn a \\u03c3\\u03c4\\u03b9\\u03ba?"
+""" % utf_16_file_rel],
+["""\
+Raw input file is UTF-16-encoded, and is not valid ASCII.
+
+.. raw:: html
+ :file: %s
+ :encoding: ascii
+""" % utf_16_file_rel,
+"""\
+<document source="test data">
+ <paragraph>
+ Raw input file is UTF-16-encoded, and is not valid ASCII.
+ <system_message level="4" line="3" source="test data" type="SEVERE">
+ <paragraph>
+ Problem with "raw" directive:
+ UnicodeError: Unable to decode input data. Tried the following encodings: \'ascii\'.
+ (UnicodeDecodeError: 'ascii' codec can't decode byte 0xfe in position 0: ordinal not in range(128))
+ <literal_block xml:space="preserve">
+ .. raw:: html
+ :file: %s
+ :encoding: ascii
+""" % utf_16_file_rel],
+["""\
+.. raw:: html
+ :encoding: utf-8
+
+ Should the parser complain becau\xdfe there is no :file:? BUG?
+""",
+"""\
+<document source="test data">
+ <raw format="html" xml:space="preserve">
+ Should the parser complain becau\xdfe there is no :file:? BUG?
+"""],
+]
+
+# Skip tests whose output contains "UnicodeDecodeError" if we are not
+# using Python 2.3 or higher.
+if sys.version_info < (2, 3):
+ for i in range(len(totest['raw'])):
+ if totest['raw'][i][1].find('UnicodeDecodeError') != -1:
+ del totest['raw'][i]
+ print ("Test totest['raw'][%s] skipped; "
+ "Python 2.3+ required for expected output." % i)
+ # Assume we have only one of these tests.
+ break
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_replace.py b/test/test_parsers/test_rst/test_directives/test_replace.py
new file mode 100755
index 000000000..f5fd2495b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_replace.py
@@ -0,0 +1,135 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "replace" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['replace'] = [
+["""\
+Test the |name| directive.
+
+.. |name| replace:: "**replace**"
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test the \n\
+ <substitution_reference refname="name">
+ name
+ directive.
+ <substitution_definition names="name">
+ "
+ <strong>
+ replace
+ "
+"""],
+["""\
+.. |name| replace:: paragraph 1
+
+ paragraph 2
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "replace" directive: may contain a single paragraph only.
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "name" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |name| replace:: paragraph 1
+
+ paragraph 2
+"""],
+["""\
+.. |name| replace::
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ The "replace" directive is empty; content required.
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "name" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |name| replace::
+"""],
+["""\
+.. |Python| replace:: Python, *the* best language around
+
+.. _Python: http://www.python.org/
+
+I recommend you try |Python|_.
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="Python">
+ Python,
+ <emphasis>
+ the
+ best language around
+ <target ids="python" names="python" refuri="http://www.python.org/">
+ <paragraph>
+ I recommend you try
+ <reference refname="python">
+ <substitution_reference refname="Python">
+ Python
+ .
+"""],
+["""\
+.. |name| replace:: *error in **inline ``markup
+""",
+"""\
+<document source="test data">
+ <system_message ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <system_message ids="id3" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline strong start-string without end-string.
+ <system_message ids="id5" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "replace" directive: may contain a single paragraph only.
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "name" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |name| replace:: *error in **inline ``markup
+"""],
+["""\
+.. replace:: not valid outside of a substitution definition
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid context: the "replace" directive can only be used within a substitution definition.
+ <literal_block xml:space="preserve">
+ .. replace:: not valid outside of a substitution definition
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_role.py b/test/test_parsers/test_rst/test_directives/test_role.py
new file mode 100755
index 000000000..0cd10c967
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_role.py
@@ -0,0 +1,230 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "role" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['role'] = [
+["""\
+.. role:: custom
+.. role:: special
+
+:custom:`interpreted` and :special:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <inline classes="custom">
+ interpreted
+ and \n\
+ <inline classes="special">
+ interpreted
+"""],
+["""\
+.. role:: custom
+ :class: custom-class
+.. role:: special
+ :class: special-class
+
+:custom:`interpreted` and :special:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <inline classes="custom-class">
+ interpreted
+ and \n\
+ <inline classes="special-class">
+ interpreted
+"""],
+["""\
+Must define :custom:`interpreted` before using it.
+
+.. role:: custom
+
+Now that it's defined, :custom:`interpreted` works.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Must define
+ <problematic ids="id2" refid="id1">
+ :custom:`interpreted`
+ before using it.
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "custom" in module "docutils.parsers.rst.languages.en".
+ Trying "custom" as canonical role name.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "custom".
+ <paragraph>
+ Now that it's defined, \n\
+ <inline classes="custom">
+ interpreted
+ works.
+"""],
+["""\
+.. role:: custom(emphasis)
+
+:custom:`text`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <emphasis classes="custom">
+ text
+"""],
+["""\
+.. role:: custom ( emphasis )
+
+:custom:`text`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <emphasis classes="custom">
+ text
+"""],
+["""\
+.. role:: custom(emphasis)
+ :class: special
+
+:custom:`text`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <emphasis classes="special">
+ text
+"""],
+["""\
+.. role:: custom(unknown-role)
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "unknown-role" in module "docutils.parsers.rst.languages.en".
+ Trying "unknown-role" as canonical role name.
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "unknown-role".
+ <literal_block xml:space="preserve">
+ .. role:: custom(unknown-role)
+"""],
+["""\
+.. role:: custom
+ :class: 1
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "role" directive:
+ invalid option value: (option: "class"; value: '1')
+ cannot make "1" into a class name.
+ <literal_block xml:space="preserve">
+ .. role:: custom
+ :class: 1
+"""],
+["""\
+.. role:: 1
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid argument for "role" directive:
+ cannot make "1" into a class name.
+ <literal_block xml:space="preserve">
+ .. role:: 1
+"""],
+["""\
+Test
+----
+
+.. role:: fileref(emphasis)
+
+Testing a :fileref:`role` in a nested parse.
+""",
+"""\
+<document source="test data">
+ <section ids="test" names="test">
+ <title>
+ Test
+ <paragraph>
+ Testing a \n\
+ <emphasis classes="fileref">
+ role
+ in a nested parse.
+"""],
+]
+
+totest['raw_role'] = [
+["""\
+.. role:: html(raw)
+ :format: html
+
+Here's some :html:`<i>raw HTML data</i>`.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here's some \n\
+ <raw classes="html" format="html" xml:space="preserve">
+ <i>raw HTML data</i>
+ .
+"""],
+["""\
+.. role:: itex(raw)
+ :format: latex html
+
+Here's some itex markup: :itex:`$x^\\infty$`.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here's some itex markup: \n\
+ <raw classes="itex" format="latex html" xml:space="preserve">
+ $x^\\infty$
+ .
+"""],
+["""\
+Can't use the :raw:`role` directly.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Can't use the \n\
+ <problematic ids="id2" refid="id1">
+ :raw:`role`
+ directly.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ No format (Writer name) is associated with this role: "raw".
+ The "raw" role cannot be used directly.
+ Instead, use the "role" directive to create a new role with an associated format.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_rubrics.py b/test/test_parsers/test_rst/test_directives/test_rubrics.py
new file mode 100755
index 000000000..271802736
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_rubrics.py
@@ -0,0 +1,74 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the "rubric" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['rubrics'] = [
+["""\
+.. rubric:: This is a rubric
+""",
+"""\
+<document source="test data">
+ <rubric>
+ This is a rubric
+"""],
+["""\
+.. rubric::
+.. rubric:: A rubric has no content
+
+ Invalid content
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "rubric" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. rubric::
+ <system_message level="3" line="2" source="test data" type="ERROR">
+ <paragraph>
+ Error in "rubric" directive:
+ no content permitted.
+ <literal_block xml:space="preserve">
+ .. rubric:: A rubric has no content
+ \n\
+ Invalid content
+"""],
+["""\
+.. rubric:: A rubric followed by a block quote
+..
+
+ Block quote
+""",
+"""\
+<document source="test data">
+ <rubric>
+ A rubric followed by a block quote
+ <comment xml:space="preserve">
+ <block_quote>
+ <paragraph>
+ Block quote
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_sidebars.py b/test/test_parsers/test_rst/test_directives/test_sidebars.py
new file mode 100755
index 000000000..a84fc248d
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_sidebars.py
@@ -0,0 +1,73 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the "sidebar" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['sidebars'] = [
+["""\
+.. sidebar:: Outer
+
+ .. sidebar:: Nested
+
+ Body.
+""",
+"""\
+<document source="test data">
+ <sidebar>
+ <title>
+ Outer
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ The "sidebar" directive may not be used within a sidebar element.
+ <literal_block xml:space="preserve">
+ .. sidebar:: Nested
+ \n\
+ Body.
+"""],
+["""\
+.. sidebar:: Outer
+
+ .. topic:: Topic
+
+ .. sidebar:: Inner
+
+ text
+""",
+"""\
+<document source="test data">
+ <sidebar>
+ <title>
+ Outer
+ <topic>
+ <title>
+ Topic
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ The "sidebar" directive may not be used within topics or body elements.
+ <literal_block xml:space="preserve">
+ .. sidebar:: Inner
+ \n\
+ text
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_tables.py b/test/test_parsers/test_rst/test_directives/test_tables.py
new file mode 100755
index 000000000..da88510e7
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_tables.py
@@ -0,0 +1,997 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for tables.py directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+import os
+try:
+ import csv
+except ImportError:
+ csv = None
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+mydir = 'test_parsers/test_rst/test_directives/'
+utf_16_csv = os.path.join(mydir, 'utf-16.csv')
+utf_16_csv_rel = DocutilsTestSupport.utils.relative_path(None, utf_16_csv)
+empty_txt = os.path.join(mydir, 'empty.txt')
+
+totest = {}
+
+totest['table'] = [
+["""\
+.. table:: Truth table for "not"
+ :class: custom
+
+ ===== =====
+ A not A
+ ===== =====
+ False True
+ True False
+ ===== =====
+""",
+"""\
+<document source="test data">
+ <table classes="custom">
+ <title>
+ Truth table for "not"
+ <tgroup cols="2">
+ <colspec colwidth="5">
+ <colspec colwidth="5">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ A
+ <entry>
+ <paragraph>
+ not A
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ False
+ <entry>
+ <paragraph>
+ True
+ <row>
+ <entry>
+ <paragraph>
+ True
+ <entry>
+ <paragraph>
+ False
+"""],
+["""\
+.. table:: title with an *error
+
+ ====== =====
+ Simple table
+ ====== =====
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ title with an \n\
+ <problematic ids="id2" refid="id1">
+ *
+ error
+ <tgroup cols="2">
+ <colspec colwidth="6">
+ <colspec colwidth="5">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Simple
+ <entry>
+ <paragraph>
+ table
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+"""],
+]
+
+if not csv:
+ print ('Tests of "csv-table" directive skipped; '
+ 'Python 2.3 or higher required.')
+else:
+ totest['csv-table'] = [
+["""\
+.. csv-table:: inline with integral header
+ :widths: 10, 20, 30
+ :header-rows: 1
+ :stub-columns: 1
+
+ "Treat", "Quantity", "Description"
+ "Albatross", 2.99, "On a stick!"
+ "Crunchy Frog", 1.49, "If we took the bones out, it wouldn\'t be
+ crunchy, now would it?"
+ "Gannet Ripple", 1.99, "On a stick!"
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ inline with integral header
+ <tgroup cols="3">
+ <colspec colwidth="10" stub="1">
+ <colspec colwidth="20">
+ <colspec colwidth="30">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <paragraph>
+ Description
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Albatross
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ On a stick!
+ <row>
+ <entry>
+ <paragraph>
+ Crunchy Frog
+ <entry>
+ <paragraph>
+ 1.49
+ <entry>
+ <paragraph>
+ If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ <row>
+ <entry>
+ <paragraph>
+ Gannet Ripple
+ <entry>
+ <paragraph>
+ 1.99
+ <entry>
+ <paragraph>
+ On a stick!
+"""],
+["""\
+.. csv-table:: inline with separate header
+ :header: "Treat", Quantity, "Description"
+ :widths: 10,20,30
+
+ "Albatross", 2.99, "On a stick!"
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ inline with separate header
+ <tgroup cols="3">
+ <colspec colwidth="10">
+ <colspec colwidth="20">
+ <colspec colwidth="30">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <paragraph>
+ Description
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Albatross
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ On a stick!
+"""],
+["""\
+.. csv-table:: complex internal structure
+ :header: "Treat", Quantity, "
+ * Description,
+ * Definition, or
+ * Narrative"
+
+ "
+ * Ice cream
+ * Sorbet
+ * Albatross", 2.99, "On a stick!"
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ complex internal structure
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ Description,
+ <list_item>
+ <paragraph>
+ Definition, or
+ <list_item>
+ <paragraph>
+ Narrative
+ <tbody>
+ <row>
+ <entry>
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ Ice cream
+ <list_item>
+ <paragraph>
+ Sorbet
+ <list_item>
+ <paragraph>
+ Albatross
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ On a stick!
+"""],
+["""\
+.. csv-table:: short rows
+
+ one, 2, three
+ 4, five
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ short rows
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ one
+ <entry>
+ <paragraph>
+ 2
+ <entry>
+ <paragraph>
+ three
+ <row>
+ <entry>
+ <paragraph>
+ 4
+ <entry>
+ <paragraph>
+ five
+ <entry>
+"""],
+["""\
+.. csv-table:: short rows
+ :header-rows: 1
+
+ header col 1, header col 2
+ one, 2, three
+ 4
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ short rows
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ header col 1
+ <entry>
+ <paragraph>
+ header col 2
+ <entry>
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ one
+ <entry>
+ <paragraph>
+ 2
+ <entry>
+ <paragraph>
+ three
+ <row>
+ <entry>
+ <paragraph>
+ 4
+ <entry>
+ <entry>
+"""],
+[u"""\
+.. csv-table:: non-ASCII characters
+
+ Heiz\xf6lr\xfccksto\xdfabd\xe4mpfung
+""",
+u"""\
+<document source="test data">
+ <table>
+ <title>
+ non-ASCII characters
+ <tgroup cols="1">
+ <colspec colwidth="100">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Heiz\xf6lr\xfccksto\xdfabd\xe4mpfung
+"""],
+["""\
+.. csv-table:: empty
+""",
+"""\
+<document source="test data">
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ The "csv-table" directive requires content; none supplied.
+ <literal_block xml:space="preserve">
+ .. csv-table:: empty
+"""],
+["""\
+.. csv-table:: insufficient header row data
+ :header-rows: 2
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ 2 header row(s) specified but only 1 row(s) of data supplied ("csv-table" directive).
+ <literal_block xml:space="preserve">
+ .. csv-table:: insufficient header row data
+ :header-rows: 2
+ \n\
+ some, csv, data
+"""],
+["""\
+.. csv-table:: insufficient body data
+ :header-rows: 1
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Insufficient data supplied (1 row(s)); no data remaining for table body, required by "csv-table" directive.
+ <literal_block xml:space="preserve">
+ .. csv-table:: insufficient body data
+ :header-rows: 1
+ \n\
+ some, csv, data
+"""],
+["""\
+.. csv-table:: content and external
+ :file: bogus.csv
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ "csv-table" directive may not both specify an external file and have content.
+ <literal_block xml:space="preserve">
+ .. csv-table:: content and external
+ :file: bogus.csv
+ \n\
+ some, csv, data
+"""],
+["""\
+.. csv-table:: external file and url
+ :file: bogus.csv
+ :url: http://example.org/bogus.csv
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ The "file" and "url" options may not be simultaneously specified for the "csv-table" directive.
+ <literal_block xml:space="preserve">
+ .. csv-table:: external file and url
+ :file: bogus.csv
+ :url: http://example.org/bogus.csv
+"""],
+["""\
+.. csv-table:: error in the *title
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ error in the \n\
+ <problematic ids="id2" refid="id1">
+ *
+ title
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ some
+ <entry>
+ <paragraph>
+ csv
+ <entry>
+ <paragraph>
+ data
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+"""],
+["""\
+.. csv-table:: no such file
+ :file: bogus.csv
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Problems with "csv-table" directive path:
+ [Errno 2] No such file or directory: 'bogus.csv'.
+ <literal_block xml:space="preserve">
+ .. csv-table:: no such file
+ :file: bogus.csv
+"""],
+["""\
+.. csv-table:: bad URL
+ :url: bogus.csv
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Problems with "csv-table" directive URL "bogus.csv":
+ unknown url type: bogus.csv.
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad URL
+ :url: bogus.csv
+"""],
+["""\
+.. csv-table:: column mismatch
+ :widths: 10,20
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ "csv-table" widths do not match the number of columns in table (3).
+ <literal_block xml:space="preserve">
+ .. csv-table:: column mismatch
+ :widths: 10,20
+ \n\
+ some, csv, data
+"""],
+["""\
+.. csv-table:: bad column widths
+ :widths: 10,y,z
+
+ some, csv, data
+
+.. csv-table:: bad column widths
+ :widths: 0 0 0
+
+ some, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "csv-table" directive:
+ invalid option value: (option: "widths"; value: '10,y,z')
+ invalid literal for int(): y.
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad column widths
+ :widths: 10,y,z
+ \n\
+ some, csv, data
+ <system_message level="3" line="6" source="test data" type="ERROR">
+ <paragraph>
+ Error in "csv-table" directive:
+ invalid option value: (option: "widths"; value: '0 0 0')
+ negative or zero value; must be positive.
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad column widths
+ :widths: 0 0 0
+ \n\
+ some, csv, data
+"""],
+["""\
+.. csv-table:: good delimiter
+ :delim: /
+
+ some/csv/data
+
+.. csv-table:: good delimiter
+ :delim: \\
+
+ some\\csv\\data
+
+.. csv-table:: good delimiter
+ :delim: 0x5c
+
+ some\\csv\\data
+
+.. csv-table:: good delimiter
+ :delim: space
+
+ some csv data
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ good delimiter
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ some
+ <entry>
+ <paragraph>
+ csv
+ <entry>
+ <paragraph>
+ data
+ <table>
+ <title>
+ good delimiter
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ some
+ <entry>
+ <paragraph>
+ csv
+ <entry>
+ <paragraph>
+ data
+ <table>
+ <title>
+ good delimiter
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ some
+ <entry>
+ <paragraph>
+ csv
+ <entry>
+ <paragraph>
+ data
+ <table>
+ <title>
+ good delimiter
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ some
+ <entry>
+ <paragraph>
+ csv
+ <entry>
+ <paragraph>
+ data
+"""],
+["""\
+.. csv-table:: bad delimiter
+ :delim: multiple
+
+.. csv-table:: bad delimiter
+ :delim: U+9999999999999
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "csv-table" directive:
+ invalid option value: (option: "delim"; value: 'multiple')
+ 'multiple' invalid; must be a single character or a Unicode code.
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad delimiter
+ :delim: multiple
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Error in "csv-table" directive:
+ invalid option value: (option: "delim"; value: 'U+9999999999999')
+ code too large (long int too large to convert to int).
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad delimiter
+ :delim: U+9999999999999
+"""],
+["""\
+.. csv-table:: bad CSV data
+
+ "bad", \"csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error with CSV data in "csv-table" directive:
+ newline inside string
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad CSV data
+ \n\
+ "bad", \"csv, data
+"""],
+["""\
+.. csv-table:: bad CSV header data
+ :header: "bad", \"csv, data
+
+ good, csv, data
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error with CSV data in "csv-table" directive:
+ newline inside string
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad CSV header data
+ :header: "bad", \"csv, data
+ \n\
+ good, csv, data
+"""],
+["""\
+.. csv-table:: bad encoding
+ :file: %s
+ :encoding: latin-1
+
+(7- and 8-bit text encoded as UTF-16 has lots of null/zero bytes.)
+""" % utf_16_csv,
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error with CSV data in "csv-table" directive:
+ string with NUL bytes
+ <literal_block xml:space="preserve">
+ .. csv-table:: bad encoding
+ :file: %s
+ :encoding: latin-1
+ <paragraph>
+ (7- and 8-bit text encoded as UTF-16 has lots of null/zero bytes.)
+""" % utf_16_csv],
+["""\
+.. csv-table:: good encoding
+ :file: %s
+ :encoding: utf-16
+ :header-rows: 1
+""" % utf_16_csv,
+u"""\
+<document source="test data">
+ <table>
+ <title>
+ good encoding
+ <tgroup cols="3">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <colspec colwidth="33">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <paragraph>
+ Description
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Albatr\u00b0\u00df
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ \u00a1On a \u03c3\u03c4\u03b9\u03ba!
+ <row>
+ <entry>
+ <paragraph>
+ Crunchy Frog
+ <entry>
+ <paragraph>
+ 1.49
+ <entry>
+ <paragraph>
+ If we took the b\u00f6nes out, it wouldn\u2019t be
+ crunchy, now would it?
+ <row>
+ <entry>
+ <paragraph>
+ Gannet Ripple
+ <entry>
+ <paragraph>
+ 1.99
+ <entry>
+ <paragraph>
+ \u00bfOn a \u03c3\u03c4\u03b9\u03ba?
+"""],
+["""\
+.. csv-table:: no CSV data
+ :file: %s
+""" % empty_txt,
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ No table data detected in CSV file.
+ <literal_block xml:space="preserve">
+ .. csv-table:: no CSV data
+ :file: %s
+""" % empty_txt],
+]
+
+totest['list-table'] = [
+["""\
+.. list-table:: list table with integral header
+ :widths: 10 20 30
+ :header-rows: 1
+ :stub-columns: 1
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn\'t be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+""",
+"""\
+<document source="test data">
+ <table>
+ <title>
+ list table with integral header
+ <tgroup cols="3">
+ <colspec colwidth="10" stub="1">
+ <colspec colwidth="20">
+ <colspec colwidth="30">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Treat
+ <entry>
+ <paragraph>
+ Quantity
+ <entry>
+ <paragraph>
+ Description
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Albatross
+ <entry>
+ <paragraph>
+ 2.99
+ <entry>
+ <paragraph>
+ On a stick!
+ <row>
+ <entry>
+ <paragraph>
+ Crunchy Frog
+ <entry>
+ <paragraph>
+ 1.49
+ <entry>
+ <paragraph>
+ If we took the bones out, it wouldn\'t be
+ crunchy, now would it?
+ <row>
+ <entry>
+ <paragraph>
+ Gannet Ripple
+ <entry>
+ <paragraph>
+ 1.99
+ <entry>
+ <paragraph>
+ On a stick!
+"""],
+["""\
+.. list-table::
+
+ not a bullet list
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error parsing content block for the "list-table" directive: exactly one bullet list expected.
+ <literal_block xml:space="preserve">
+ .. list-table::
+ \n\
+ not a bullet list
+"""],
+["""\
+.. list-table::
+
+ * not a second-level bullet list
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error parsing content block for the "list-table" directive: two-level bullet list expected, but row 1 does not contain a second-level bullet list.
+ <literal_block xml:space="preserve">
+ .. list-table::
+ \n\
+ * not a second-level bullet list
+"""],
+["""\
+.. list-table::
+
+ * - columns not uniform
+ * - first row has one,
+ - second row has two
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error parsing content block for the "list-table" directive: uniform two-level bullet list expected, but row 2 does not contain the same number of items as row 1 (2 vs 1).
+ <literal_block xml:space="preserve">
+ .. list-table::
+ \n\
+ * - columns not uniform
+ * - first row has one,
+ - second row has two
+"""],
+["""\
+.. list-table::
+ :widths: 10 20
+
+ * - ":widths:" option doesn't match columns
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ "list-table" widths do not match the number of columns in table (1).
+ <literal_block xml:space="preserve">
+ .. list-table::
+ :widths: 10 20
+ \n\
+ * - ":widths:" option doesn\'t match columns
+"""],
+["""\
+.. list-table::
+ :stub-columns: 3
+
+ * - column 1
+ - column 2
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ 3 stub column(s) specified but only 2 columns(s) of data supplied ("list-table" directive).
+ <literal_block xml:space="preserve">
+ .. list-table::
+ :stub-columns: 3
+ \n\
+ * - column 1
+ - column 2
+"""],
+["""\
+.. list-table::
+ :stub-columns: 2
+
+ * - column 1
+ - column 2
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Insufficient data supplied (2 columns(s)); no data remaining for table body, required by "list-table" directive.
+ <literal_block xml:space="preserve">
+ .. list-table::
+ :stub-columns: 2
+ \n\
+ * - column 1
+ - column 2
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_target_notes.py b/test/test_parsers/test_rst/test_directives/test_target_notes.py
new file mode 100755
index 000000000..18dc1d207
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_target_notes.py
@@ -0,0 +1,64 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the target-notes directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['target-notes'] = [
+["""\
+.. target-notes::
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.references.TargetNotes
+ .details:
+"""],
+["""\
+.. target-notes:: :class: custom
+""",
+"""\
+<document source="test data">
+ <pending>
+ .. internal attributes:
+ .transform: docutils.transforms.references.TargetNotes
+ .details:
+ class: ['custom']
+"""],
+["""\
+.. target-notes::
+ :class:
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "target-notes" directive:
+ invalid option value: (option: "class"; value: None)
+ argument required but none supplied.
+ <literal_block xml:space="preserve">
+ .. target-notes::
+ :class:
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_test_directives.py b/test/test_parsers/test_rst/test_directives/test_test_directives.py
new file mode 100755
index 000000000..b90b26473
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_test_directives.py
@@ -0,0 +1,208 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py test directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['test_directives'] = [
+["""\
+.. reStructuredText-test-directive::
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive ::
+
+An optional space before the "::".
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={}, content: None
+ <paragraph>
+ An optional space before the "::".
+"""],
+["""\
+.. reStructuredText-test-directive:: argument
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=['argument'], options={}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive:: argument
+ :option: value
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=['argument'], options={'option': 'value'}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive:: :option: value
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={'option': 'value'}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive:: :option:
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "reStructuredText-test-directive" directive:
+ invalid option value: (option: "option"; value: None)
+ argument required but none supplied.
+ <literal_block xml:space="preserve">
+ .. reStructuredText-test-directive:: :option:
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive::
+
+ Directive block contains one paragraph, with a blank line before.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={}, content:
+ <literal_block xml:space="preserve">
+ Directive block contains one paragraph, with a blank line before.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive::
+
+
+ Directive block contains one paragraph, with two blank lines before.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={}, content:
+ <literal_block xml:space="preserve">
+ Directive block contains one paragraph, with two blank lines before.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive::
+ Directive block contains one paragraph, no blank line before.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=['Directive block contains one paragraph, no blank line before.'], options={}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive::
+ block
+no blank line.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=['block'], options={}, content: None
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive:: argument
+ :option: * value1
+ * value2
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=['argument'], options={'option': '* value1\\n* value2'}, content: None
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. reStructuredText-test-directive::
+
+ Directive \\block \\*contains* \\\\backslashes.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Directive processed. Type="reStructuredText-test-directive", arguments=[], options={}, content:
+ <literal_block xml:space="preserve">
+ Directive \\block \\*contains* \\\\backslashes.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_topics.py b/test/test_parsers/test_rst/test_directives/test_topics.py
new file mode 100755
index 000000000..4d0fae27b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_topics.py
@@ -0,0 +1,240 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for the "topic" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['topics'] = [
+["""\
+.. topic::
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "topic" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. topic::
+"""],
+["""\
+.. topic:: Title
+""",
+"""\
+<document source="test data">
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Content block expected for the "topic" directive; none found.
+ <literal_block xml:space="preserve">
+ .. topic:: Title
+"""],
+["""\
+.. topic:: Title
+
+ Body.
+""",
+"""\
+<document source="test data">
+ <topic>
+ <title>
+ Title
+ <paragraph>
+ Body.
+"""],
+["""\
+.. topic::
+
+ Title
+
+ Body.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "topic" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. topic::
+ \n\
+ Title
+ \n\
+ Body.
+"""],
+["""\
+.. topic:: Title
+ Body.
+""",
+"""\
+<document source="test data">
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Content block expected for the "topic" directive; none found.
+ <literal_block xml:space="preserve">
+ .. topic:: Title
+ Body.
+"""],
+["""\
+.. topic::
+
+ Title
+ Body.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "topic" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. topic::
+ \n\
+ Title
+ Body.
+"""],
+["""\
+.. topic:: Title
+
+ .. topic:: Nested
+
+ Body.
+""",
+"""\
+<document source="test data">
+ <topic>
+ <title>
+ Title
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ The "topic" directive may not be used within topics or body elements.
+ <literal_block xml:space="preserve">
+ .. topic:: Nested
+ \n\
+ Body.
+"""],
+["""\
+.. topic:: Title
+
+ .. topic:: Nested
+
+ Body.
+ More.
+""",
+"""\
+<document source="test data">
+ <topic>
+ <title>
+ Title
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ The "topic" directive may not be used within topics or body elements.
+ <literal_block xml:space="preserve">
+ .. topic:: Nested
+ \n\
+ Body.
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ More.
+"""],
+["""\
+.. topic:: Title
+
+ .. topic:: Nested
+
+ Body.
+
+ More.
+
+More.
+""",
+"""\
+<document source="test data">
+ <topic>
+ <title>
+ Title
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ The "topic" directive may not be used within topics or body elements.
+ <literal_block xml:space="preserve">
+ .. topic:: Nested
+ \n\
+ Body.
+ <paragraph>
+ More.
+ <paragraph>
+ More.
+"""],
+["""\
+.. topic:: First
+
+ Body
+
+.. topic:: Second
+
+ Body.
+""",
+"""\
+<document source="test data">
+ <topic>
+ <title>
+ First
+ <paragraph>
+ Body
+ <topic>
+ <title>
+ Second
+ <paragraph>
+ Body.
+"""],
+["""\
+.. sidebar:: Title
+ :subtitle: Outer
+
+ .. topic:: Nested
+
+ Body.
+
+ More.
+
+More.
+""",
+"""\
+<document source="test data">
+ <sidebar>
+ <title>
+ Title
+ <subtitle>
+ Outer
+ <topic>
+ <title>
+ Nested
+ <paragraph>
+ Body.
+ <paragraph>
+ More.
+ <paragraph>
+ More.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_unicode.py b/test/test_parsers/test_rst/test_directives/test_unicode.py
new file mode 100755
index 000000000..bd028cf42
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_unicode.py
@@ -0,0 +1,172 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for misc.py "unicode" directive.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['unicode'] = [
+["""
+Insert an em-dash (|mdash|), a copyright symbol (|copy|), a non-breaking
+space (|nbsp|), a backwards-not-equals (|bne|), and a captial omega (|Omega|).
+
+.. |mdash| unicode:: 0x02014
+.. |copy| unicode:: \\u00A9
+.. |nbsp| unicode:: &#x000A0;
+.. |bne| unicode:: U0003D U020E5
+.. |Omega| unicode:: U+003A9
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Insert an em-dash (
+ <substitution_reference refname="mdash">
+ mdash
+ ), a copyright symbol (
+ <substitution_reference refname="copy">
+ copy
+ ), a non-breaking
+ space (
+ <substitution_reference refname="nbsp">
+ nbsp
+ ), a backwards-not-equals (
+ <substitution_reference refname="bne">
+ bne
+ ), and a captial omega (
+ <substitution_reference refname="Omega">
+ Omega
+ ).
+ <substitution_definition names="mdash">
+ \u2014
+ <substitution_definition names="copy">
+ \u00A9
+ <substitution_definition names="nbsp">
+ \u00A0
+ <substitution_definition names="bne">
+ =
+ \u20e5
+ <substitution_definition names="Omega">
+ \u03a9
+"""],
+["""
+Bad input:
+
+.. |empty| unicode::
+.. |empty too| unicode:: .. comment doesn't count as content
+.. |not hex| unicode:: 0xHEX
+.. |not all hex| unicode:: UABCX
+.. unicode:: not in a substitution definition
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Bad input:
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Error in "unicode" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ unicode::
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "empty" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |empty| unicode::
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "empty too" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |empty too| unicode:: .. comment doesn't count as content
+ <substitution_definition names="not\ hex">
+ 0xHEX
+ <substitution_definition names="not\ all\ hex">
+ UABCX
+ <system_message level="3" line="8" source="test data" type="ERROR">
+ <paragraph>
+ Invalid context: the "unicode" directive can only be used within a substitution definition.
+ <literal_block xml:space="preserve">
+ .. unicode:: not in a substitution definition
+"""],
+["""
+Testing comments and extra text.
+
+Copyright |copy| 2003, |BogusMegaCorp (TM)|.
+
+.. |copy| unicode:: 0xA9 .. copyright sign
+.. |BogusMegaCorp (TM)| unicode:: BogusMegaCorp U+2122
+ .. with trademark sign
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Testing comments and extra text.
+ <paragraph>
+ Copyright
+ <substitution_reference refname="copy">
+ copy
+ 2003,
+ <substitution_reference refname="BogusMegaCorp (TM)">
+ BogusMegaCorp (TM)
+ .
+ <substitution_definition names="copy">
+ \u00A9
+ <substitution_definition names="BogusMegaCorp\ (TM)">
+ BogusMegaCorp
+ \u2122
+"""],
+["""
+.. |too big for int| unicode:: 0x111111111111111111
+.. |too big for unicode| unicode:: 0x11111111
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="2" source="test data" type="ERROR">
+ <paragraph>
+ Invalid character code: 0x111111111111111111
+ ValueError: %s
+ <literal_block xml:space="preserve">
+ unicode:: 0x111111111111111111
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "too big for int" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |too big for int| unicode:: 0x111111111111111111
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Invalid character code: 0x11111111
+ %s
+ <literal_block xml:space="preserve">
+ unicode:: 0x11111111
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "too big for unicode" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |too big for unicode| unicode:: 0x11111111
+""" % ([DocutilsTestSupport.exception_data(
+ 'unichr(int("111111111111111111", 16))')[0],
+ 'code too large (%s)' % DocutilsTestSupport.exception_data(
+ 'unichr(int("111111111111111111", 16))')[0]]
+ [isinstance(DocutilsTestSupport.exception_data(
+ 'unichr(int("111111111111111111", 16))')[0], OverflowError)],
+ DocutilsTestSupport.exception_data('unichr(int("11111111", 16))')[2])]
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/test_unknown.py b/test/test_parsers/test_rst/test_directives/test_unknown.py
new file mode 100755
index 000000000..3c859faa3
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/test_unknown.py
@@ -0,0 +1,67 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for unknown directives.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['unknown'] = [
+["""\
+.. reStructuredText-unknown-directive::
+
+.. reStructuredText-unknown-directive:: argument
+
+.. reStructuredText-unknown-directive::
+ block
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No directive entry for "reStructuredText-unknown-directive" in module "docutils.parsers.rst.languages.en".
+ Trying "reStructuredText-unknown-directive" as canonical directive name.
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown directive type "reStructuredText-unknown-directive".
+ <literal_block xml:space="preserve">
+ .. reStructuredText-unknown-directive::
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ No directive entry for "reStructuredText-unknown-directive" in module "docutils.parsers.rst.languages.en".
+ Trying "reStructuredText-unknown-directive" as canonical directive name.
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Unknown directive type "reStructuredText-unknown-directive".
+ <literal_block xml:space="preserve">
+ .. reStructuredText-unknown-directive:: argument
+ <system_message level="1" line="5" source="test data" type="INFO">
+ <paragraph>
+ No directive entry for "reStructuredText-unknown-directive" in module "docutils.parsers.rst.languages.en".
+ Trying "reStructuredText-unknown-directive" as canonical directive name.
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Unknown directive type "reStructuredText-unknown-directive".
+ <literal_block xml:space="preserve">
+ .. reStructuredText-unknown-directive::
+ block
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_directives/utf-16.csv b/test/test_parsers/test_rst/test_directives/utf-16.csv
new file mode 100644
index 000000000..ba60d155e
--- /dev/null
+++ b/test/test_parsers/test_rst/test_directives/utf-16.csv
Binary files differ
diff --git a/test/test_parsers/test_rst/test_doctest_blocks.py b/test/test_parsers/test_rst/test_doctest_blocks.py
new file mode 100755
index 000000000..c9637c6d6
--- /dev/null
+++ b/test/test_parsers/test_rst/test_doctest_blocks.py
@@ -0,0 +1,74 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['doctest_blocks'] = [
+["""\
+Paragraph.
+
+>>> print "Doctest block."
+Doctest block.
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <doctest_block xml:space="preserve">
+ >>> print "Doctest block."
+ Doctest block.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Paragraph.
+
+>>> print " Indented output."
+ Indented output.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <doctest_block xml:space="preserve">
+ >>> print " Indented output."
+ Indented output.
+"""],
+["""\
+Paragraph.
+
+ >>> print " Indented block & output."
+ Indented block & output.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <block_quote>
+ <doctest_block xml:space="preserve">
+ >>> print " Indented block & output."
+ Indented block & output.
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_east_asian_text.py b/test/test_parsers/test_rst/test_east_asian_text.py
new file mode 100755
index 000000000..1ac27743e
--- /dev/null
+++ b/test/test_parsers/test_rst/test_east_asian_text.py
@@ -0,0 +1,324 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for East Asian text with double-width characters.
+"""
+
+from __init__ import DocutilsTestSupport
+
+import unicodedata
+try:
+ east_asian_width = unicodedata.east_asian_width
+except AttributeError:
+ east_asian_width = None
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+if not east_asian_width:
+ print ('test_east_asian_text.py tests skipped; '
+ 'Python 2.4 or higher required.')
+else:
+ totest['double-width'] = [
+[u"""\
+タイトル1
+=========
+
+タイトル2
+========
+""",
+u"""\
+<document source="test data">
+ <section ids="id1" names="タイトル1">
+ <title>
+ タイトル1
+ <section ids="id2" names="タイトル2">
+ <title>
+ タイトル2
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Title underline too short.
+ <literal_block xml:space="preserve">
+ タイトル2
+ ========
+"""],
+[ur"""
++-----------------------+
+| * ヒョウ:ダイ1ギョウ |
+| * ダイ2ギョウ |
++-----------------------+
+| \* ダイ1ギョウ |
+| * ダイ2ギョウ |
++-----------------------+
+""",
+u"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="23">
+ <tbody>
+ <row>
+ <entry>
+ <bullet_list bullet="*">
+ <list_item>
+ <paragraph>
+ ヒョウ:ダイ1ギョウ
+ <list_item>
+ <paragraph>
+ ダイ2ギョウ
+ <row>
+ <entry>
+ <paragraph>
+ * ダイ1ギョウ
+ * ダイ2ギョウ
+"""],
+[u"""\
+Complex spanning pattern (no edge knows all rows/cols):
+
++--------+---------------------+
+| 北西・ | 北・北æ±ã‚»ãƒ« |
+| 西セル +--------------+------+
+| | 真ん中ã®ã‚»ãƒ« | æ±ãƒ» |
++--------+--------------+ å—æ± |
+| å—西・å—セル | セル |
++-----------------------+------+
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Complex spanning pattern (no edge knows all rows/cols):
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="8">
+ <colspec colwidth="14">
+ <colspec colwidth="6">
+ <tbody>
+ <row>
+ <entry morerows="1">
+ <paragraph>
+ 北西・
+ 西セル
+ <entry morecols="1">
+ <paragraph>
+ 北・北æ±ã‚»ãƒ«
+ <row>
+ <entry>
+ <paragraph>
+ 真ん中ã®ã‚»ãƒ«
+ <entry morerows="1">
+ <paragraph>
+ æ±ãƒ»
+ å—æ±
+ セル
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ å—西・å—セル
+"""],
+[u"""\
+========= =========
+ダイ1ラン ダイ2ラン
+========= =========
+
+======== =========
+ダイ1ラン ダイ2ラン
+======== =========
+""",
+u"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="9">
+ <colspec colwidth="9">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ ダイ1ラン
+ <entry>
+ <paragraph>
+ ダイ2ラン
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Text in column margin at line offset 1.
+ <literal_block xml:space="preserve">
+ ======== =========
+ ダイ1ラン ダイ2ラン
+ ======== =========
+"""],
+[u"""\
+Some ambiguous-width characters:
+
+= ===================================
+© copyright sign
+® registered sign
+« left pointing guillemet
+» right pointing guillemet
+– en-dash
+— em-dash
+‘ single turned comma quotation mark
+’ single comma quotation mark
+‚ low single comma quotation mark
+“ double turned comma quotation mark
+†double comma quotation mark
+„ low double comma quotation mark
+† dagger
+‡ double dagger
+… ellipsis
+â„¢ trade mark sign
+⇔ left-right double arrow
+= ===================================
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Some ambiguous-width characters:
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="1">
+ <colspec colwidth="35">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ \xa9
+ <entry>
+ <paragraph>
+ copyright sign
+ <row>
+ <entry>
+ <paragraph>
+ \xae
+ <entry>
+ <paragraph>
+ registered sign
+ <row>
+ <entry>
+ <paragraph>
+ \xab
+ <entry>
+ <paragraph>
+ left pointing guillemet
+ <row>
+ <entry>
+ <paragraph>
+ \xbb
+ <entry>
+ <paragraph>
+ right pointing guillemet
+ <row>
+ <entry>
+ <paragraph>
+ \\u2013
+ <entry>
+ <paragraph>
+ en-dash
+ <row>
+ <entry>
+ <paragraph>
+ \\u2014
+ <entry>
+ <paragraph>
+ em-dash
+ <row>
+ <entry>
+ <paragraph>
+ \\u2018
+ <entry>
+ <paragraph>
+ single turned comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u2019
+ <entry>
+ <paragraph>
+ single comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u201a
+ <entry>
+ <paragraph>
+ low single comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u201c
+ <entry>
+ <paragraph>
+ double turned comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u201d
+ <entry>
+ <paragraph>
+ double comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u201e
+ <entry>
+ <paragraph>
+ low double comma quotation mark
+ <row>
+ <entry>
+ <paragraph>
+ \\u2020
+ <entry>
+ <paragraph>
+ dagger
+ <row>
+ <entry>
+ <paragraph>
+ \\u2021
+ <entry>
+ <paragraph>
+ double dagger
+ <row>
+ <entry>
+ <paragraph>
+ \\u2026
+ <entry>
+ <paragraph>
+ ellipsis
+ <row>
+ <entry>
+ <paragraph>
+ \\u2122
+ <entry>
+ <paragraph>
+ trade mark sign
+ <row>
+ <entry>
+ <paragraph>
+ \\u21d4
+ <entry>
+ <paragraph>
+ left-right double arrow
+"""],
+]
+'''
+[u"""\
+""",
+u"""\
+"""],
+'''
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_enumerated_lists.py b/test/test_parsers/test_rst/test_enumerated_lists.py
new file mode 100755
index 000000000..0375b33e9
--- /dev/null
+++ b/test/test_parsers/test_rst/test_enumerated_lists.py
@@ -0,0 +1,908 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['enumerated_lists'] = [
+["""\
+1. Item one.
+
+2. Item two.
+
+3. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+No blank lines betwen items:
+
+1. Item one.
+2. Item two.
+3. Item three.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ No blank lines betwen items:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+1.
+empty item above, no blank line
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ 1.
+ empty item above, no blank line
+"""],
+["""\
+Scrambled:
+
+3. Item three.
+
+2. Item two.
+
+1. Item one.
+
+3. Item three.
+2. Item two.
+1. Item one.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Scrambled:
+ <enumerated_list enumtype="arabic" prefix="" start="3" suffix=".">
+ <list_item>
+ <paragraph>
+ Item three.
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "3" (ordinal 3)
+ <enumerated_list enumtype="arabic" prefix="" start="2" suffix=".">
+ <list_item>
+ <paragraph>
+ Item two.
+ <system_message level="1" line="5" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "2" (ordinal 2)
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <paragraph>
+ 3. Item three.
+ 2. Item two.
+ 1. Item one.
+"""],
+["""\
+Skipping item 3:
+
+1. Item 1.
+2. Item 2.
+4. Item 4.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Skipping item 3:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item 1.
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <paragraph>
+ 2. Item 2.
+ 4. Item 4.
+"""],
+["""\
+Start with non-ordinal-1:
+
+0. Item zero.
+1. Item one.
+2. Item two.
+3. Item three.
+
+And again:
+
+2. Item two.
+3. Item three.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Start with non-ordinal-1:
+ <enumerated_list enumtype="arabic" prefix="" start="0" suffix=".">
+ <list_item>
+ <paragraph>
+ Item zero.
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "0" (ordinal 0)
+ <paragraph>
+ And again:
+ <enumerated_list enumtype="arabic" prefix="" start="2" suffix=".">
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+ <system_message level="1" line="10" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "2" (ordinal 2)
+"""],
+["""\
+1. Item one: line 1,
+ line 2.
+2. Item two: line 1,
+ line 2.
+3. Item three: paragraph 1, line 1,
+ line 2.
+
+ Paragraph 2.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one: line 1,
+ line 2.
+ <list_item>
+ <paragraph>
+ Item two: line 1,
+ line 2.
+ <list_item>
+ <paragraph>
+ Item three: paragraph 1, line 1,
+ line 2.
+ <paragraph>
+ Paragraph 2.
+"""],
+["""\
+Different enumeration sequences:
+
+1. Item 1.
+2. Item 2.
+3. Item 3.
+
+A. Item A.
+B. Item B.
+C. Item C.
+
+a. Item a.
+b. Item b.
+c. Item c.
+
+I. Item I.
+II. Item II.
+III. Item III.
+
+i. Item i.
+ii. Item ii.
+iii. Item iii.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Different enumeration sequences:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item 1.
+ <list_item>
+ <paragraph>
+ Item 2.
+ <list_item>
+ <paragraph>
+ Item 3.
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item A.
+ <list_item>
+ <paragraph>
+ Item B.
+ <list_item>
+ <paragraph>
+ Item C.
+ <enumerated_list enumtype="loweralpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item a.
+ <list_item>
+ <paragraph>
+ Item b.
+ <list_item>
+ <paragraph>
+ Item c.
+ <enumerated_list enumtype="upperroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item I.
+ <list_item>
+ <paragraph>
+ Item II.
+ <list_item>
+ <paragraph>
+ Item III.
+ <enumerated_list enumtype="lowerroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item i.
+ <list_item>
+ <paragraph>
+ Item ii.
+ <list_item>
+ <paragraph>
+ Item iii.
+"""],
+["""\
+Bad Roman numerals:
+
+i. i
+
+ii. ii
+
+iii. iii
+
+iiii. iiii
+ second line
+
+(LCD) is an acronym made up of Roman numerals
+
+(livid) is a word made up of Roman numerals
+
+(CIVIL) is another such word
+
+(I) I
+
+(IVXLCDM) IVXLCDM
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Bad Roman numerals:
+ <enumerated_list enumtype="lowerroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ i
+ <list_item>
+ <paragraph>
+ ii
+ <list_item>
+ <paragraph>
+ iii
+ <definition_list>
+ <definition_list_item>
+ <term>
+ iiii. iiii
+ <definition>
+ <paragraph>
+ second line
+ <paragraph>
+ (LCD) is an acronym made up of Roman numerals
+ <paragraph>
+ (livid) is a word made up of Roman numerals
+ <paragraph>
+ (CIVIL) is another such word
+ <enumerated_list enumtype="upperroman" prefix="(" suffix=")">
+ <list_item>
+ <paragraph>
+ I
+ <paragraph>
+ (IVXLCDM) IVXLCDM
+"""],
+["""\
+Potentially ambiguous cases:
+
+A. Item A.
+B. Item B.
+C. Item C.
+
+I. Item I.
+II. Item II.
+III. Item III.
+
+a. Item a.
+b. Item b.
+c. Item c.
+
+i. Item i.
+ii. Item ii.
+iii. Item iii.
+
+Phew! Safe!
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Potentially ambiguous cases:
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item A.
+ <list_item>
+ <paragraph>
+ Item B.
+ <list_item>
+ <paragraph>
+ Item C.
+ <enumerated_list enumtype="upperroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item I.
+ <list_item>
+ <paragraph>
+ Item II.
+ <list_item>
+ <paragraph>
+ Item III.
+ <enumerated_list enumtype="loweralpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item a.
+ <list_item>
+ <paragraph>
+ Item b.
+ <list_item>
+ <paragraph>
+ Item c.
+ <enumerated_list enumtype="lowerroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item i.
+ <list_item>
+ <paragraph>
+ Item ii.
+ <list_item>
+ <paragraph>
+ Item iii.
+ <paragraph>
+ Phew! Safe!
+"""],
+["""\
+Definitely ambiguous:
+
+A. Item A.
+B. Item B.
+C. Item C.
+D. Item D.
+E. Item E.
+F. Item F.
+G. Item G.
+H. Item H.
+I. Item I.
+II. Item II.
+III. Item III.
+
+a. Item a.
+b. Item b.
+c. Item c.
+d. Item d.
+e. Item e.
+f. Item f.
+g. Item g.
+h. Item h.
+i. Item i.
+ii. Item ii.
+iii. Item iii.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Definitely ambiguous:
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item A.
+ <list_item>
+ <paragraph>
+ Item B.
+ <list_item>
+ <paragraph>
+ Item C.
+ <list_item>
+ <paragraph>
+ Item D.
+ <list_item>
+ <paragraph>
+ Item E.
+ <list_item>
+ <paragraph>
+ Item F.
+ <list_item>
+ <paragraph>
+ Item G.
+ <list_item>
+ <paragraph>
+ Item H.
+ <system_message level="2" line="11" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <enumerated_list enumtype="upperroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item I.
+ <list_item>
+ <paragraph>
+ Item II.
+ <list_item>
+ <paragraph>
+ Item III.
+ <enumerated_list enumtype="loweralpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item a.
+ <list_item>
+ <paragraph>
+ Item b.
+ <list_item>
+ <paragraph>
+ Item c.
+ <list_item>
+ <paragraph>
+ Item d.
+ <list_item>
+ <paragraph>
+ Item e.
+ <list_item>
+ <paragraph>
+ Item f.
+ <list_item>
+ <paragraph>
+ Item g.
+ <list_item>
+ <paragraph>
+ Item h.
+ <system_message level="2" line="23" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <enumerated_list enumtype="lowerroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item i.
+ <list_item>
+ <paragraph>
+ Item ii.
+ <list_item>
+ <paragraph>
+ Item iii.
+"""],
+["""\
+Different enumeration formats:
+
+1. Item 1.
+2. Item 2.
+3. Item 3.
+
+1) Item 1).
+2) Item 2).
+3) Item 3).
+
+(1) Item (1).
+(2) Item (2).
+(3) Item (3).
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Different enumeration formats:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item 1.
+ <list_item>
+ <paragraph>
+ Item 2.
+ <list_item>
+ <paragraph>
+ Item 3.
+ <enumerated_list enumtype="arabic" prefix="" suffix=")">
+ <list_item>
+ <paragraph>
+ Item 1).
+ <list_item>
+ <paragraph>
+ Item 2).
+ <list_item>
+ <paragraph>
+ Item 3).
+ <enumerated_list enumtype="arabic" prefix="(" suffix=")">
+ <list_item>
+ <paragraph>
+ Item (1).
+ <list_item>
+ <paragraph>
+ Item (2).
+ <list_item>
+ <paragraph>
+ Item (3).
+"""],
+["""\
+Nested enumerated lists:
+
+1. Item 1.
+
+ A) Item A).
+ B) Item B).
+ C) Item C).
+
+2. Item 2.
+
+ (a) Item (a).
+
+ I) Item I).
+ II) Item II).
+ III) Item III).
+
+ (b) Item (b).
+
+ (c) Item (c).
+
+ (i) Item (i).
+ (ii) Item (ii).
+ (iii) Item (iii).
+
+3. Item 3.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Nested enumerated lists:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item 1.
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=")">
+ <list_item>
+ <paragraph>
+ Item A).
+ <list_item>
+ <paragraph>
+ Item B).
+ <list_item>
+ <paragraph>
+ Item C).
+ <list_item>
+ <paragraph>
+ Item 2.
+ <enumerated_list enumtype="loweralpha" prefix="(" suffix=")">
+ <list_item>
+ <paragraph>
+ Item (a).
+ <enumerated_list enumtype="upperroman" prefix="" suffix=")">
+ <list_item>
+ <paragraph>
+ Item I).
+ <list_item>
+ <paragraph>
+ Item II).
+ <list_item>
+ <paragraph>
+ Item III).
+ <list_item>
+ <paragraph>
+ Item (b).
+ <list_item>
+ <paragraph>
+ Item (c).
+ <enumerated_list enumtype="lowerroman" prefix="(" suffix=")">
+ <list_item>
+ <paragraph>
+ Item (i).
+ <list_item>
+ <paragraph>
+ Item (ii).
+ <list_item>
+ <paragraph>
+ Item (iii).
+ <list_item>
+ <paragraph>
+ Item 3.
+"""],
+[u"""\
+A. Einstein was a great influence on
+B. Physicist, who was a colleague of
+C. Chemist. They all worked in
+Princeton, NJ.
+
+Using a non-breaking space as a workaround:
+
+A.\u00a0Einstein was a great influence on
+B. Physicist, who was a colleague of
+C. Chemist. They all worked in
+Princeton, NJ.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="upperalpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Einstein was a great influence on
+ <list_item>
+ <paragraph>
+ Physicist, who was a colleague of
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <paragraph>
+ C. Chemist. They all worked in
+ Princeton, NJ.
+ <paragraph>
+ Using a non-breaking space as a workaround:
+ <paragraph>
+ A.\xa0Einstein was a great influence on
+ B. Physicist, who was a colleague of
+ C. Chemist. They all worked in
+ Princeton, NJ.
+"""],
+["""\
+1. Item one: line 1,
+ line 2.
+2. Item two: line 1,
+ line 2.
+3. Item three: paragraph 1, line 1,
+ line 2.
+
+ Paragraph 2.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one: line 1,
+ line 2.
+ <list_item>
+ <paragraph>
+ Item two: line 1,
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <block_quote>
+ <paragraph>
+ line 2.
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Block quote ends without a blank line; unexpected unindent.
+ <enumerated_list enumtype="arabic" prefix="" start="3" suffix=".">
+ <list_item>
+ <paragraph>
+ Item three: paragraph 1, line 1,
+ <system_message level="1" line="5" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "3" (ordinal 3)
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <block_quote>
+ <paragraph>
+ line 2.
+ <block_quote>
+ <paragraph>
+ Paragraph 2.
+"""],
+["""\
+1. Item one.
+
+#. Item two.
+
+#. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+a. Item one.
+#. Item two.
+#. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="loweralpha" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+i. Item one.
+ii. Item two.
+#. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="lowerroman" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+#. Item one.
+#. Item two.
+#. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <list_item>
+ <paragraph>
+ Item two.
+ <list_item>
+ <paragraph>
+ Item three.
+"""],
+["""\
+1. Item one.
+#. Item two.
+3. Item three.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item one.
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <paragraph>
+ #. Item two.
+ 3. Item three.
+"""],
+["""\
+z.
+x
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ z.
+ x
+"""],
+["""\
+3-space indent, with a trailing space:
+
+1. \n\
+ foo
+
+3-space indent, no trailing space:
+
+1.
+ foo
+
+2-space indent:
+
+1.
+ foo
+
+1-space indent:
+
+1.
+ foo
+
+0-space indent, not a list item:
+
+1.
+foo
+
+No item content:
+
+1.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ 3-space indent, with a trailing space:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ foo
+ <paragraph>
+ 3-space indent, no trailing space:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ foo
+ <paragraph>
+ 2-space indent:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ foo
+ <paragraph>
+ 1-space indent:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ foo
+ <paragraph>
+ 0-space indent, not a list item:
+ <paragraph>
+ 1.
+ foo
+ <paragraph>
+ No item content:
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_field_lists.py b/test/test_parsers/test_rst/test_field_lists.py
new file mode 100755
index 000000000..2e715770c
--- /dev/null
+++ b/test/test_parsers/test_rst/test_field_lists.py
@@ -0,0 +1,551 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['field_lists'] = [
+["""\
+One-liners:
+
+:Author: Me
+
+:Version: 1
+
+:Date: 2001-08-11
+
+:Parameter i: integer
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ One-liners:
+ <field_list>
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ integer
+"""],
+["""\
+One-liners, no blank lines:
+
+:Author: Me
+:Version: 1
+:Date: 2001-08-11
+:Parameter i: integer
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ One-liners, no blank lines:
+ <field_list>
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ integer
+"""],
+["""\
+:field:
+empty item above, no blank line
+""",
+"""\
+<document source="test data">
+ <field_list>
+ <field>
+ <field_name>
+ field
+ <field_body>
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Field list ends without a blank line; unexpected unindent.
+ <paragraph>
+ empty item above, no blank line
+"""],
+["""\
+Field bodies starting on the next line:
+
+:Author:
+ Me
+:Version:
+ 1
+:Date:
+ 2001-08-11
+:Parameter i:
+ integer
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Field bodies starting on the next line:
+ <field_list>
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ integer
+"""],
+["""\
+One-paragraph, multi-liners:
+
+:Authors: Me,
+ Myself,
+ and I
+:Version: 1
+ or so
+:Date: 2001-08-11
+ (Saturday)
+:Parameter i: counter
+ (integer)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ One-paragraph, multi-liners:
+ <field_list>
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <paragraph>
+ Me,
+ Myself,
+ and I
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ or so
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ (Saturday)
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ counter
+ (integer)
+"""],
+["""\
+One-paragraph, multi-liners, not lined up:
+
+:Authors: Me,
+ Myself,
+ and I
+:Version: 1
+ or so
+:Date: 2001-08-11
+ (Saturday)
+:Parameter i: counter
+ (integer)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ One-paragraph, multi-liners, not lined up:
+ <field_list>
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <paragraph>
+ Me,
+ Myself,
+ and I
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ or so
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ (Saturday)
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ counter
+ (integer)
+"""],
+["""\
+Multiple body elements:
+
+:Authors: - Me
+ - Myself
+ - I
+
+:Abstract:
+ This is a field list item's body,
+ containing multiple elements.
+
+ Here's a literal block::
+
+ def f(x):
+ return x**2 + x
+
+ Even nested field lists are possible:
+
+ :Date: 2001-08-11
+ :Day: Saturday
+ :Time: 15:07
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Multiple body elements:
+ <field_list>
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Me
+ <list_item>
+ <paragraph>
+ Myself
+ <list_item>
+ <paragraph>
+ I
+ <field>
+ <field_name>
+ Abstract
+ <field_body>
+ <paragraph>
+ This is a field list item's body,
+ containing multiple elements.
+ <paragraph>
+ Here's a literal block:
+ <literal_block xml:space="preserve">
+ def f(x):
+ return x**2 + x
+ <paragraph>
+ Even nested field lists are possible:
+ <field_list>
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2001-08-11
+ <field>
+ <field_name>
+ Day
+ <field_body>
+ <paragraph>
+ Saturday
+ <field>
+ <field_name>
+ Time
+ <field_body>
+ <paragraph>
+ 15:07
+"""],
+["""\
+Nested field lists on one line:
+
+:field1: :field2: :field3: body
+:field4: :field5: :field6: body
+ :field7: body
+ :field8: body
+ :field9: body line 1
+ body line 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Nested field lists on one line:
+ <field_list>
+ <field>
+ <field_name>
+ field1
+ <field_body>
+ <field_list>
+ <field>
+ <field_name>
+ field2
+ <field_body>
+ <field_list>
+ <field>
+ <field_name>
+ field3
+ <field_body>
+ <paragraph>
+ body
+ <field>
+ <field_name>
+ field4
+ <field_body>
+ <field_list>
+ <field>
+ <field_name>
+ field5
+ <field_body>
+ <field_list>
+ <field>
+ <field_name>
+ field6
+ <field_body>
+ <paragraph>
+ body
+ <field>
+ <field_name>
+ field7
+ <field_body>
+ <paragraph>
+ body
+ <field>
+ <field_name>
+ field8
+ <field_body>
+ <paragraph>
+ body
+ <field>
+ <field_name>
+ field9
+ <field_body>
+ <paragraph>
+ body line 1
+ body line 2
+"""],
+["""\
+:Parameter i j k: multiple arguments
+""",
+"""\
+<document source="test data">
+ <field_list>
+ <field>
+ <field_name>
+ Parameter i j k
+ <field_body>
+ <paragraph>
+ multiple arguments
+"""],
+["""\
+:Field *name* `with` **inline** ``markup``: inline markup in
+ field name is parsed.
+""",
+"""\
+<document source="test data">
+ <field_list>
+ <field>
+ <field_name>
+ Field \n\
+ <emphasis>
+ name
+ \n\
+ <title_reference>
+ with
+ \n\
+ <strong>
+ inline
+ \n\
+ <literal>
+ markup
+ <field_body>
+ <paragraph>
+ inline markup in
+ field name is parsed.
+"""],
+["""\
+:Field name with *bad inline markup: should generate warning.
+""",
+"""\
+<document source="test data">
+ <field_list>
+ <field>
+ <field_name>
+ Field name with \n\
+ <problematic ids="id2" refid="id1">
+ *
+ bad inline markup
+ <field_body>
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <paragraph>
+ should generate warning.
+"""],
+[r"""Some edge cases:
+
+:Empty:
+:Author: Me
+No blank line before this paragraph.
+
+: Field: marker must not begin with whitespace.
+
+:Field : marker must not end with whitespace.
+
+Field: marker is missing its open-colon.
+
+:Field marker is missing its close-colon.
+
+:Field\: names\: with\: colons\:: are possible.
+
+:\\Field\ names with backslashes\\: are possible, too.
+
+:\\: A backslash.
+
+:Not a\\\: field list.
+
+:Not a \: field list either.
+
+:\: Not a field list either.
+
+:\:
+ A definition list, not a field list.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Some edge cases:
+ <field_list>
+ <field>
+ <field_name>
+ Empty
+ <field_body>
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Field list ends without a blank line; unexpected unindent.
+ <paragraph>
+ No blank line before this paragraph.
+ <paragraph>
+ : Field: marker must not begin with whitespace.
+ <paragraph>
+ :Field : marker must not end with whitespace.
+ <paragraph>
+ Field: marker is missing its open-colon.
+ <paragraph>
+ :Field marker is missing its close-colon.
+ <field_list>
+ <field>
+ <field_name>
+ Field: names: with: colons:
+ <field_body>
+ <paragraph>
+ are possible.
+ <field>
+ <field_name>
+ \\Field names with backslashes\\
+ <field_body>
+ <paragraph>
+ are possible, too.
+ <field>
+ <field_name>
+ \\
+ <field_body>
+ <paragraph>
+ A backslash.
+ <paragraph>
+ :Not a\\: field list.
+ <paragraph>
+ :Not a : field list either.
+ <paragraph>
+ :: Not a field list either.
+ <definition_list>
+ <definition_list_item>
+ <term>
+ ::
+ <definition>
+ <paragraph>
+ A definition list, not a field list.
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_footnotes.py b/test/test_parsers/test_rst/test_footnotes.py
new file mode 100755
index 000000000..cca255cbc
--- /dev/null
+++ b/test/test_parsers/test_rst/test_footnotes.py
@@ -0,0 +1,332 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['footnotes'] = [
+["""\
+.. [1] This is a footnote.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ This is a footnote.
+"""],
+["""\
+.. [1] This is a footnote
+ on multiple lines.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ This is a footnote
+ on multiple lines.
+"""],
+["""\
+.. [1] This is a footnote
+ on multiple lines with more space.
+
+.. [2] This is a footnote
+ on multiple lines with less space.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ This is a footnote
+ on multiple lines with more space.
+ <footnote ids="id2" names="2">
+ <label>
+ 2
+ <paragraph>
+ This is a footnote
+ on multiple lines with less space.
+"""],
+["""\
+.. [1]
+ This is a footnote on multiple lines
+ whose block starts on line 2.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ This is a footnote on multiple lines
+ whose block starts on line 2.
+"""],
+["""\
+.. [1]
+
+That was an empty footnote.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ That was an empty footnote.
+"""],
+["""\
+.. [1]
+No blank line.
+""",
+"""\
+<document source="test data">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ No blank line.
+"""],
+]
+
+totest['auto_numbered_footnotes'] = [
+["""\
+[#]_ is the first auto-numbered footnote reference.
+[#]_ is the second auto-numbered footnote reference.
+
+.. [#] Auto-numbered footnote 1.
+.. [#] Auto-numbered footnote 2.
+.. [#] Auto-numbered footnote 3.
+
+[#]_ is the third auto-numbered footnote reference.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1">
+ is the first auto-numbered footnote reference.
+ <footnote_reference auto="1" ids="id2">
+ is the second auto-numbered footnote reference.
+ <footnote auto="1" ids="id3">
+ <paragraph>
+ Auto-numbered footnote 1.
+ <footnote auto="1" ids="id4">
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" ids="id5">
+ <paragraph>
+ Auto-numbered footnote 3.
+ <paragraph>
+ <footnote_reference auto="1" ids="id6">
+ is the third auto-numbered footnote reference.
+"""],
+["""\
+[#third]_ is a reference to the third auto-numbered footnote.
+
+.. [#first] First auto-numbered footnote.
+.. [#second] Second auto-numbered footnote.
+.. [#third] Third auto-numbered footnote.
+
+[#second]_ is a reference to the second auto-numbered footnote.
+[#first]_ is a reference to the first auto-numbered footnote.
+[#third]_ is another reference to the third auto-numbered footnote.
+
+Here are some internal cross-references to the targets generated by
+the footnotes: first_, second_, third_.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refname="third">
+ is a reference to the third auto-numbered footnote.
+ <footnote auto="1" ids="first" names="first">
+ <paragraph>
+ First auto-numbered footnote.
+ <footnote auto="1" ids="second" names="second">
+ <paragraph>
+ Second auto-numbered footnote.
+ <footnote auto="1" ids="third" names="third">
+ <paragraph>
+ Third auto-numbered footnote.
+ <paragraph>
+ <footnote_reference auto="1" ids="id2" refname="second">
+ is a reference to the second auto-numbered footnote.
+ <footnote_reference auto="1" ids="id3" refname="first">
+ is a reference to the first auto-numbered footnote.
+ <footnote_reference auto="1" ids="id4" refname="third">
+ is another reference to the third auto-numbered footnote.
+ <paragraph>
+ Here are some internal cross-references to the targets generated by
+ the footnotes: \n\
+ <reference name="first" refname="first">
+ first
+ , \n\
+ <reference name="second" refname="second">
+ second
+ , \n\
+ <reference name="third" refname="third">
+ third
+ .
+"""],
+["""\
+Mixed anonymous and labelled auto-numbered footnotes:
+
+[#four]_ should be 4, [#]_ should be 1,
+[#]_ should be 3, [#]_ is one too many,
+[#two]_ should be 2, and [#six]_ doesn't exist.
+
+.. [#] Auto-numbered footnote 1.
+.. [#two] Auto-numbered footnote 2.
+.. [#] Auto-numbered footnote 3.
+.. [#four] Auto-numbered footnote 4.
+.. [#five] Auto-numbered footnote 5.
+.. [#five] Auto-numbered footnote 5 again (duplicate).
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed anonymous and labelled auto-numbered footnotes:
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refname="four">
+ should be 4, \n\
+ <footnote_reference auto="1" ids="id2">
+ should be 1,
+ <footnote_reference auto="1" ids="id3">
+ should be 3, \n\
+ <footnote_reference auto="1" ids="id4">
+ is one too many,
+ <footnote_reference auto="1" ids="id5" refname="two">
+ should be 2, and \n\
+ <footnote_reference auto="1" ids="id6" refname="six">
+ doesn't exist.
+ <footnote auto="1" ids="id7">
+ <paragraph>
+ Auto-numbered footnote 1.
+ <footnote auto="1" ids="two" names="two">
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" ids="id8">
+ <paragraph>
+ Auto-numbered footnote 3.
+ <footnote auto="1" ids="four" names="four">
+ <paragraph>
+ Auto-numbered footnote 4.
+ <footnote auto="1" dupnames="five" ids="five">
+ <paragraph>
+ Auto-numbered footnote 5.
+ <footnote auto="1" dupnames="five" ids="id9">
+ <system_message backrefs="id9" level="2" line="12" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "five".
+ <paragraph>
+ Auto-numbered footnote 5 again (duplicate).
+"""],
+["""\
+Mixed manually-numbered, anonymous auto-numbered,
+and labelled auto-numbered footnotes:
+
+[#four]_ should be 4, [#]_ should be 2,
+[1]_ is 1, [3]_ is 3,
+[#]_ should be 6, [#]_ is one too many,
+[#five]_ should be 5, and [#six]_ doesn't exist.
+
+.. [1] Manually-numbered footnote 1.
+.. [#] Auto-numbered footnote 2.
+.. [#four] Auto-numbered footnote 4.
+.. [3] Manually-numbered footnote 3
+.. [#five] Auto-numbered footnote 5.
+.. [#five] Auto-numbered footnote 5 again (duplicate).
+.. [#] Auto-numbered footnote 6.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed manually-numbered, anonymous auto-numbered,
+ and labelled auto-numbered footnotes:
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refname="four">
+ should be 4, \n\
+ <footnote_reference auto="1" ids="id2">
+ should be 2,
+ <footnote_reference ids="id3" refname="1">
+ 1
+ is 1, \n\
+ <footnote_reference ids="id4" refname="3">
+ 3
+ is 3,
+ <footnote_reference auto="1" ids="id5">
+ should be 6, \n\
+ <footnote_reference auto="1" ids="id6">
+ is one too many,
+ <footnote_reference auto="1" ids="id7" refname="five">
+ should be 5, and \n\
+ <footnote_reference auto="1" ids="id8" refname="six">
+ doesn't exist.
+ <footnote ids="id9" names="1">
+ <label>
+ 1
+ <paragraph>
+ Manually-numbered footnote 1.
+ <footnote auto="1" ids="id10">
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" ids="four" names="four">
+ <paragraph>
+ Auto-numbered footnote 4.
+ <footnote ids="id11" names="3">
+ <label>
+ 3
+ <paragraph>
+ Manually-numbered footnote 3
+ <footnote auto="1" dupnames="five" ids="five">
+ <paragraph>
+ Auto-numbered footnote 5.
+ <footnote auto="1" dupnames="five" ids="id12">
+ <system_message backrefs="id12" level="2" line="14" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "five".
+ <paragraph>
+ Auto-numbered footnote 5 again (duplicate).
+ <footnote auto="1" ids="id13">
+ <paragraph>
+ Auto-numbered footnote 6.
+"""],
+]
+
+totest['auto_symbol_footnotes'] = [
+["""\
+.. [*] This is an auto-symbol footnote.
+""",
+"""\
+<document source="test data">
+ <footnote auto="*" ids="id1">
+ <paragraph>
+ This is an auto-symbol footnote.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_functions.py b/test/test_parsers/test_rst/test_functions.py
new file mode 100755
index 000000000..e6694b2c5
--- /dev/null
+++ b/test/test_parsers/test_rst/test_functions.py
@@ -0,0 +1,38 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+import unittest
+from __init__ import DocutilsTestSupport
+states = DocutilsTestSupport.states
+
+
+class FuctionTests(unittest.TestCase):
+
+ escaped = r'escapes: \*one, \\*two, \\\*three'
+ nulled = 'escapes: \x00*one, \x00\\*two, \x00\\\x00*three'
+ unescaped = r'escapes: *one, \*two, \*three'
+
+ def test_escape2null(self):
+ nulled = states.escape2null(self.escaped)
+ self.assertEquals(nulled, self.nulled)
+ nulled = states.escape2null(self.escaped + '\\')
+ self.assertEquals(nulled, self.nulled + '\x00')
+
+ def test_unescape(self):
+ unescaped = states.unescape(self.nulled)
+ self.assertEquals(unescaped, self.unescaped)
+ restored = states.unescape(self.nulled, 1)
+ self.assertEquals(restored, self.escaped)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_parsers/test_rst/test_inline_markup.py b/test/test_parsers/test_rst/test_inline_markup.py
new file mode 100755
index 000000000..7185d723d
--- /dev/null
+++ b/test/test_parsers/test_rst/test_inline_markup.py
@@ -0,0 +1,924 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for inline markup in docutils/parsers/rst/states.py.
+Interpreted text tests are in a separate module, test_interpreted.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['emphasis'] = [
+["""\
+*emphasis*
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <emphasis>
+ emphasis
+"""],
+["""\
+*emphasized sentence
+across lines*
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <emphasis>
+ emphasized sentence
+ across lines
+"""],
+["""\
+*emphasis without closing asterisk
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ *
+ emphasis without closing asterisk
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+"""],
+["""\
+'*emphasis*' and 1/*emphasis*/2 and 3-*emphasis*-4 and 5:*emphasis*:6
+but not '*' or '"*"' or x*2* or 2*x* or \\*args or *
+or *the\\* *stars\\\\\\* *inside*
+
+(however, '*args' will trigger a warning and may be problematic)
+
+what about *this**?
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ '
+ <emphasis>
+ emphasis
+ ' and 1/
+ <emphasis>
+ emphasis
+ /2 and 3-
+ <emphasis>
+ emphasis
+ -4 and 5:
+ <emphasis>
+ emphasis
+ :6
+ but not '*' or '"*"' or x*2* or 2*x* or *args or *
+ or \n\
+ <emphasis>
+ the* *stars\* *inside
+ <paragraph>
+ (however, '
+ <problematic ids="id2" refid="id1">
+ *
+ args' will trigger a warning and may be problematic)
+ <system_message backrefs="id2" ids="id1" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+ <paragraph>
+ what about \n\
+ <emphasis>
+ this*
+ ?
+"""],
+["""\
+Emphasized asterisk: *\\**
+
+Emphasized double asterisk: *\\***
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Emphasized asterisk: \n\
+ <emphasis>
+ *
+ <paragraph>
+ Emphasized double asterisk: \n\
+ <emphasis>
+ **
+"""],
+]
+
+totest['strong'] = [
+["""\
+**strong**
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <strong>
+ strong
+"""],
+["""\
+(**strong**) but not (**) or '(** ' or x**2 or \\**kwargs or **
+
+(however, '**kwargs' will trigger a warning and may be problematic)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ (
+ <strong>
+ strong
+ ) but not (**) or '(** ' or x**2 or **kwargs or **
+ <paragraph>
+ (however, '
+ <problematic ids="id2" refid="id1">
+ **
+ kwargs' will trigger a warning and may be problematic)
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Inline strong start-string without end-string.
+"""],
+["""\
+Strong asterisk: *****
+
+Strong double asterisk: ******
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Strong asterisk: \n\
+ <strong>
+ *
+ <paragraph>
+ Strong double asterisk: \n\
+ <strong>
+ **
+"""],
+["""\
+**strong without closing asterisks
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ **
+ strong without closing asterisks
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline strong start-string without end-string.
+"""],
+]
+
+totest['literal'] = [
+["""\
+``literal``
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <literal>
+ literal
+"""],
+["""\
+``\\literal``
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <literal>
+ \\literal
+"""],
+["""\
+``lite\\ral``
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <literal>
+ lite\\ral
+"""],
+["""\
+``literal\\``
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <literal>
+ literal\\
+"""],
+["""\
+``literal ``TeX quotes'' & \\backslash`` but not "``" or ``
+
+(however, ``standalone TeX quotes'' will trigger a warning
+and may be problematic)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <literal>
+ literal ``TeX quotes'' & \\backslash
+ but not "``" or ``
+ <paragraph>
+ (however, \n\
+ <problematic ids="id2" refid="id1">
+ ``
+ standalone TeX quotes'' will trigger a warning
+ and may be problematic)
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+"""],
+["""\
+Find the ```interpreted text``` in this paragraph!
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Find the \n\
+ <literal>
+ `interpreted text`
+ in this paragraph!
+"""],
+["""\
+``literal without closing backquotes
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ ``
+ literal without closing backquotes
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline literal start-string without end-string.
+"""],
+["""\
+Python ``list``\\s use square bracket syntax.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Python \n\
+ <literal>
+ list
+ s use square bracket syntax.
+"""],
+]
+
+totest['references'] = [
+["""\
+ref_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="ref" refname="ref">
+ ref
+"""],
+["""\
+ref__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="ref">
+ ref
+"""],
+["""\
+ref_, r_, r_e-f_, -ref_, and anonymousref__,
+but not _ref_ or __attr__ or object.__attr__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="ref" refname="ref">
+ ref
+ , \n\
+ <reference name="r" refname="r">
+ r
+ , \n\
+ <reference name="r_e-f" refname="r_e-f">
+ r_e-f
+ , -
+ <reference name="ref" refname="ref">
+ ref
+ , and \n\
+ <reference anonymous="1" name="anonymousref">
+ anonymousref
+ ,
+ but not _ref_ or __attr__ or object.__attr__
+"""],
+]
+
+totest['phrase_references'] = [
+["""\
+`phrase reference`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="phrase reference" refname="phrase reference">
+ phrase reference
+"""],
+["""\
+`anonymous reference`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="anonymous reference">
+ anonymous reference
+"""],
+["""\
+`phrase reference
+across lines`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="phrase reference across lines" refname="phrase reference across lines">
+ phrase reference
+ across lines
+"""],
+["""\
+`phrase\`_ reference`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="phrase`_ reference" refname="phrase`_ reference">
+ phrase`_ reference
+"""],
+["""\
+Invalid phrase reference:
+
+:role:`phrase reference`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Invalid phrase reference:
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :role:`phrase reference`_
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Mismatch: both interpreted text role prefix and reference suffix.
+"""],
+["""\
+Invalid phrase reference:
+
+`phrase reference`:role:_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Invalid phrase reference:
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ `phrase reference`:role:_
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Mismatch: both interpreted text role suffix and reference suffix.
+"""],
+["""\
+`phrase reference_ without closing backquote
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ `
+ phrase \n\
+ <reference name="reference" refname="reference">
+ reference
+ without closing backquote
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+"""],
+["""\
+`anonymous phrase reference__ without closing backquote
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ `
+ anonymous phrase \n\
+ <reference anonymous="1" name="reference">
+ reference
+ without closing backquote
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+"""],
+]
+
+totest['embedded_URIs'] = [
+["""\
+`phrase reference <http://example.com>`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="phrase reference" refuri="http://example.com">
+ phrase reference
+ <target ids="phrase-reference" names="phrase\ reference" refuri="http://example.com">
+"""],
+["""\
+`anonymous reference <http://example.com>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="anonymous reference" refuri="http://example.com">
+ anonymous reference
+"""],
+["""\
+`embedded URI on next line
+<http://example.com>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded URI on next line" refuri="http://example.com">
+ embedded URI on next line
+"""],
+["""\
+`embedded URI across lines <http://example.com/
+long/path>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded URI across lines" refuri="http://example.com/long/path">
+ embedded URI across lines
+"""],
+["""\
+`embedded URI with whitespace <http://example.com/
+long/path /and /whitespace>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded URI with whitespace" refuri="http://example.com/long/path/and/whitespace">
+ embedded URI with whitespace
+"""],
+["""\
+`embedded email address <jdoe@example.com>`__
+
+`embedded email address broken across lines <jdoe
+@example.com>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="embedded email address" refuri="mailto:jdoe@example.com">
+ embedded email address
+ <paragraph>
+ <reference name="embedded email address broken across lines" refuri="mailto:jdoe@example.com">
+ embedded email address broken across lines
+"""],
+["""\
+`embedded URI with too much whitespace < http://example.com/
+long/path /and /whitespace >`__
+
+`embedded URI with too much whitespace at end <http://example.com/
+long/path /and /whitespace >`__
+
+`embedded URI with no preceding whitespace<http://example.com>`__
+
+`escaped URI \\<http://example.com>`__
+
+See `HTML Anchors: \\<a>`_.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="embedded URI with too much whitespace < http://example.com/ long/path /and /whitespace >">
+ embedded URI with too much whitespace < http://example.com/
+ long/path /and /whitespace >
+ <paragraph>
+ <reference anonymous="1" name="embedded URI with too much whitespace at end <http://example.com/ long/path /and /whitespace >">
+ embedded URI with too much whitespace at end <http://example.com/
+ long/path /and /whitespace >
+ <paragraph>
+ <reference anonymous="1" name="embedded URI with no preceding whitespace<http://example.com>">
+ embedded URI with no preceding whitespace<http://example.com>
+ <paragraph>
+ <reference anonymous="1" name="escaped URI <http://example.com>">
+ escaped URI <http://example.com>
+ <paragraph>
+ See \n\
+ <reference name="HTML Anchors: <a>" refname="html anchors: <a>">
+ HTML Anchors: <a>
+ .
+"""],
+["""\
+Relative URIs' reference text can be omitted:
+
+`<reference>`_
+
+`<anonymous>`__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Relative URIs' reference text can be omitted:
+ <paragraph>
+ <reference name="reference" refuri="reference">
+ reference
+ <target ids="reference" names="reference" refuri="reference">
+ <paragraph>
+ <reference name="anonymous" refuri="anonymous">
+ anonymous
+"""],
+]
+
+totest['inline_targets'] = [
+["""\
+_`target`
+
+Here is _`another target` in some text. And _`yet
+another target`, spanning lines.
+
+_`Here is a TaRgeT` with case and spacial difficulties.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <target ids="target" names="target">
+ target
+ <paragraph>
+ Here is \n\
+ <target ids="another-target" names="another\ target">
+ another target
+ in some text. And \n\
+ <target ids="yet-another-target" names="yet\ another\ target">
+ yet
+ another target
+ , spanning lines.
+ <paragraph>
+ <target ids="here-is-a-target" names="here\ is\ a\ target">
+ Here is a TaRgeT
+ with case and spacial difficulties.
+"""],
+["""\
+But this isn't a _target; targets require backquotes.
+
+And _`this`_ is just plain confusing.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ But this isn't a _target; targets require backquotes.
+ <paragraph>
+ And \n\
+ <problematic ids="id2" refid="id1">
+ _`
+ this`_ is just plain confusing.
+ <system_message backrefs="id2" ids="id1" level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Inline target start-string without end-string.
+"""],
+["""\
+_`inline target without closing backquote
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ _`
+ inline target without closing backquote
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline target start-string without end-string.
+"""],
+]
+
+totest['footnote_reference'] = [
+["""\
+[1]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference ids="id1" refname="1">
+ 1
+"""],
+["""\
+[#]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1">
+"""],
+["""\
+[#label]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refname="label">
+"""],
+["""\
+[*]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="*" ids="id1">
+"""],
+]
+
+totest['citation_reference'] = [
+["""\
+[citation]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <citation_reference ids="id1" refname="citation">
+ citation
+"""],
+["""\
+[citation]_ and [cit-ation]_ and [cit.ation]_ and [CIT1]_ but not [CIT 1]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <citation_reference ids="id1" refname="citation">
+ citation
+ and \n\
+ <citation_reference ids="id2" refname="cit-ation">
+ cit-ation
+ and \n\
+ <citation_reference ids="id3" refname="cit.ation">
+ cit.ation
+ and \n\
+ <citation_reference ids="id4" refname="cit1">
+ CIT1
+ but not [CIT 1]_
+"""],
+]
+
+totest['substitution_references'] = [
+["""\
+|subref|
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <substitution_reference refname="subref">
+ subref
+"""],
+["""\
+|subref|_ and |subref|__
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference refname="subref">
+ <substitution_reference refname="subref">
+ subref
+ and \n\
+ <reference anonymous="1">
+ <substitution_reference refname="subref">
+ subref
+"""],
+["""\
+|substitution reference|
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <substitution_reference refname="substitution reference">
+ substitution reference
+"""],
+["""\
+|substitution
+reference|
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <substitution_reference refname="substitution reference">
+ substitution
+ reference
+"""],
+["""\
+|substitution reference without closing verbar
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ |
+ substitution reference without closing verbar
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline substitution_reference start-string without end-string.
+"""],
+["""\
+first | then || and finally |||
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ first | then || and finally |||
+"""],
+]
+
+totest['standalone_hyperlink'] = [
+["""\
+http://www.standalone.hyperlink.com
+
+http:/one-slash-only.absolute.path
+
+[http://example.com]
+
+(http://example.com)
+
+<http://example.com>
+
+http://[1080:0:0:0:8:800:200C:417A]/IPv6address.html
+
+http://[3ffe:2a00:100:7031::1] (the final "]" is ambiguous in text)
+
+http://[3ffe:2a00:100:7031::1]/
+
+mailto:someone@somewhere.com
+
+news:comp.lang.python
+
+An email address in a sentence: someone@somewhere.com.
+
+ftp://ends.with.a.period.
+
+(a.question.mark@end?)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference refuri="http://www.standalone.hyperlink.com">
+ http://www.standalone.hyperlink.com
+ <paragraph>
+ <reference refuri="http:/one-slash-only.absolute.path">
+ http:/one-slash-only.absolute.path
+ <paragraph>
+ [
+ <reference refuri="http://example.com">
+ http://example.com
+ ]
+ <paragraph>
+ (
+ <reference refuri="http://example.com">
+ http://example.com
+ )
+ <paragraph>
+ <
+ <reference refuri="http://example.com">
+ http://example.com
+ >
+ <paragraph>
+ <reference refuri="http://[1080:0:0:0:8:800:200C:417A]/IPv6address.html">
+ http://[1080:0:0:0:8:800:200C:417A]/IPv6address.html
+ <paragraph>
+ <reference refuri="http://[3ffe:2a00:100:7031::1">
+ http://[3ffe:2a00:100:7031::1
+ ] (the final "]" is ambiguous in text)
+ <paragraph>
+ <reference refuri="http://[3ffe:2a00:100:7031::1]/">
+ http://[3ffe:2a00:100:7031::1]/
+ <paragraph>
+ <reference refuri="mailto:someone@somewhere.com">
+ mailto:someone@somewhere.com
+ <paragraph>
+ <reference refuri="news:comp.lang.python">
+ news:comp.lang.python
+ <paragraph>
+ An email address in a sentence: \n\
+ <reference refuri="mailto:someone@somewhere.com">
+ someone@somewhere.com
+ .
+ <paragraph>
+ <reference refuri="ftp://ends.with.a.period">
+ ftp://ends.with.a.period
+ .
+ <paragraph>
+ (
+ <reference refuri="mailto:a.question.mark@end">
+ a.question.mark@end
+ ?)
+"""],
+["""\
+Valid URLs with escaped markup characters:
+
+http://example.com/\\*content\\*/whatever
+
+http://example.com/\\*content*/whatever
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Valid URLs with escaped markup characters:
+ <paragraph>
+ <reference refuri="http://example.com/*content*/whatever">
+ http://example.com/*content*/whatever
+ <paragraph>
+ <reference refuri="http://example.com/*content*/whatever">
+ http://example.com/*content*/whatever
+"""],
+["""\
+Valid URLs may end with punctuation inside "<>":
+
+<http://example.org/ends-with-dot.>
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Valid URLs may end with punctuation inside "<>":
+ <paragraph>
+ <
+ <reference refuri="http://example.org/ends-with-dot.">
+ http://example.org/ends-with-dot.
+ >
+"""],
+["""\
+Valid URLs with interesting endings:
+
+http://example.org/ends-with-pluses++
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Valid URLs with interesting endings:
+ <paragraph>
+ <reference refuri="http://example.org/ends-with-pluses++">
+ http://example.org/ends-with-pluses++
+"""],
+["""\
+None of these are standalone hyperlinks (their "schemes"
+are not recognized): signal:noise, a:b.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ None of these are standalone hyperlinks (their "schemes"
+ are not recognized): signal:noise, a:b.
+"""],
+["""\
+Escaped email addresses are not recognized: test\@example.org
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Escaped email addresses are not recognized: test@example.org
+"""],
+]
+
+totest['miscellaneous'] = [
+["""\
+__This__ should be left alone.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ __This__ should be left alone.
+"""],
+[r"""
+Character-level m\ *a*\ **r**\ ``k``\ `u`:title:\p
+with backslash-escaped whitespace, including new\
+lines.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Character-level m
+ <emphasis>
+ a
+ <strong>
+ r
+ <literal>
+ k
+ <title_reference>
+ u
+ p
+ with backslash-escaped whitespace, including newlines.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_interpreted.py b/test/test_parsers/test_rst/test_interpreted.py
new file mode 100755
index 000000000..a5392d497
--- /dev/null
+++ b/test/test_parsers/test_rst/test_interpreted.py
@@ -0,0 +1,305 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for interpreted text in docutils/parsers/rst/states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['basics'] = [
+["""\
+`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+"""],
+["""\
+:title:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+"""],
+["""\
+`interpreted`:title:
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+"""],
+["""\
+`interpreted \`title``
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted `title`
+"""],
+["""\
+:title:`:not-role: interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ :not-role: interpreted
+"""],
+["""\
+`interpreted` but not \\`interpreted` [`] or ({[`] or [`]}) or `
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+ but not `interpreted` [`] or ({[`] or [`]}) or `
+"""],
+["""\
+`interpreted`-text `interpreted`: text `interpreted`:text `text`'s interpreted
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+ -text \n\
+ <title_reference>
+ interpreted
+ : text \n\
+ <title_reference>
+ interpreted
+ :text \n\
+ <title_reference>
+ text
+ 's interpreted
+"""],
+["""\
+`interpreted without closing backquote
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ `
+ interpreted without closing backquote
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline interpreted text or phrase reference start-string without end-string.
+"""],
+["""\
+`interpreted`:not a role if it contains whitespace:
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <title_reference>
+ interpreted
+ :not a role if it contains whitespace:
+"""],
+["""\
+:title:`` (empty interpteted text not recognized)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ :title:`` (empty interpteted text not recognized)
+"""],
+["""\
+Explicit roles for standard inline markup:
+:emphasis:`emphasis`,
+:strong:`strong`,
+:literal:`inline literal text`.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Explicit roles for standard inline markup:
+ <emphasis>
+ emphasis
+ ,
+ <strong>
+ strong
+ ,
+ <literal>
+ inline literal text
+ .
+"""],
+["""\
+Simple explicit roles:
+:ab:`abbreviation`,
+:ac:`acronym`,
+:sup:`superscript`,
+:sub:`subscript`,
+:title:`title reference`.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Simple explicit roles:
+ <abbreviation>
+ abbreviation
+ ,
+ <acronym>
+ acronym
+ ,
+ <superscript>
+ superscript
+ ,
+ <subscript>
+ subscript
+ ,
+ <title_reference>
+ title reference
+ .
+"""],
+]
+
+totest['references'] = [
+["""\
+:PEP:`0`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference refuri="http://www.python.org/peps/pep-0000.html">
+ PEP 0
+"""],
+["""\
+:PEP:`-1`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :PEP:`-1`
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ PEP number must be a number from 0 to 9999; "-1" is invalid.
+"""],
+["""\
+:RFC:`2822`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference refuri="http://www.faqs.org/rfcs/rfc2822.html">
+ RFC 2822
+"""],
+["""\
+:RFC:`0`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :RFC:`0`
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ RFC number must be a number greater than or equal to 1; "0" is invalid.
+"""],
+]
+
+totest['unknown_roles'] = [
+["""\
+:role:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :role:`interpreted`
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "role" in module "docutils.parsers.rst.languages.en".
+ Trying "role" as canonical role name.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "role".
+"""],
+["""\
+`interpreted`:role:
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ `interpreted`:role:
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "role" in module "docutils.parsers.rst.languages.en".
+ Trying "role" as canonical role name.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "role".
+"""],
+["""\
+:role:`interpreted`:role:
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :role:`interpreted`:role:
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Multiple roles in interpreted text (both prefix and suffix present; only one allowed).
+"""],
+["""\
+:very.long-role_name:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :very.long-role_name:`interpreted`
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "very.long-role_name" in module "docutils.parsers.rst.languages.en".
+ Trying "very.long-role_name" as canonical role name.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown interpreted text role "very.long-role_name".
+"""],
+["""\
+:restructuredtext-unimplemented-role:`interpreted`
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ :restructuredtext-unimplemented-role:`interpreted`
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ No role entry for "restructuredtext-unimplemented-role" in module "docutils.parsers.rst.languages.en".
+ Trying "restructuredtext-unimplemented-role" as canonical role name.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Interpreted text role "restructuredtext-unimplemented-role" not implemented.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_line_blocks.py b/test/test_parsers/test_rst/test_line_blocks.py
new file mode 100755
index 000000000..10eaa8354
--- /dev/null
+++ b/test/test_parsers/test_rst/test_line_blocks.py
@@ -0,0 +1,310 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['line_blocks'] = [
+["""\
+| This is a line block.
+| Line breaks are *preserved*.
+
+| This is a second line block.
+
+| This is a third.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ This is a line block.
+ <line>
+ Line breaks are \n\
+ <emphasis>
+ preserved
+ .
+ <line_block>
+ <line>
+ This is a second line block.
+ <line_block>
+ <line>
+ This is a third.
+"""],
+["""\
+| In line blocks,
+| Initial indentation is *also* preserved.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ In line blocks,
+ <line_block>
+ <line>
+ Initial indentation is \n\
+ <emphasis>
+ also
+ preserved.
+"""],
+["""\
+| Individual lines in line blocks
+ *may* wrap, as indicated by the lack of a vertical bar prefix.
+| These are called "continuation lines".
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ Individual lines in line blocks
+ <emphasis>
+ may
+ wrap, as indicated by the lack of a vertical bar prefix.
+ <line>
+ These are called "continuation lines".
+"""],
+["""\
+| Inline markup in line blocks may also wrap *to
+ continuation lines*.
+| But not to following lines.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ Inline markup in line blocks may also wrap \n\
+ <emphasis>
+ to
+ continuation lines
+ .
+ <line>
+ But not to following lines.
+"""],
+["""\
+\\| This is not a line block.
+The vertical bar is simply part of a paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ | This is not a line block.
+ The vertical bar is simply part of a paragraph.
+"""],
+["""\
+| This line block is incomplete.
+There should be a blank line before this paragraph.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ This line block is incomplete.
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Line block ends without a blank line.
+ <paragraph>
+ There should be a blank line before this paragraph.
+"""],
+["""\
+| This line block contains
+|
+| blank lines.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ This line block contains
+ <line>
+ <line>
+ blank lines.
+"""],
+["""\
+| The blank lines in this block
+| \n\
+| \n\
+| have bogus spaces.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ The blank lines in this block
+ <line>
+ <line>
+ <line>
+ have bogus spaces.
+"""],
+["""\
+| Initial indentation is also significant and preserved:
+|
+| Indented 4 spaces
+| Not indented
+| Indented 2 spaces
+| Indented 4 spaces
+| Only one space
+|
+| Continuation lines may be indented less
+ than their base lines.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ Initial indentation is also significant and preserved:
+ <line>
+ <line_block>
+ <line>
+ Indented 4 spaces
+ <line>
+ Not indented
+ <line_block>
+ <line_block>
+ <line>
+ Indented 2 spaces
+ <line_block>
+ <line>
+ Indented 4 spaces
+ <line>
+ Only one space
+ <line>
+ <line_block>
+ <line>
+ Continuation lines may be indented less
+ than their base lines.
+"""],
+["""\
+|
+| This block begins and ends with blank lines.
+|
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ <line>
+ This block begins and ends with blank lines.
+ <line>
+"""],
+["""\
+This is not
+| a line block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ This is not
+ | a line block.
+"""],
+["""\
+| The first line is indented.
+| The second line is more indented.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ The first line is indented.
+ <line_block>
+ <line>
+ The second line is more indented.
+"""],
+["""\
+| The first line is indented.
+| The second line is less indented.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line_block>
+ <line>
+ The first line is indented.
+ <line>
+ The second line is less indented.
+"""],
+["""\
+|This is not
+|a line block
+
+| This is an
+|incomplete line block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ |
+ This is not
+ <problematic ids="id4" refid="id3">
+ |
+ a line block
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline substitution_reference start-string without end-string.
+ <system_message backrefs="id4" ids="id3" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline substitution_reference start-string without end-string.
+ <line_block>
+ <line>
+ This is an
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Line block ends without a blank line.
+ <paragraph>
+ <problematic ids="id6" refid="id5">
+ |
+ incomplete line block.
+ <system_message backrefs="id6" ids="id5" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Inline substitution_reference start-string without end-string.
+"""],
+["""\
+| Inline markup *may not
+| wrap* over several lines.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ Inline markup \n\
+ <problematic ids="id2" refid="id1">
+ *
+ may not
+ <line>
+ wrap* over several lines.
+ <system_message backrefs="id2" ids="id1" level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Inline emphasis start-string without end-string.
+"""],
+["""\
+| * Block level markup
+| * is not recognized.
+""",
+"""\
+<document source="test data">
+ <line_block>
+ <line>
+ * Block level markup
+ <line>
+ * is not recognized.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_literal_blocks.py b/test/test_parsers/test_rst/test_literal_blocks.py
new file mode 100755
index 000000000..332e0eb27
--- /dev/null
+++ b/test/test_parsers/test_rst/test_literal_blocks.py
@@ -0,0 +1,371 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['indented_literal_blocks'] = [
+["""\
+A paragraph::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph with a space after the colons:: \n\
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph with a space after the colons:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph::
+
+ A literal block.
+
+Another paragraph::
+
+ Another literal block.
+ With two blank lines following.
+
+
+A final paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+ <paragraph>
+ Another paragraph:
+ <literal_block xml:space="preserve">
+ Another literal block.
+ With two blank lines following.
+ <paragraph>
+ A final paragraph.
+"""],
+["""\
+A paragraph
+on more than
+one line::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph
+ on more than
+ one line:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph
+on more than
+one line::
+ A literal block
+ with no blank line above.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph
+ on more than
+ one line:
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Unexpected indentation.
+ <literal_block xml:space="preserve">
+ A literal block
+ with no blank line above.
+"""],
+["""\
+A paragraph::
+
+ A literal block.
+no blank line
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Literal block ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+"""],
+[r"""
+A paragraph\\::
+
+ A literal block.
+
+A paragraph\::
+
+ Not a literal block.
+""",
+r"""<document source="test data">
+ <paragraph>
+ A paragraph\:
+ <literal_block xml:space="preserve">
+ A literal block.
+ <paragraph>
+ A paragraph::
+ <block_quote>
+ <paragraph>
+ Not a literal block.
+"""],
+[r"""
+\\::
+
+ A literal block.
+
+\::
+
+ Not a literal block.
+""",
+r"""<document source="test data">
+ <paragraph>
+ \:
+ <literal_block xml:space="preserve">
+ A literal block.
+ <paragraph>
+ ::
+ <block_quote>
+ <paragraph>
+ Not a literal block.
+"""],
+["""\
+A paragraph: ::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph:
+
+::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph:
+::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Possible title underline, too short for the title.
+ Treating it as ordinary text because it's so short.
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph:
+
+::
+
+ A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A literal block.
+"""],
+["""\
+A paragraph::
+
+Not a literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Literal block expected; none found.
+ <paragraph>
+ Not a literal block.
+"""],
+["""\
+A paragraph::
+
+ A wonky literal block.
+ Literal line 2.
+
+ Literal line 3.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ A wonky literal block.
+ Literal line 2.
+ \n\
+ Literal line 3.
+"""],
+["""\
+EOF, even though a literal block is indicated::
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ EOF, even though a literal block is indicated:
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Literal block expected; none found.
+"""],
+]
+
+totest['quoted_literal_blocks'] = [
+["""\
+A paragraph::
+
+> A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+"""],
+["""\
+A paragraph::
+
+
+> A literal block.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+"""],
+["""\
+A paragraph::
+
+> A literal block.
+> Line 2.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+ > Line 2.
+"""],
+["""\
+A paragraph::
+
+> A literal block.
+ Indented line.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Unexpected indentation.
+ <block_quote>
+ <paragraph>
+ Indented line.
+"""],
+["""\
+A paragraph::
+
+> A literal block.
+Text.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Inconsistent literal block quoting.
+ <paragraph>
+ Text.
+"""],
+["""\
+A paragraph::
+
+> A literal block.
+$ Inconsistent line.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph:
+ <literal_block xml:space="preserve">
+ > A literal block.
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Inconsistent literal block quoting.
+ <paragraph>
+ $ Inconsistent line.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_option_lists.py b/test/test_parsers/test_rst/test_option_lists.py
new file mode 100755
index 000000000..a5afc498b
--- /dev/null
+++ b/test/test_parsers/test_rst/test_option_lists.py
@@ -0,0 +1,756 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['option_lists'] = [
+["""\
+Short options:
+
+-a option -a
+
+-b file option -b
+
+-c name option -c
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Short options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -c
+ <option_argument delimiter=" ">
+ name
+ <description>
+ <paragraph>
+ option -c
+"""],
+["""\
+Long options:
+
+--aaaa option --aaaa
+--bbbb=file option --bbbb
+--cccc name option --cccc
+--d-e-f-g option --d-e-f-g
+--h_i_j_k option --h_i_j_k
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Long options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --aaaa
+ <description>
+ <paragraph>
+ option --aaaa
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --bbbb
+ <option_argument delimiter="=">
+ file
+ <description>
+ <paragraph>
+ option --bbbb
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --cccc
+ <option_argument delimiter=" ">
+ name
+ <description>
+ <paragraph>
+ option --cccc
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --d-e-f-g
+ <description>
+ <paragraph>
+ option --d-e-f-g
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --h_i_j_k
+ <description>
+ <paragraph>
+ option --h_i_j_k
+"""],
+["""\
+Old GNU-style options:
+
++a option +a
+
++b file option +b
+
++c name option +c
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Old GNU-style options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ +a
+ <description>
+ <paragraph>
+ option +a
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ +b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option +b
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ +c
+ <option_argument delimiter=" ">
+ name
+ <description>
+ <paragraph>
+ option +c
+"""],
+["""\
+VMS/DOS-style options:
+
+/A option /A
+/B file option /B
+/CCC option /CCC
+/DDD string option /DDD
+/EEE=int option /EEE
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ VMS/DOS-style options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /A
+ <description>
+ <paragraph>
+ option /A
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /B
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option /B
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /CCC
+ <description>
+ <paragraph>
+ option /CCC
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /DDD
+ <option_argument delimiter=" ">
+ string
+ <description>
+ <paragraph>
+ option /DDD
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /EEE
+ <option_argument delimiter="=">
+ int
+ <description>
+ <paragraph>
+ option /EEE
+"""],
+["""\
+Mixed short, long, and VMS/DOS options:
+
+-a option -a
+--bbbb=file option -bbbb
+/C option /C
+--dddd name option --dddd
+-e string option -e
+/F file option /F
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed short, long, and VMS/DOS options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --bbbb
+ <option_argument delimiter="=">
+ file
+ <description>
+ <paragraph>
+ option -bbbb
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /C
+ <description>
+ <paragraph>
+ option /C
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --dddd
+ <option_argument delimiter=" ">
+ name
+ <description>
+ <paragraph>
+ option --dddd
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -e
+ <option_argument delimiter=" ">
+ string
+ <description>
+ <paragraph>
+ option -e
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ /F
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option /F
+"""],
+["""\
+Aliased options:
+
+-a, --aaaa, /A option -a, --aaaa, /A
+-b file, --bbbb=file, /B file option -b, --bbbb, /B
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Aliased options:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <option>
+ <option_string>
+ --aaaa
+ <option>
+ <option_string>
+ /A
+ <description>
+ <paragraph>
+ option -a, --aaaa, /A
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <option>
+ <option_string>
+ --bbbb
+ <option_argument delimiter="=">
+ file
+ <option>
+ <option_string>
+ /B
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b, --bbbb, /B
+"""],
+["""\
+Multiple lines in descriptions, aligned:
+
+-a option -a, line 1
+ line 2
+-b file option -b, line 1
+ line 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Multiple lines in descriptions, aligned:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a, line 1
+ line 2
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b, line 1
+ line 2
+"""],
+["""\
+Multiple lines in descriptions, not aligned:
+
+-a option -a, line 1
+ line 2
+-b file option -b, line 1
+ line 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Multiple lines in descriptions, not aligned:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a, line 1
+ line 2
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b, line 1
+ line 2
+"""],
+["""\
+Descriptions begin on next line:
+
+-a
+ option -a, line 1
+ line 2
+-b file
+ option -b, line 1
+ line 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Descriptions begin on next line:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a, line 1
+ line 2
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b, line 1
+ line 2
+"""],
+["""\
+Multiple body elements in descriptions:
+
+-a option -a, para 1
+
+ para 2
+-b file
+ option -b, para 1
+
+ para 2
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Multiple body elements in descriptions:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -a
+ <description>
+ <paragraph>
+ option -a, para 1
+ <paragraph>
+ para 2
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -b
+ <option_argument delimiter=" ">
+ file
+ <description>
+ <paragraph>
+ option -b, para 1
+ <paragraph>
+ para 2
+"""],
+["""\
+--option
+empty item above, no blank line
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ --option
+ empty item above, no blank line
+"""],
+["""\
+An option list using equals:
+
+--long1=arg1 Description 1
+--long2=arg2 Description 2
+
+An option list using spaces:
+
+--long1 arg1 Description 1
+--long2 arg2 Description 2
+
+An option list using mixed delimiters:
+
+--long1=arg1 Description 1
+--long2 arg2 Description 2
+
+An option list using mixed delimiters in one line:
+
+--long1=arg1, --long2 arg2 Description
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ An option list using equals:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long1
+ <option_argument delimiter="=">
+ arg1
+ <description>
+ <paragraph>
+ Description 1
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long2
+ <option_argument delimiter="=">
+ arg2
+ <description>
+ <paragraph>
+ Description 2
+ <paragraph>
+ An option list using spaces:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long1
+ <option_argument delimiter=" ">
+ arg1
+ <description>
+ <paragraph>
+ Description 1
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long2
+ <option_argument delimiter=" ">
+ arg2
+ <description>
+ <paragraph>
+ Description 2
+ <paragraph>
+ An option list using mixed delimiters:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long1
+ <option_argument delimiter="=">
+ arg1
+ <description>
+ <paragraph>
+ Description 1
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long2
+ <option_argument delimiter=" ">
+ arg2
+ <description>
+ <paragraph>
+ Description 2
+ <paragraph>
+ An option list using mixed delimiters in one line:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --long1
+ <option_argument delimiter="=">
+ arg1
+ <option>
+ <option_string>
+ --long2
+ <option_argument delimiter=" ">
+ arg2
+ <description>
+ <paragraph>
+ Description
+"""],
+["""\
+Some edge cases:
+
+--option=arg arg too many arguments
+
+--option=arg,arg not supported (yet?)
+
+--option=arg=arg too many arguments
+
+--option arg arg too many arguments
+
+-a letter arg2 too many arguments
+
+/A letter arg2 too many arguments
+
+--option= argument missing
+
+--=argument option missing
+
+-- everything missing
+
+- this should be a bullet list item
+
+These next ones should be simple paragraphs:
+
+-1
+
+--option
+
+--1
+
+-1 and this one too.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Some edge cases:
+ <paragraph>
+ --option=arg arg too many arguments
+ <paragraph>
+ --option=arg,arg not supported (yet?)
+ <paragraph>
+ --option=arg=arg too many arguments
+ <paragraph>
+ --option arg arg too many arguments
+ <paragraph>
+ -a letter arg2 too many arguments
+ <paragraph>
+ /A letter arg2 too many arguments
+ <paragraph>
+ --option= argument missing
+ <paragraph>
+ --=argument option missing
+ <paragraph>
+ -- everything missing
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ this should be a bullet list item
+ <paragraph>
+ These next ones should be simple paragraphs:
+ <paragraph>
+ -1
+ <paragraph>
+ --option
+ <paragraph>
+ --1
+ <paragraph>
+ -1 and this one too.
+"""],
+["""\
+Complex optargs:
+
+--source-url=<URL> Use the supplied <URL> verbatim.
+--output-encoding=<name[:handler]>, -o<name[:handler]>
+ Specify the text encoding for output.
+-f <[path]filename> Send output to file.
+-d <src dest> Use diff from <src> to <dest>.
+--bogus=<x y z> Bogus 3D coordinates.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Complex optargs:
+ <option_list>
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --source-url
+ <option_argument delimiter="=">
+ <URL>
+ <description>
+ <paragraph>
+ Use the supplied <URL> verbatim.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --output-encoding
+ <option_argument delimiter="=">
+ <name[:handler]>
+ <option>
+ <option_string>
+ -o
+ <option_argument delimiter="">
+ <name[:handler]>
+ <description>
+ <paragraph>
+ Specify the text encoding for output.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -f
+ <option_argument delimiter=" ">
+ <[path]filename>
+ <description>
+ <paragraph>
+ Send output to file.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ -d
+ <option_argument delimiter=" ">
+ <src dest>
+ <description>
+ <paragraph>
+ Use diff from <src> to <dest>.
+ <option_list_item>
+ <option_group>
+ <option>
+ <option_string>
+ --bogus
+ <option_argument delimiter="=">
+ <x y z>
+ <description>
+ <paragraph>
+ Bogus 3D coordinates.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_outdenting.py b/test/test_parsers/test_rst/test_outdenting.py
new file mode 100755
index 000000000..1522b7f30
--- /dev/null
+++ b/test/test_parsers/test_rst/test_outdenting.py
@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['outdenting'] = [
+["""\
+Anywhere a paragraph would have an effect on the current
+indentation level, a comment or list item should also.
+
++ bullet
+
+This paragraph ends the bullet list item before a block quote.
+
+ Block quote.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anywhere a paragraph would have an effect on the current
+ indentation level, a comment or list item should also.
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ bullet
+ <paragraph>
+ This paragraph ends the bullet list item before a block quote.
+ <block_quote>
+ <paragraph>
+ Block quote.
+"""],
+["""\
++ bullet
+
+.. Comments swallow up all indented text following.
+
+ (Therefore this is not a) block quote.
+
+- bullet
+
+ If we want a block quote after this bullet list item,
+ we need to use an empty comment:
+
+..
+
+ Block quote.
+""",
+"""\
+<document source="test data">
+ <bullet_list bullet="+">
+ <list_item>
+ <paragraph>
+ bullet
+ <comment xml:space="preserve">
+ Comments swallow up all indented text following.
+ \n\
+ (Therefore this is not a) block quote.
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ bullet
+ <paragraph>
+ If we want a block quote after this bullet list item,
+ we need to use an empty comment:
+ <comment xml:space="preserve">
+ <block_quote>
+ <paragraph>
+ Block quote.
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_paragraphs.py b/test/test_parsers/test_rst/test_paragraphs.py
new file mode 100755
index 000000000..8ec8cbbc5
--- /dev/null
+++ b/test/test_parsers/test_rst/test_paragraphs.py
@@ -0,0 +1,89 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['paragraphs'] = [
+["""\
+A paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph.
+"""],
+["""\
+Paragraph 1.
+
+Paragraph 2.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph 1.
+ <paragraph>
+ Paragraph 2.
+"""],
+["""\
+Line 1.
+Line 2.
+Line 3.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Line 1.
+ Line 2.
+ Line 3.
+"""],
+["""\
+Paragraph 1, Line 1.
+Line 2.
+Line 3.
+
+Paragraph 2, Line 1.
+Line 2.
+Line 3.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph 1, Line 1.
+ Line 2.
+ Line 3.
+ <paragraph>
+ Paragraph 2, Line 1.
+ Line 2.
+ Line 3.
+"""],
+["""\
+A. Einstein was a really
+smart dude.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A. Einstein was a really
+ smart dude.
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_section_headers.py b/test/test_parsers/test_rst/test_section_headers.py
new file mode 100755
index 000000000..3c5a21170
--- /dev/null
+++ b/test/test_parsers/test_rst/test_section_headers.py
@@ -0,0 +1,897 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""Tests for states.py."""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['section_headers'] = [
+["""\
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Title
+=====
+Paragraph (no blank line).
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph (no blank line).
+"""],
+["""\
+Paragraph.
+
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Test unexpected section titles.
+
+ Title
+ =====
+ Paragraph.
+
+ -----
+ Title
+ -----
+ Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test unexpected section titles.
+ <block_quote>
+ <system_message level="4" line="4" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title.
+ <literal_block xml:space="preserve">
+ Title
+ =====
+ <paragraph>
+ Paragraph.
+ <system_message level="4" line="7" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title or transition.
+ <literal_block xml:space="preserve">
+ -----
+ <system_message level="4" line="9" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title.
+ <literal_block xml:space="preserve">
+ Title
+ -----
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Title
+====
+
+Test short underline.
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Title underline too short.
+ <literal_block xml:space="preserve">
+ Title
+ ====
+ <paragraph>
+ Test short underline.
+"""],
+["""\
+=====
+Title
+=====
+
+Test overline title.
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Test overline title.
+"""],
+["""\
+=======
+ Title
+=======
+
+Test overline title with inset.
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Test overline title with inset.
+"""],
+["""\
+========================
+ Test Missing Underline
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Incomplete section title.
+ <literal_block xml:space="preserve">
+ ========================
+ Test Missing Underline
+"""],
+["""\
+========================
+ Test Missing Underline
+
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Missing matching underline for section title overline.
+ <literal_block xml:space="preserve">
+ ========================
+ Test Missing Underline
+"""],
+["""\
+=======
+ Title
+
+Test missing underline, with paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Missing matching underline for section title overline.
+ <literal_block xml:space="preserve">
+ =======
+ Title
+ <paragraph>
+ Test missing underline, with paragraph.
+"""],
+["""\
+=======
+ Long Title
+=======
+
+Test long title and space normalization.
+""",
+"""\
+<document source="test data">
+ <section ids="long-title" names="long\ title">
+ <title>
+ Long Title
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Title overline too short.
+ <literal_block xml:space="preserve">
+ =======
+ Long Title
+ =======
+ <paragraph>
+ Test long title and space normalization.
+"""],
+["""\
+=======
+ Title
+-------
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <system_message level="4" line="1" source="test data" type="SEVERE">
+ <paragraph>
+ Title overline & underline mismatch.
+ <literal_block xml:space="preserve">
+ =======
+ Title
+ -------
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+========================
+
+========================
+
+Test missing titles; blank line in-between.
+
+========================
+
+========================
+""",
+"""\
+<document source="test data">
+ <transition>
+ <transition>
+ <paragraph>
+ Test missing titles; blank line in-between.
+ <transition>
+ <transition>
+"""],
+["""\
+========================
+========================
+
+Test missing titles; nothing in-between.
+
+========================
+========================
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Invalid section title or transition marker.
+ <literal_block xml:space="preserve">
+ ========================
+ ========================
+ <paragraph>
+ Test missing titles; nothing in-between.
+ <system_message level="3" line="6" source="test data" type="ERROR">
+ <paragraph>
+ Invalid section title or transition marker.
+ <literal_block xml:space="preserve">
+ ========================
+ ========================
+"""],
+["""\
+.. Test return to existing, highest-level section (Title 3).
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+=======
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ Test return to existing, highest-level section (Title 3).
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title>
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Test return to existing, highest-level section (Title 3, with overlines).
+
+=======
+Title 1
+=======
+Paragraph 1.
+
+-------
+Title 2
+-------
+Paragraph 2.
+
+=======
+Title 3
+=======
+Paragraph 3.
+
+-------
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test return to existing, highest-level section (Title 3, with overlines).
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title>
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Test return to existing, higher-level section (Title 4).
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test return to existing, higher-level section (Title 4).
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title>
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Test bad subsection order (Title 4).
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+=======
+Paragraph 3.
+
+Title 4
+```````
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test bad subsection order (Title 4).
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <system_message level="4" line="15" source="test data" type="SEVERE">
+ <paragraph>
+ Title level inconsistent:
+ <literal_block xml:space="preserve">
+ Title 4
+ ```````
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Test bad subsection order (Title 4, with overlines).
+
+=======
+Title 1
+=======
+Paragraph 1.
+
+-------
+Title 2
+-------
+Paragraph 2.
+
+=======
+Title 3
+=======
+Paragraph 3.
+
+```````
+Title 4
+```````
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test bad subsection order (Title 4, with overlines).
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <system_message level="4" line="19" source="test data" type="SEVERE">
+ <paragraph>
+ Title level inconsistent:
+ <literal_block xml:space="preserve">
+ ```````
+ Title 4
+ ```````
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Title containing *inline* ``markup``
+====================================
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <section ids="title-containing-inline-markup" names="title\ containing\ inline\ markup">
+ <title>
+ Title containing \n\
+ <emphasis>
+ inline
+ \n\
+ <literal>
+ markup
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+1. Numbered Title
+=================
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <section ids="numbered-title" names="1.\ numbered\ title">
+ <title>
+ 1. Numbered Title
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+1. Item 1.
+2. Item 2.
+3. Numbered Title
+=================
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ Item 1.
+ <list_item>
+ <paragraph>
+ Item 2.
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Enumerated list ends without a blank line; unexpected unindent.
+ <section ids="numbered-title" names="3.\ numbered\ title">
+ <title>
+ 3. Numbered Title
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+ABC
+===
+
+Short title.
+""",
+"""\
+<document source="test data">
+ <section ids="abc" names="abc">
+ <title>
+ ABC
+ <paragraph>
+ Short title.
+"""],
+["""\
+ABC
+==
+
+Underline too short.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Possible title underline, too short for the title.
+ Treating it as ordinary text because it's so short.
+ <paragraph>
+ ABC
+ ==
+ <paragraph>
+ Underline too short.
+"""],
+["""\
+==
+ABC
+==
+
+Over & underline too short.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <paragraph>
+ ==
+ ABC
+ ==
+ <paragraph>
+ Over & underline too short.
+"""],
+["""\
+==
+ABC
+
+Overline too short, no underline.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <paragraph>
+ ==
+ ABC
+ <paragraph>
+ Overline too short, no underline.
+"""],
+["""\
+==
+ABC
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <paragraph>
+ ==
+ ABC
+"""],
+["""\
+==
+ Not a title: a definition list item.
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <definition_list>
+ <definition_list_item>
+ <term>
+ ==
+ <definition>
+ <paragraph>
+ Not a title: a definition list item.
+"""],
+["""\
+==
+ Not a title: a definition list item.
+--
+ Another definition list item. It's in a different list,
+ but that's an acceptable limitation given that this will
+ probably never happen in real life.
+
+ The next line will trigger a warning:
+==
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <definition_list>
+ <definition_list_item>
+ <term>
+ ==
+ <definition>
+ <paragraph>
+ Not a title: a definition list item.
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Definition list ends without a blank line; unexpected unindent.
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <definition_list>
+ <definition_list_item>
+ <term>
+ --
+ <definition>
+ <paragraph>
+ Another definition list item. It's in a different list,
+ but that's an acceptable limitation given that this will
+ probably never happen in real life.
+ <paragraph>
+ The next line will trigger a warning:
+ <system_message level="2" line="9" source="test data" type="WARNING">
+ <paragraph>
+ Definition list ends without a blank line; unexpected unindent.
+ <paragraph>
+ ==
+"""],
+["""\
+Paragraph
+
+ ==
+ ABC
+ ==
+
+ Over & underline too short.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph
+ <block_quote>
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ Unexpected possible title overline or transition.
+ Treating it as ordinary text because it's so short.
+ <paragraph>
+ ==
+ ABC
+ ==
+ <paragraph>
+ Over & underline too short.
+"""],
+["""\
+Paragraph
+
+ ABC
+ ==
+
+ Underline too short.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph
+ <block_quote>
+ <paragraph>
+ ABC
+ ==
+ <paragraph>
+ Underline too short.
+"""],
+["""\
+...
+...
+
+...
+---
+
+...
+...
+...
+""",
+"""\
+<document source="test data">
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <section dupnames="..." ids="id1">
+ <title>
+ ...
+ <system_message level="1" line="4" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <section dupnames="..." ids="id2">
+ <title>
+ ...
+ <system_message backrefs="id2" level="1" line="5" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "...".
+ <system_message level="1" line="7" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <system_message level="1" line="7" source="test data" type="INFO">
+ <paragraph>
+ Possible incomplete section title.
+ Treating the overline as ordinary text because it's so short.
+ <section dupnames="..." ids="id3">
+ <title>
+ ...
+ <system_message backrefs="id3" level="1" line="8" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "...".
+ <paragraph>
+ ...
+"""],
+["""\
+..
+Hi
+..
+
+...
+Yo
+...
+
+Ho
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <section ids="hi" names="hi">
+ <title>
+ Hi
+ <section ids="yo" names="yo">
+ <title>
+ Yo
+ <paragraph>
+ Ho
+"""],
+["""\
+Empty Section
+=============
+""",
+"""\
+<document source="test data">
+ <section ids="empty-section" names="empty\ section">
+ <title>
+ Empty Section
+"""],
+["""\
+===
+One
+===
+
+The bubble-up parser strategy conflicts with short titles
+(<= 3 char-long over- & underlines).
+
+===
+Two
+===
+
+The parser currently contains a work-around kludge.
+Without it, the parser ends up in an infinite loop.
+""",
+"""\
+<document source="test data">
+ <section ids="one" names="one">
+ <title>
+ One
+ <paragraph>
+ The bubble-up parser strategy conflicts with short titles
+ (<= 3 char-long over- & underlines).
+ <section ids="two" names="two">
+ <title>
+ Two
+ <paragraph>
+ The parser currently contains a work-around kludge.
+ Without it, the parser ends up in an infinite loop.
+"""],
+["""\
+""",
+"""\
+<document source="test data">
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_substitutions.py b/test/test_parsers/test_rst/test_substitutions.py
new file mode 100755
index 000000000..fb8af4c2d
--- /dev/null
+++ b/test/test_parsers/test_rst/test_substitutions.py
@@ -0,0 +1,298 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['substitution_definitions'] = [
+["""\
+Here's an image substitution definition:
+
+.. |symbol| image:: symbol.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here's an image substitution definition:
+ <substitution_definition names="symbol">
+ <image alt="symbol" uri="symbol.png">
+"""],
+["""\
+Embedded directive starts on the next line:
+
+.. |symbol|
+ image:: symbol.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Embedded directive starts on the next line:
+ <substitution_definition names="symbol">
+ <image alt="symbol" uri="symbol.png">
+"""],
+["""\
+Trailing spaces should not be significant:
+
+.. |symbol| image:: \n\
+ symbol.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Trailing spaces should not be significant:
+ <substitution_definition names="symbol">
+ <image alt="symbol" uri="symbol.png">
+"""],
+["""\
+Here's a series of substitution definitions:
+
+.. |symbol 1| image:: symbol1.png
+.. |SYMBOL 2| image:: symbol2.png
+ :height: 50
+ :width: 100
+.. |symbol 3| image:: symbol3.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here's a series of substitution definitions:
+ <substitution_definition names="symbol\ 1">
+ <image alt="symbol 1" uri="symbol1.png">
+ <substitution_definition names="SYMBOL\ 2">
+ <image alt="SYMBOL 2" height="50" uri="symbol2.png" width="100">
+ <substitution_definition names="symbol\ 3">
+ <image alt="symbol 3" uri="symbol3.png">
+"""],
+["""\
+.. |very long substitution text,
+ split across lines| image:: symbol.png
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="very\ long\ substitution\ text,\ split\ across\ lines">
+ <image alt="very long substitution text, split across lines" uri="symbol.png">
+"""],
+["""\
+.. |symbol 1| image:: symbol.png
+
+ Followed by a block quote.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "image" directive:
+ no content permitted.
+ <literal_block xml:space="preserve">
+ image:: symbol.png
+ \n\
+ Followed by a block quote.
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "symbol 1" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |symbol 1| image:: symbol.png
+ \n\
+ Followed by a block quote.
+"""],
+["""\
+.. |symbol 1| image:: symbol.png
+
+Followed by a paragraph.
+
+.. |symbol 2| image:: symbol.png
+
+..
+
+ Followed by a block quote.
+""",
+"""\
+<document source="test data">
+ <substitution_definition names="symbol\ 1">
+ <image alt="symbol 1" uri="symbol.png">
+ <paragraph>
+ Followed by a paragraph.
+ <substitution_definition names="symbol\ 2">
+ <image alt="symbol 2" uri="symbol.png">
+ <comment xml:space="preserve">
+ <block_quote>
+ <paragraph>
+ Followed by a block quote.
+"""],
+[u"""\
+Substitutions support case differences:
+
+.. |eacute| replace:: \u00E9
+.. |Eacute| replace:: \u00C9
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Substitutions support case differences:
+ <substitution_definition names="eacute">
+ \u00E9
+ <substitution_definition names="Eacute">
+ \u00C9
+"""],
+["""\
+Raw substitution, backslashes should be preserved:
+
+.. |alpha| raw:: latex
+
+ $\\\\alpha$
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Raw substitution, backslashes should be preserved:
+ <substitution_definition names="alpha">
+ <raw format="latex" xml:space="preserve">
+ $\\\\alpha$
+"""],
+["""\
+Here are some duplicate substitution definitions:
+
+.. |symbol| image:: symbol.png
+.. |symbol| image:: symbol.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here are some duplicate substitution definitions:
+ <substitution_definition dupnames="symbol">
+ <image alt="symbol" uri="symbol.png">
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Duplicate substitution definition name: "symbol".
+ <substitution_definition names="symbol">
+ <image alt="symbol" uri="symbol.png">
+"""],
+["""\
+Here are some bad cases:
+
+.. |symbol| image:: symbol.png
+No blank line after.
+
+.. |empty|
+
+.. |unknown| directive:: symbol.png
+
+.. |invalid 1| there's no directive here
+.. |invalid 2| there's no directive here
+ With some block quote text, line 1.
+ And some more, line 2.
+
+.. |invalid 3| there's no directive here
+
+.. | bad name | bad data
+
+.. |
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here are some bad cases:
+ <substitution_definition names="symbol">
+ <image alt="symbol" uri="symbol.png">
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ No blank line after.
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "empty" missing contents.
+ <literal_block xml:space="preserve">
+ .. |empty|
+ <system_message level="1" line="8" source="test data" type="INFO">
+ <paragraph>
+ No directive entry for "directive" in module "docutils.parsers.rst.languages.en".
+ Trying "directive" as canonical directive name.
+ <system_message level="3" line="8" source="test data" type="ERROR">
+ <paragraph>
+ Unknown directive type "directive".
+ <literal_block xml:space="preserve">
+ directive:: symbol.png
+ <system_message level="2" line="8" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "unknown" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |unknown| directive:: symbol.png
+ <system_message level="2" line="10" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "invalid 1" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |invalid 1| there's no directive here
+ <system_message level="2" line="11" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "invalid 2" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |invalid 2| there's no directive here
+ With some block quote text, line 1.
+ And some more, line 2.
+ <system_message level="2" line="15" source="test data" type="WARNING">
+ <paragraph>
+ Substitution definition "invalid 3" empty or invalid.
+ <literal_block xml:space="preserve">
+ .. |invalid 3| there's no directive here
+ <comment xml:space="preserve">
+ | bad name | bad data
+ <comment xml:space="preserve">
+ |
+"""],
+["""\
+Elements that are prohibited inside of substitution definitions:
+
+.. |target| replace:: _`target`
+.. |reference| replace:: anonymous__
+.. |auto-numbered footnote| replace:: [#]_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Elements that are prohibited inside of substitution definitions:
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Substitution definition contains illegal element:
+ <literal_block xml:space="preserve">
+ <target ids="target" names="target">
+ target
+ <literal_block xml:space="preserve">
+ .. |target| replace:: _`target`
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Substitution definition contains illegal element:
+ <literal_block xml:space="preserve">
+ <reference anonymous="1" name="anonymous">
+ anonymous
+ <literal_block xml:space="preserve">
+ .. |reference| replace:: anonymous__
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Substitution definition contains illegal element:
+ <literal_block xml:space="preserve">
+ <footnote_reference auto="1" ids="id1">
+ <literal_block xml:space="preserve">
+ .. |auto-numbered footnote| replace:: [#]_
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_tables.py b/test/test_parsers/test_rst/test_tables.py
new file mode 100755
index 000000000..81c423bc4
--- /dev/null
+++ b/test/test_parsers/test_rst/test_tables.py
@@ -0,0 +1,1261 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+import os
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+mydir = 'test_parsers/test_rst/'
+include2 = os.path.join(mydir, 'test_directives/include2.txt')
+
+totest = {}
+
+totest['grid_tables'] = [
+["""\
++-------------------------------------+
+| A table with one cell and one line. |
++-------------------------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="37">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with one cell and one line.
+"""],
+["""\
++-----------------------+
+| A table with one cell |
+| and two lines. |
++-----------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="23">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with one cell
+ and two lines.
+"""],
+["""\
++-----------------------+
+| A malformed table. |
++-----------------------+
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ <literal_block xml:space="preserve">
+ +-----------------------+
+ | A malformed table. |
+ +-----------------------+
+"""],
+["""\
++------------------------+
+| A well-formed | table. |
++------------------------+
+
++------------------------+
+| This +----------+ too! |
++------------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="24">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A well-formed | table.
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="24">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ This +----------+ too!
+"""],
+["""\
++--------------+--------------+
+| A table with | two columns. |
++--------------+--------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="14">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns.
+"""],
+["""\
++--------------+
+| A table with |
++--------------+
+| two rows. |
++--------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="14">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <row>
+ <entry>
+ <paragraph>
+ two rows.
+"""],
+["""\
++--------------+-------------+
+| A table with | two columns |
++--------------+-------------+
+| and | two rows. |
++--------------+-------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="13">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns
+ <row>
+ <entry>
+ <paragraph>
+ and
+ <entry>
+ <paragraph>
+ two rows.
+"""],
+["""\
++--------------+---------------+
+| A table with | two columns, |
++--------------+---------------+
+| two rows, and a column span. |
++------------------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="15">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns,
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ two rows, and a column span.
+"""],
+["""\
++--------------------------+
+| A table with three rows, |
++------------+-------------+
+| and two | columns. |
++------------+-------------+
+| First and last rows |
+| contains column spans. |
++--------------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="13">
+ <tbody>
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ A table with three rows,
+ <row>
+ <entry>
+ <paragraph>
+ and two
+ <entry>
+ <paragraph>
+ columns.
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ First and last rows
+ contains column spans.
+"""],
+["""\
++--------------+--------------+
+| A table with | two columns, |
++--------------+ and a row |
+| two rows, | span. |
++--------------+--------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="14">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry morerows="1">
+ <paragraph>
+ two columns,
+ and a row
+ span.
+ <row>
+ <entry>
+ <paragraph>
+ two rows,
+"""],
+["""\
++------------+-------------+---------------+
+| A table | two rows in | and row spans |
+| with three +-------------+ to left and |
+| columns, | the middle, | right. |
++------------+-------------+---------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="12">
+ <colspec colwidth="13">
+ <colspec colwidth="15">
+ <tbody>
+ <row>
+ <entry morerows="1">
+ <paragraph>
+ A table
+ with three
+ columns,
+ <entry>
+ <paragraph>
+ two rows in
+ <entry morerows="1">
+ <paragraph>
+ and row spans
+ to left and
+ right.
+ <row>
+ <entry>
+ <paragraph>
+ the middle,
+"""],
+["""\
+Complex spanning pattern (no edge knows all rows/cols):
+
++-----------+-------------------------+
+| W/NW cell | N/NE cell |
+| +-------------+-----------+
+| | Middle cell | E/SE cell |
++-----------+-------------+ |
+| S/SE cell | |
++-------------------------+-----------+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Complex spanning pattern (no edge knows all rows/cols):
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="11">
+ <colspec colwidth="13">
+ <colspec colwidth="11">
+ <tbody>
+ <row>
+ <entry morerows="1">
+ <paragraph>
+ W/NW cell
+ <entry morecols="1">
+ <paragraph>
+ N/NE cell
+ <row>
+ <entry>
+ <paragraph>
+ Middle cell
+ <entry morerows="1">
+ <paragraph>
+ E/SE cell
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ S/SE cell
+"""],
+["""\
++------------------------+------------+----------+----------+
+| Header row, column 1 | Header 2 | Header 3 | Header 4 |
++========================+============+==========+==========+
+| body row 1, column 1 | column 2 | column 3 | column 4 |
++------------------------+------------+----------+----------+
+| body row 2 | Cells may span columns. |
++------------------------+------------+---------------------+
+| body row 3 | Cells may | - Table cells |
++------------------------+ span rows. | - contain |
+| body row 4 | | - body elements. |
++------------------------+------------+---------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="4">
+ <colspec colwidth="24">
+ <colspec colwidth="12">
+ <colspec colwidth="10">
+ <colspec colwidth="10">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ Header row, column 1
+ <entry>
+ <paragraph>
+ Header 2
+ <entry>
+ <paragraph>
+ Header 3
+ <entry>
+ <paragraph>
+ Header 4
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ body row 1, column 1
+ <entry>
+ <paragraph>
+ column 2
+ <entry>
+ <paragraph>
+ column 3
+ <entry>
+ <paragraph>
+ column 4
+ <row>
+ <entry>
+ <paragraph>
+ body row 2
+ <entry morecols="2">
+ <paragraph>
+ Cells may span columns.
+ <row>
+ <entry>
+ <paragraph>
+ body row 3
+ <entry morerows="1">
+ <paragraph>
+ Cells may
+ span rows.
+ <entry morecols="1" morerows="1">
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Table cells
+ <list_item>
+ <paragraph>
+ contain
+ <list_item>
+ <paragraph>
+ body elements.
+ <row>
+ <entry>
+ <paragraph>
+ body row 4
+"""],
+["""\
++-----------------+--------+
+| A simple table | cell 2 |
++-----------------+--------+
+| cell 3 | cell 4 |
++-----------------+--------+
+No blank line after table.
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="17">
+ <colspec colwidth="8">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A simple table
+ <entry>
+ <paragraph>
+ cell 2
+ <row>
+ <entry>
+ <paragraph>
+ cell 3
+ <entry>
+ <paragraph>
+ cell 4
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Blank line required after table.
+ <paragraph>
+ No blank line after table.
+"""],
+["""\
++-----------------+--------+
+| A simple table | cell 2 |
++-----------------+--------+
+| cell 3 | cell 4 |
++-----------------+--------+
+ Unexpected indent and no blank line after table.
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="17">
+ <colspec colwidth="8">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A simple table
+ <entry>
+ <paragraph>
+ cell 2
+ <row>
+ <entry>
+ <paragraph>
+ cell 3
+ <entry>
+ <paragraph>
+ cell 4
+ <system_message level="3" line="6" source="test data" type="ERROR">
+ <paragraph>
+ Unexpected indentation.
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Blank line required after table.
+ <block_quote>
+ <paragraph>
+ Unexpected indent and no blank line after table.
+"""],
+["""\
++--------------+-------------+
+| A bad table. | |
++--------------+ |
+| Cells must be rectangles. |
++----------------------------+
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Malformed table; parse incomplete.
+ <literal_block xml:space="preserve">
+ +--------------+-------------+
+ | A bad table. | |
+ +--------------+ |
+ | Cells must be rectangles. |
+ +----------------------------+
+"""],
+["""\
++------------------------------+
+| This table contains another. |
+| |
+| +-------------------------+ |
+| | A table within a table. | |
+| +-------------------------+ |
++------------------------------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="30">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ This table contains another.
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="25">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table within a table.
+"""],
+["""\
++------------------+--------+
+| A simple table | |
++------------------+--------+
+| with empty cells | |
++------------------+--------+
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="18">
+ <colspec colwidth="8">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A simple table
+ <entry>
+ <row>
+ <entry>
+ <paragraph>
+ with empty cells
+ <entry>
+"""],
+[("""\
++------------------------------------------------------------------------------+
+| .. include:: |
+%s
++------------------------------------------------------------------------------+
+| (The first cell of this table may expand |
+| to accommodate long filesystem paths.) |
++------------------------------------------------------------------------------+
+""") % ('\n'.join(['| %-70s |' % include2[part * 70 : (part + 1) * 70]
+ for part in range(len(include2) / 70 + 1)])),
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="78">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Here are some paragraphs
+ that can appear at any level.
+ <paragraph>
+ This file (include2.txt) is used by
+ <literal>
+ test_include.py
+ .
+ <row>
+ <entry>
+ <paragraph>
+ (The first cell of this table may expand
+ to accommodate long filesystem paths.)
+"""],
+[("""\
+Something before.
+
++------------------------------------------------------------------------------+
+| .. include:: |
+%s
++------------------------------------------------------------------------------+
+
+Something afterwards.
+
+And more.
+""") % ('\n'.join(['| %-70s |' % include2[part * 70 : (part + 1) * 70]
+ for part in range(len(include2) / 70 + 1)])),
+"""\
+<document source="test data">
+ <paragraph>
+ Something before.
+ <table>
+ <tgroup cols="1">
+ <colspec colwidth="78">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Here are some paragraphs
+ that can appear at any level.
+ <paragraph>
+ This file (include2.txt) is used by
+ <literal>
+ test_include.py
+ .
+ <paragraph>
+ Something afterwards.
+ <paragraph>
+ And more.
+"""],
+]
+
+totest['simple_tables'] = [
+["""\
+============ ============
+A table with two columns.
+============ ============
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="12">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns.
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+============ ============
+A table with two columns
+and two rows.
+============ ============
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="12">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns
+ <row>
+ <entry>
+ <paragraph>
+ and
+ <entry>
+ <paragraph>
+ two rows.
+"""],
+["""\
+============ ==============
+A table with two columns,
+two rows, and a column span.
+============================
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="14">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ two columns,
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ two rows, and a column span.
+"""],
+["""\
+== =========== ===========
+1 A table with three rows,
+-- ------------------------
+2 and three columns.
+3 First and third rows
+ contain column spans.
+
+ This row is a multi-line row, and overflows to the right.
+-- ------------------------
+4 One last row.
+== =========== ===========
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="2">
+ <colspec colwidth="11">
+ <colspec colwidth="44">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ 1
+ <entry morecols="1">
+ <paragraph>
+ A table with three rows,
+ <row>
+ <entry>
+ <paragraph>
+ 2
+ <entry>
+ <paragraph>
+ and three
+ <entry>
+ <paragraph>
+ columns.
+ <row>
+ <entry>
+ <paragraph>
+ 3
+ <entry morecols="1">
+ <paragraph>
+ First and third rows
+ contain column spans.
+ <paragraph>
+ This row is a multi-line row, and overflows to the right.
+ <row>
+ <entry>
+ <paragraph>
+ 4
+ <entry>
+ <paragraph>
+ One last
+ <entry>
+ <paragraph>
+ row.
+"""],
+["""\
+======= ========= ========
+A table with three columns.
+================== ========
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="7">
+ <colspec colwidth="9">
+ <colspec colwidth="8">
+ <tbody>
+ <row>
+ <entry morecols="1">
+ <paragraph>
+ A table with three
+ <entry>
+ <paragraph>
+ columns.
+"""],
+["""\
+============== ======
+A simple table with
+no bottom border
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ No bottom table border found.
+ <literal_block xml:space="preserve">
+ ============== ======
+ A simple table with
+ no bottom border
+"""],
+["""\
+============== ======
+A simple table cell 2
+cell 3 cell 4
+============== ======
+No blank line after table.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ No bottom table border found or no blank line after table bottom.
+ <literal_block xml:space="preserve">
+ ============== ======
+ A simple table cell 2
+ cell 3 cell 4
+ ============== ======
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Blank line required after table.
+ <paragraph>
+ No blank line after table.
+"""],
+["""\
+============== ======
+A simple table cell 2
+============== ======
+cell 3 cell 4
+============== ======
+No blank line after table.
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="6">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ A simple table
+ <entry>
+ <paragraph>
+ cell 2
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ cell 3
+ <entry>
+ <paragraph>
+ cell 4
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Blank line required after table.
+ <paragraph>
+ No blank line after table.
+"""],
+["""\
+============== ======
+A simple table cell 2
+cell 3 cell 4
+============== ======
+ Unexpected indent and no blank line after table.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ No bottom table border found or no blank line after table bottom.
+ <literal_block xml:space="preserve">
+ ============== ======
+ A simple table cell 2
+ cell 3 cell 4
+ ============== ======
+ <system_message level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Blank line required after table.
+ <block_quote>
+ <paragraph>
+ Unexpected indent and no blank line after table.
+"""],
+["""\
+============== ======
+A bad table cell 2
+cell 3 cell 4
+============ ========
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Column span alignment problem at line offset 3.
+ <literal_block xml:space="preserve">
+ ============== ======
+ A bad table cell 2
+ cell 3 cell 4
+ ============ ========
+"""],
+["""\
+======== =========
+A bad table cell 2
+cell 3 cell 4
+======== =========
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Text in column margin at line offset 1.
+ <literal_block xml:space="preserve">
+ ======== =========
+ A bad table cell 2
+ cell 3 cell 4
+ ======== =========
+"""],
+["""\
+== ============================
+1 This table contains another.
+2 ======= ====== ========
+ A table within a table.
+ ======= ====== ========
+
+ The outer table does have to
+ have at least two columns
+ though.
+== ============================
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="2">
+ <colspec colwidth="28">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ 1
+ <entry>
+ <paragraph>
+ This table contains another.
+ <row>
+ <entry>
+ <paragraph>
+ 2
+ <entry>
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="7">
+ <colspec colwidth="6">
+ <colspec colwidth="8">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table
+ <entry>
+ <paragraph>
+ within
+ <entry>
+ <paragraph>
+ a table.
+ <paragraph>
+ The outer table does have to
+ have at least two columns
+ though.
+"""],
+["""\
+================ ======
+A simple table
+with empty cells
+================ ======
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="16">
+ <colspec colwidth="6">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A simple table
+ <entry>
+ <row>
+ <entry>
+ <paragraph>
+ with empty cells
+ <entry>
+"""],
+["""\
+============== ========
+ A table with
+============== ========
+ centered cells.
+
+============== ========
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="14">
+ <colspec colwidth="8">
+ <thead>
+ <row>
+ <entry>
+ <paragraph>
+ A table
+ <entry>
+ <paragraph>
+ with
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ centered
+ <entry>
+ <paragraph>
+ cells.
+"""],
+["""\
+============== ======
+A simple table this text extends to the right
+cell 3 the bottom border below is too long
+============== ========
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Bottom/header table border does not match top border.
+ <literal_block xml:space="preserve">
+ ============== ======
+ A simple table this text extends to the right
+ cell 3 the bottom border below is too long
+ ============== ========
+"""],
+["""\
+============ =================
+A table with row separators.
+------------ -----------------
+
+Blank line before.
+------------ -----------------
+
+Blank lines before and after.
+
+------------ -----------------
+Blank line after.
+
+============ =================
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="17">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ row separators.
+ <row>
+ <entry>
+ <paragraph>
+ Blank line
+ <entry>
+ <paragraph>
+ before.
+ <row>
+ <entry>
+ <paragraph>
+ Blank lines
+ <entry>
+ <paragraph>
+ before and after.
+ <row>
+ <entry>
+ <paragraph>
+ Blank line
+ <entry>
+ <paragraph>
+ after.
+"""],
+["""\
+============ ====================
+A table with many row separators.
+------------ --------------------
+------------ --------------------
+
+------------ --------------------
+============ ====================
+""",
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="12">
+ <colspec colwidth="20">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ A table with
+ <entry>
+ <paragraph>
+ many row separators.
+ <row>
+ <entry>
+ <entry>
+ <row>
+ <entry>
+ <entry>
+ <row>
+ <entry>
+ <entry>
+"""],
+["""\
+== =========== ===========
+1 Span columns 2 & 3
+-- ------------------------
+2 Span columns 2 & 3
+ ------------------------
+3
+== =========== ===========
+
+== =========== ===========
+1 Span cols 1&2 but not 3
+--------------- -----------
+2 Span cols 1&2 but not 3
+---------------
+3 no spans here
+== =========== ===========
+
+== =========== ===========
+1 Not a span Not a span
+ ----------- -----------
+2
+== =========== ===========
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Text in column margin at line offset 3.
+ <literal_block xml:space="preserve">
+ == =========== ===========
+ 1 Span columns 2 & 3
+ -- ------------------------
+ 2 Span columns 2 & 3
+ ------------------------
+ 3
+ == =========== ===========
+ <system_message level="3" line="9" source="test data" type="ERROR">
+ <paragraph>
+ Malformed table.
+ Column span incomplete at line offset 4.
+ <literal_block xml:space="preserve">
+ == =========== ===========
+ 1 Span cols 1&2 but not 3
+ --------------- -----------
+ 2 Span cols 1&2 but not 3
+ ---------------
+ 3 no spans here
+ == =========== ===========
+ <table>
+ <tgroup cols="3">
+ <colspec colwidth="2">
+ <colspec colwidth="11">
+ <colspec colwidth="11">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ 1
+ <entry>
+ <system_message level="4" line="20" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title.
+ <literal_block xml:space="preserve">
+ Not a span
+ -----------
+ <entry>
+ <system_message level="4" line="20" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title.
+ <literal_block xml:space="preserve">
+ Not a span
+ -----------
+ <row>
+ <entry>
+ <paragraph>
+ 2
+ <entry>
+ <entry>
+"""],
+["""\
+========= =====================================================================
+Inclusion .. include::
+%s
+Note The first row of this table may expand
+ to accommodate long filesystem paths.
+========= =====================================================================
+""" % ('\n'.join([' %-65s' % include2[part * 65 : (part + 1) * 65]
+ for part in range(len(include2) / 65 + 1)])),
+"""\
+<document source="test data">
+ <table>
+ <tgroup cols="2">
+ <colspec colwidth="9">
+ <colspec colwidth="69">
+ <tbody>
+ <row>
+ <entry>
+ <paragraph>
+ Inclusion
+ <entry>
+ <paragraph>
+ Here are some paragraphs
+ that can appear at any level.
+ <paragraph>
+ This file (include2.txt) is used by
+ <literal>
+ test_include.py
+ .
+ <row>
+ <entry>
+ <paragraph>
+ Note
+ <entry>
+ <paragraph>
+ The first row of this table may expand
+ to accommodate long filesystem paths.
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_targets.py b/test/test_parsers/test_rst/test_targets.py
new file mode 100755
index 000000000..362bf2cca
--- /dev/null
+++ b/test/test_parsers/test_rst/test_targets.py
@@ -0,0 +1,440 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for states.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['targets'] = [
+["""\
+.. _target:
+
+(Internal hyperlink target.)
+""",
+"""\
+<document source="test data">
+ <target ids="target" names="target">
+ <paragraph>
+ (Internal hyperlink target.)
+"""],
+["""\
+.. _optional space before colon :
+""",
+"""\
+<document source="test data">
+ <target ids="optional-space-before-colon" names="optional\ space\ before\ colon">
+"""],
+["""\
+External hyperlink targets:
+
+.. _one-liner: http://structuredtext.sourceforge.net
+
+.. _starts-on-this-line: http://
+ structuredtext.
+ sourceforge.net
+
+.. _entirely-below:
+ http://structuredtext.
+ sourceforge.net
+
+.. _not-indirect: uri\\_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ External hyperlink targets:
+ <target ids="one-liner" names="one-liner" refuri="http://structuredtext.sourceforge.net">
+ <target ids="starts-on-this-line" names="starts-on-this-line" refuri="http://structuredtext.sourceforge.net">
+ <target ids="entirely-below" names="entirely-below" refuri="http://structuredtext.sourceforge.net">
+ <target ids="not-indirect" names="not-indirect" refuri="uri_">
+"""],
+["""\
+Indirect hyperlink targets:
+
+.. _target1: reference_
+
+.. _target2: `phrase-link reference`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Indirect hyperlink targets:
+ <target ids="target1" names="target1" refname="reference">
+ <target ids="target2" names="target2" refname="phrase-link reference">
+"""],
+["""\
+.. _a long target name:
+
+.. _`a target name: including a colon (quoted)`:
+
+.. _a target name\: including a colon (escaped):
+""",
+"""\
+<document source="test data">
+ <target ids="a-long-target-name" names="a\ long\ target\ name">
+ <target ids="a-target-name-including-a-colon-quoted" names="a\ target\ name:\ including\ a\ colon\ (quoted)">
+ <target ids="a-target-name-including-a-colon-escaped" names="a\ target\ name:\ including\ a\ colon\ (escaped)">
+"""],
+["""\
+.. _a very long target name,
+ split across lines:
+.. _`and another,
+ with backquotes`:
+""",
+"""\
+<document source="test data">
+ <target ids="a-very-long-target-name-split-across-lines" names="a\ very\ long\ target\ name,\ split\ across\ lines">
+ <target ids="and-another-with-backquotes" names="and\ another,\ with\ backquotes">
+"""],
+["""\
+External hyperlink:
+
+.. _target: http://www.python.org/
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ External hyperlink:
+ <target ids="target" names="target" refuri="http://www.python.org/">
+"""],
+["""\
+.. _email: jdoe@example.com
+
+.. _multi-line email: jdoe
+ @example.com
+""",
+"""\
+<document source="test data">
+ <target ids="email" names="email" refuri="mailto:jdoe@example.com">
+ <target ids="multi-line-email" names="multi-line\ email" refuri="mailto:jdoe@example.com">
+"""],
+["""\
+Duplicate external targets (different URIs):
+
+.. _target: first
+
+.. _target: second
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate external targets (different URIs):
+ <target dupnames="target" ids="target" refuri="first">
+ <system_message backrefs="id1" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id1" refuri="second">
+"""],
+["""\
+Duplicate external targets (same URIs):
+
+.. _target: first
+
+.. _target: first
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate external targets (same URIs):
+ <target ids="target" names="target" refuri="first">
+ <system_message backrefs="id1" level="1" line="5" source="test data" type="INFO">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id1" refuri="first">
+"""],
+["""\
+Duplicate implicit targets.
+
+Title
+=====
+
+Paragraph.
+
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate implicit targets.
+ <section dupnames="title" ids="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph.
+ <section dupnames="title" ids="id1">
+ <title>
+ Title
+ <system_message backrefs="id1" level="1" line="9" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "title".
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Duplicate implicit/explicit targets.
+
+Title
+=====
+
+.. _title:
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate implicit/explicit targets.
+ <section dupnames="title" ids="title">
+ <title>
+ Title
+ <system_message backrefs="id1" level="1" line="6" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "title".
+ <target ids="id1" names="title">
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Duplicate explicit targets.
+
+.. _title:
+
+First.
+
+.. _title:
+
+Second.
+
+.. _title:
+
+Third.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate explicit targets.
+ <target dupnames="title" ids="title">
+ <paragraph>
+ First.
+ <system_message backrefs="id1" level="2" line="7" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "title".
+ <target dupnames="title" ids="id1">
+ <paragraph>
+ Second.
+ <system_message backrefs="id2" level="2" line="11" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "title".
+ <target dupnames="title" ids="id2">
+ <paragraph>
+ Third.
+"""],
+["""\
+Duplicate targets:
+
+Target
+======
+
+Implicit section header target.
+
+.. [target] Citation target.
+
+.. [#target] Autonumber-labeled footnote target.
+
+.. _target:
+
+Explicit internal target.
+
+.. _target: Explicit_external_target
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate targets:
+ <section dupnames="target" ids="target">
+ <title>
+ Target
+ <paragraph>
+ Implicit section header target.
+ <citation dupnames="target" ids="id1">
+ <label>
+ target
+ <system_message backrefs="id1" level="1" line="8" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "target".
+ <paragraph>
+ Citation target.
+ <footnote auto="1" dupnames="target" ids="id2">
+ <system_message backrefs="id2" level="2" line="10" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <paragraph>
+ Autonumber-labeled footnote target.
+ <system_message backrefs="id3" level="2" line="12" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id3">
+ <paragraph>
+ Explicit internal target.
+ <system_message backrefs="id4" level="2" line="16" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id4" refuri="Explicit_external_target">
+"""],
+["""\
+.. _unescaped colon at end:: no good
+
+.. _:: no good either
+
+.. _escaped colon\:: OK
+
+.. _`unescaped colon, quoted:`: OK
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ _unescaped colon at end:: no good
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ malformed hyperlink target.
+ <comment xml:space="preserve">
+ _:: no good either
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ malformed hyperlink target.
+ <target ids="escaped-colon" names="escaped\ colon:" refuri="OK">
+ <target ids="unescaped-colon-quoted" names="unescaped\ colon,\ quoted:" refuri="OK">
+"""],
+]
+
+totest['anonymous_targets'] = [
+["""\
+Anonymous external hyperlink target:
+
+.. __: http://w3c.org/
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anonymous external hyperlink target:
+ <target anonymous="1" ids="id1" refuri="http://w3c.org/">
+"""],
+["""\
+Anonymous external hyperlink target:
+
+__ http://w3c.org/
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anonymous external hyperlink target:
+ <target anonymous="1" ids="id1" refuri="http://w3c.org/">
+"""],
+["""\
+Anonymous indirect hyperlink target:
+
+.. __: reference_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anonymous indirect hyperlink target:
+ <target anonymous="1" ids="id1" refname="reference">
+"""],
+["""\
+Anonymous external hyperlink target, not indirect:
+
+__ uri\\_
+
+__ this URI ends with an underscore_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anonymous external hyperlink target, not indirect:
+ <target anonymous="1" ids="id1" refuri="uri_">
+ <target anonymous="1" ids="id2" refuri="thisURIendswithanunderscore_">
+"""],
+["""\
+Anonymous indirect hyperlink targets:
+
+__ reference_
+__ `a very long
+ reference`_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Anonymous indirect hyperlink targets:
+ <target anonymous="1" ids="id1" refname="reference">
+ <target anonymous="1" ids="id2" refname="a very long reference">
+"""],
+["""\
+Mixed anonymous & named indirect hyperlink targets:
+
+__ reference_
+.. __: reference_
+__ reference_
+.. _target1: reference_
+no blank line
+
+.. _target2: reference_
+__ reference_
+.. __: reference_
+__ reference_
+no blank line
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed anonymous & named indirect hyperlink targets:
+ <target anonymous="1" ids="id1" refname="reference">
+ <target anonymous="1" ids="id2" refname="reference">
+ <target anonymous="1" ids="id3" refname="reference">
+ <target ids="target1" names="target1" refname="reference">
+ <system_message level="2" line="7" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+ <target ids="target2" names="target2" refname="reference">
+ <target anonymous="1" ids="id4" refname="reference">
+ <target anonymous="1" ids="id5" refname="reference">
+ <target anonymous="1" ids="id6" refname="reference">
+ <system_message level="2" line="13" source="test data" type="WARNING">
+ <paragraph>
+ Explicit markup ends without a blank line; unexpected unindent.
+ <paragraph>
+ no blank line
+"""],
+["""\
+.. _
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ _
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_parsers/test_rst/test_transitions.py b/test/test_parsers/test_rst/test_transitions.py
new file mode 100755
index 000000000..c60a28e96
--- /dev/null
+++ b/test/test_parsers/test_rst/test_transitions.py
@@ -0,0 +1,309 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for transition markers.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.ParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+# See DocutilsTestSupport.ParserTestSuite.generateTests for a
+# description of the 'totest' data structure.
+totest['transitions'] = [
+["""\
+Test transition markers.
+
+--------
+
+Paragraph
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test transition markers.
+ <transition>
+ <paragraph>
+ Paragraph
+"""],
+["""\
+Section 1
+=========
+First text division of section 1.
+
+--------
+
+Second text division of section 1.
+
+Section 2
+---------
+Paragraph 2 in section 2.
+""",
+"""\
+<document source="test data">
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <paragraph>
+ First text division of section 1.
+ <transition>
+ <paragraph>
+ Second text division of section 1.
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <paragraph>
+ Paragraph 2 in section 2.
+"""],
+["""\
+--------
+
+A section or document may not begin with a transition.
+
+The DTD specifies that two transitions may not
+be adjacent:
+
+--------
+
+--------
+
+--------
+
+The DTD also specifies that a section or document
+may not end with a transition.
+
+--------
+""",
+"""\
+<document source="test data">
+ <transition>
+ <paragraph>
+ A section or document may not begin with a transition.
+ <paragraph>
+ The DTD specifies that two transitions may not
+ be adjacent:
+ <transition>
+ <transition>
+ <transition>
+ <paragraph>
+ The DTD also specifies that a section or document
+ may not end with a transition.
+ <transition>
+"""],
+["""\
+Test unexpected transition markers.
+
+ Block quote.
+
+ --------
+
+ Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test unexpected transition markers.
+ <block_quote>
+ <paragraph>
+ Block quote.
+ <system_message level="4" line="5" source="test data" type="SEVERE">
+ <paragraph>
+ Unexpected section title or transition.
+ <literal_block xml:space="preserve">
+ --------
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Short transition marker.
+
+---
+
+Paragraph
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Short transition marker.
+ <paragraph>
+ ---
+ <paragraph>
+ Paragraph
+"""],
+["""\
+Sections with transitions at beginning and end.
+
+Section 1
+=========
+
+----------
+
+The next transition is legal:
+
+----------
+
+Section 2
+=========
+
+----------
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Sections with transitions at beginning and end.
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <transition>
+ <paragraph>
+ The next transition is legal:
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <transition>
+"""],
+["""\
+A paragraph, two transitions, and a blank line.
+
+----------
+
+----------
+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph, two transitions, and a blank line.
+ <transition>
+ <transition>
+"""],
+["""\
+A paragraph and two transitions.
+
+----------
+
+----------
+""", # the same:
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph and two transitions.
+ <transition>
+ <transition>
+"""],
+["""\
+----------
+
+Document beginning with a transition.
+""",
+"""\
+<document source="test data">
+ <transition>
+ <paragraph>
+ Document beginning with a transition.
+"""],
+["""\
+Section 1
+=========
+
+Subsection 1
+------------
+
+Some text.
+
+----------
+
+Section 2
+=========
+
+Some text.
+""",
+"""\
+<document source="test data">
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <section ids="subsection-1" names="subsection\ 1">
+ <title>
+ Subsection 1
+ <paragraph>
+ Some text.
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <paragraph>
+ Some text.
+"""],
+["""\
+Section 1
+=========
+
+----------
+
+----------
+
+----------
+
+Section 2
+=========
+
+Some text.
+""",
+"""\
+<document source="test data">
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <transition>
+ <transition>
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <paragraph>
+ Some text.
+"""],
+["""\
+----------
+
+----------
+
+----------
+""",
+"""\
+<document source="test data">
+ <transition>
+ <transition>
+ <transition>
+"""],
+["""\
+A paragraph.
+
+----------
+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph.
+ <transition>
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_publisher.py b/test/test_publisher.py
new file mode 100755
index 000000000..708c3ef87
--- /dev/null
+++ b/test/test_publisher.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+
+# Author: Martin Blais
+# Contact: blais@furius.ca
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test the `Publisher` facade and the ``publish_*`` convenience functions.
+"""
+
+import pickle
+from types import StringType, DictType
+import DocutilsTestSupport # must be imported before docutils
+import docutils
+from docutils import core, nodes, io
+
+
+test_document = """\
+Test Document
+=============
+
+This is a test document with a broken reference: nonexistent_
+"""
+pseudoxml_output = """\
+<document ids="test-document" names="test\ document" source="<string>" title="Test Document">
+ <title>
+ Test Document
+ <paragraph>
+ This is a test document with a broken reference: \n\
+ <problematic ids="id2" refid="id1">
+ nonexistent_
+ <section classes="system-messages">
+ <title>
+ Docutils System Messages
+ <system_message backrefs="id2" ids="id1" level="3" line="4" source="<string>" type="ERROR">
+ <paragraph>
+ Unknown target name: "nonexistent".
+"""
+exposed_pseudoxml_output = """\
+<document ids="test-document" internal:refnames="{u\'nonexistent\': [<reference: <#text: u\'nonexistent\'>>]}" names="test\ document" source="<string>" title="Test Document">
+ <title>
+ Test Document
+ <paragraph>
+ This is a test document with a broken reference: \n\
+ <problematic ids="id2" refid="id1">
+ nonexistent_
+ <section classes="system-messages">
+ <title>
+ Docutils System Messages
+ <system_message backrefs="id2" ids="id1" level="3" line="4" source="<string>" type="ERROR">
+ <paragraph>
+ Unknown target name: "nonexistent".
+"""
+
+
+class PublishDoctreeTestCase(DocutilsTestSupport.StandardTestCase, docutils.SettingsSpec):
+
+ settings_default_overrides = {
+ '_disable_config': 1,
+ 'warning_stream': io.NullOutput()}
+
+ def test_publish_doctree(self):
+ # Test `publish_doctree` and `publish_from_doctree`.
+
+ # Produce the document tree.
+ doctree = core.publish_doctree(
+ source=test_document, reader_name='standalone',
+ parser_name='restructuredtext', settings_spec=self,
+ settings_overrides={'expose_internals':
+ ['refnames', 'do_not_expose'],
+ 'report_level': 5})
+ self.assert_(isinstance(doctree, nodes.document))
+
+ # Confirm that transforms have been applied (in this case, the
+ # DocTitle transform):
+ self.assert_(isinstance(doctree[0], nodes.title))
+ self.assert_(isinstance(doctree[1], nodes.paragraph))
+ # Confirm that the Messages transform has not yet been applied:
+ self.assertEquals(len(doctree), 2)
+
+ # The `do_not_expose` attribute may not show up in the
+ # pseudoxml output because the expose_internals transform may
+ # not be applied twice.
+ doctree.do_not_expose = 'test'
+ # Write out the document:
+ output = core.publish_from_doctree(
+ doctree, writer_name='pseudoxml',
+ settings_spec=self,
+ settings_overrides={'expose_internals':
+ ['refnames', 'do_not_expose'],
+ 'report_level': 1})
+ self.assertEquals(output, exposed_pseudoxml_output)
+
+ # Test publishing parts using document as the source.
+ parts = core.publish_parts(
+ reader_name='doctree', source_class=io.DocTreeInput,
+ source=doctree, source_path='test', writer_name='html',
+ settings_spec=self)
+ self.assert_(isinstance(parts, DictType))
+
+ def test_publish_pickle(self):
+ # Test publishing a document tree with pickling and unpickling.
+
+ # Produce the document tree.
+ doctree = core.publish_doctree(
+ source=test_document,
+ reader_name='standalone',
+ parser_name='restructuredtext',
+ settings_spec=self)
+ self.assert_(isinstance(doctree, nodes.document))
+
+ # Pickle the document. Note: if this fails, some unpickleable
+ # reference has been added somewhere within the document tree.
+ # If so, you need to fix that.
+ #
+ # Note: Please do not remove this test, this is an important
+ # requirement, applications will be built on the assumption
+ # that we can pickle the document.
+
+ # Remove the reporter and the transformer before pickling.
+ doctree.reporter = None
+ doctree.transformer = None
+
+ doctree_pickled = pickle.dumps(doctree)
+ self.assert_(isinstance(doctree_pickled, StringType))
+ del doctree
+
+ # Unpickle the document.
+ doctree_zombie = pickle.loads(doctree_pickled)
+ self.assert_(isinstance(doctree_zombie, nodes.document))
+
+ # Write out the document:
+ output = core.publish_from_doctree(
+ doctree_zombie, writer_name='pseudoxml',
+ settings_spec=self)
+ self.assertEquals(output, pseudoxml_output)
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
diff --git a/test/test_readers/__init__.py b/test/test_readers/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_readers/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_readers/test_pep/__init__.py b/test/test_readers/test_pep/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_readers/test_pep/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_readers/test_pep/test_inline_markup.py b/test/test_readers/test_pep/test_inline_markup.py
new file mode 100755
index 000000000..4965af3d1
--- /dev/null
+++ b/test/test_readers/test_pep/test_inline_markup.py
@@ -0,0 +1,140 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for inline markup in PEPs (readers/pep.py).
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.PEPParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+
+totest = {}
+
+totest['standalone_references'] = [
+["""\
+See PEP 287 (pep-0287.txt),
+and RFC 2822 (which obsoletes RFC822 and RFC-733).
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ See \n\
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ PEP 287
+ (
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ pep-0287.txt
+ ),
+ and \n\
+ <reference refuri="http://www.faqs.org/rfcs/rfc2822.html">
+ RFC 2822
+ (which obsoletes \n\
+ <reference refuri="http://www.faqs.org/rfcs/rfc822.html">
+ RFC822
+ and \n\
+ <reference refuri="http://www.faqs.org/rfcs/rfc733.html">
+ RFC-733
+ ).
+"""],
+["""\
+References split across lines:
+
+PEP
+287
+
+RFC
+2822
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ References split across lines:
+ <paragraph>
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ PEP
+ 287
+ <paragraph>
+ <reference refuri="http://www.faqs.org/rfcs/rfc2822.html">
+ RFC
+ 2822
+"""],
+["""\
+Test PEP-specific implicit references before a URL:
+
+PEP 287 (http://www.python.org/peps/pep-0287.html), RFC 2822.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Test PEP-specific implicit references before a URL:
+ <paragraph>
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ PEP 287
+ (
+ <reference refuri="http://www.python.org/peps/pep-0287.html">
+ http://www.python.org/peps/pep-0287.html
+ ), \n\
+ <reference refuri="http://www.faqs.org/rfcs/rfc2822.html">
+ RFC 2822
+ .
+"""],
+]
+
+totest['miscellaneous'] = [
+["""\
+For *completeness*, _`let's` ``test`` **other** forms_
+|of| `inline markup` [*]_.
+
+.. [*] See http://docutils.sf.net/docs/ref/rst/restructuredtext.html.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ For \n\
+ <emphasis>
+ completeness
+ , \n\
+ <target ids="let-s" names="let's">
+ let's
+ \n\
+ <literal>
+ test
+ \n\
+ <strong>
+ other
+ \n\
+ <reference name="forms" refname="forms">
+ forms
+ \n\
+ <substitution_reference refname="of">
+ of
+ \n\
+ <title_reference>
+ inline markup
+ \n\
+ <footnote_reference auto="*" ids="id1">
+ .
+ <footnote auto="*" ids="id2">
+ <paragraph>
+ See \n\
+ <reference refuri="http://docutils.sf.net/docs/ref/rst/restructuredtext.html">
+ http://docutils.sf.net/docs/ref/rst/restructuredtext.html
+ .
+"""],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_readers/test_pep/test_rfc2822.py b/test/test_readers/test_pep/test_rfc2822.py
new file mode 100755
index 000000000..82fa27543
--- /dev/null
+++ b/test/test_readers/test_pep/test_rfc2822.py
@@ -0,0 +1,291 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for RFC-2822 headers in PEPs (readers/pep.py).
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.PEPParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['rfc2822'] = [
+["""\
+Author: Me
+Version: 1
+Date: 2002-04-23
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2002-04-23
+"""],
+["""\
+
+
+Author: Me
+Version: 1
+Date: 2002-04-23
+
+.. Leading blank lines don't affect RFC-2822 header parsing.
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2002-04-23
+ <comment xml:space="preserve">
+ Leading blank lines don't affect RFC-2822 header parsing.
+"""],
+["""\
+.. A comment should prevent RFC-2822 header parsing.
+
+Author: Me
+Version: 1
+Date: 2002-04-23
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ A comment should prevent RFC-2822 header parsing.
+ <paragraph>
+ Author: Me
+ Version: 1
+ Date: 2002-04-23
+"""],
+["""\
+Author: Me
+
+Version: 1
+Date: 2002-04-23
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <paragraph>
+ Version: 1
+ Date: 2002-04-23
+"""],
+["""\
+field:
+empty item above, no blank line
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ field
+ <field_body>
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ RFC2822-style field list ends without a blank line; unexpected unindent.
+ <paragraph>
+ empty item above, no blank line
+"""],
+["""\
+Author:
+ Me
+Version:
+ 1
+Date:
+ 2002-04-23
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <paragraph>
+ Me
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2002-04-23
+"""],
+["""\
+Authors: Me,
+ Myself,
+ and I
+Version: 1
+ or so
+Date: 2002-04-23
+ (Tuesday)
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <paragraph>
+ Me,
+ Myself,
+ and I
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ or so
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2002-04-23
+ (Tuesday)
+"""],
+["""\
+Authors: Me,
+ Myself,
+ and I
+Version: 1
+ or so
+Date: 2002-04-23
+ (Tuesday)
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <paragraph>
+ Me,
+ Myself,
+ and I
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <paragraph>
+ 1
+ or so
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ 2002-04-23
+ (Tuesday)
+"""],
+["""\
+Authors: - Me
+ - Myself
+ - I
+Version:
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ Me
+ <list_item>
+ <paragraph>
+ Myself
+ <list_item>
+ <paragraph>
+ I
+ <field>
+ <field_name>
+ Version
+ <field_body>
+"""],
+["""\
+Authors: Me
+
+ Myself and I
+Version:
+""",
+"""\
+<document source="test data">
+ <field_list classes="rfc2822">
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <paragraph>
+ Me
+ <block_quote>
+ <paragraph>
+ Myself and I
+ <system_message level="2" line="4" source="test data" type="WARNING">
+ <paragraph>
+ Block quote ends without a blank line; unexpected unindent.
+ <paragraph>
+ Version:
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_readers/test_python/__init__.py b/test/test_readers/test_python/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_readers/test_python/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_readers/test_python/showast b/test/test_readers/test_python/showast
new file mode 100755
index 000000000..e7d846307
--- /dev/null
+++ b/test/test_readers/test_python/showast
@@ -0,0 +1,57 @@
+#! /usr/bin/env python
+
+"""
+This is a tool for exploring abstract syntax trees generated by
+``compiler.parse()`` from test data in
+docutils/test/test_readers/test_python/test_parser or stdin.
+
+Usage::
+
+ showast <key> <index>
+
+ showast < <module.py>
+
+Where ``<key>`` is the key to the ``totest`` dictionary, and ``<index>`` is
+the index of the list ``totest[key]``. If no arguments are given, stdin is
+used for input.
+"""
+
+import sys
+import compiler
+from compiler.ast import Node
+import test_parser
+
+def pformat(ast, indent=' ', level=0):
+ assert isinstance(ast, Node), 'ast is not a Node: %r' % (ast,)
+ atts = {}
+ for name, value in vars(ast).items():
+ if not value or isinstance(value, Node):
+ continue
+ if isinstance(value, list):
+ if isinstance(value[0], Node):
+ continue
+ if isinstance(value[0], tuple) and value[0] \
+ and isinstance(value[0][0], Node):
+ continue
+ atts[name] = str(value).encode('unicode-escape')
+ attlist = atts.items()
+ attlist.sort()
+ parts = [ast.__class__.__name__]
+ for name, value in attlist:
+ parts.append('%s="%s"' % (name, value))
+ result = ['%s<%s>\n' % (indent * level, ' '.join(parts))]
+ for node in ast.getChildNodes():
+ result.extend(pformat(node, level=level+1))
+ return result
+
+if len(sys.argv) > 1:
+ key, caseno = sys.argv[1:]
+ print 'totest["%s"][%s][0]:\n' % (key, caseno)
+ input_text = test_parser.totest[key][int(caseno)][0]
+else:
+ input_text = sys.stdin.read()
+print input_text
+module = compiler.parse(input_text)
+print module
+print
+print ''.join(pformat(module)),
diff --git a/test/test_readers/test_python/showdoc b/test/test_readers/test_python/showdoc
new file mode 100755
index 000000000..6461960f8
--- /dev/null
+++ b/test/test_readers/test_python/showdoc
@@ -0,0 +1,33 @@
+#! /usr/bin/env python
+
+"""
+This is a tool for exploring module documentation trees generated by
+``docutils.readers.python.moduleparser.parse_module()`` from test data in
+docutils/test/test_readers/test_python/test_parser or stdin.
+
+Usage::
+
+ showdoc <key> <index>
+
+ showdoc < <module.py>
+
+Where ``<key>`` is the key to the ``totest`` dictionary, and ``<index>`` is
+the index of the list ``totest[key]``. If no arguments are given, stdin is
+used for input.
+"""
+
+import sys
+from docutils.readers.python.moduleparser import parse_module
+import test_parser
+
+if len(sys.argv) > 1:
+ key, caseno = sys.argv[1:]
+ print 'totest["%s"][%s][0]:\n' % (key, caseno)
+ input_text = test_parser.totest[key][int(caseno)][0]
+ input_source = "test_parser.totest['%s'][%s][0]" % (key, caseno)
+else:
+ input_text = sys.stdin.read()
+ input_source = '<stdin>'
+print input_text
+module = parse_module(input_text, input_source)
+print module,
diff --git a/test/test_readers/test_python/showparse b/test/test_readers/test_python/showparse
new file mode 100755
index 000000000..8144256d6
--- /dev/null
+++ b/test/test_readers/test_python/showparse
@@ -0,0 +1,48 @@
+#! /usr/bin/env python
+
+"""
+This is a tool for exploring abstract syntax trees generated by
+``parser.suite()`` from test data in
+docutils/test/test_readers/test_python/test_parser or stdin.
+
+Usage::
+
+ showparse <key> <index>
+
+ showparse < <module.py>
+
+Where ``<key>`` is the key to the ``totest`` dictionary, and ``<index>`` is
+the index of the list ``totest[key]``. If no arguments are given, stdin is
+used for input.
+"""
+
+import sys
+import types
+import parser
+import token
+import symbol
+import pprint
+import test_parser
+
+names = token.tok_name.copy()
+names.update(symbol.sym_name)
+
+def name_elements(ast):
+ if ast:
+ name = names[ast[0]]
+ ast[0] = '%s (%s)' % (name, ast[0])
+ for node in ast[1:]:
+ if type(node) == types.ListType:
+ name_elements(node)
+
+if len(sys.argv) > 1:
+ key, caseno = sys.argv[1:]
+ print 'totest["%s"][%s][0]:\n' % (key, caseno)
+ input_text = test_parser.totest[key][int(caseno)][0]
+else:
+ input_text = sys.stdin.read()
+print input_text
+module = parser.suite(input_text)
+ast = parser.ast2list(module, line_info=1)
+name_elements(ast)
+pprint.pprint(ast)
diff --git a/test/test_readers/test_python/showtok b/test/test_readers/test_python/showtok
new file mode 100755
index 000000000..efd250ce1
--- /dev/null
+++ b/test/test_readers/test_python/showtok
@@ -0,0 +1,40 @@
+#! /usr/bin/env python
+
+
+"""
+This is a tool for exploring token lists generated by
+``tokenize.generate_tokens()`` from test data in
+docutils/test/test_readers/test_python/test_parser or stdin.
+
+Usage::
+
+ showtok <key> <index>
+
+ showtok < <module.py>
+
+Where ``<key>`` is the key to the ``totest`` dictionary, and ``<index>`` is
+the index of the list ``totest[key]``. If no arguments are given, stdin is
+used for input.
+"""
+
+import sys
+import tokenize
+import pprint
+from token import tok_name
+import test_parser
+
+def name_tokens(tokens):
+ for i in range(len(tokens)):
+ tup = tokens[i]
+ tokens[i] = (tok_name[tup[0]], tup)
+
+if len(sys.argv) > 1:
+ key, caseno = sys.argv[1:]
+ print 'totest["%s"][%s][0]:\n' % (key, caseno)
+ input_text = test_parser.totest[key][int(caseno)][0]
+else:
+ input_text = sys.stdin.read()
+print input_text
+tokens = list(tokenize.generate_tokens(iter(input_text.splitlines(1)).next))
+name_tokens(tokens)
+pprint.pprint(tokens)
diff --git a/test/test_readers/test_python/test_functions.py b/test/test_readers/test_python/test_functions.py
new file mode 100755
index 000000000..d521b2203
--- /dev/null
+++ b/test/test_readers/test_python/test_functions.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for PySource Reader functions.
+"""
+
+import unittest
+from __init__ import DocutilsTestSupport
+from docutils.readers.python.moduleparser import trim_docstring
+
+
+class MiscTests(unittest.TestCase):
+
+ docstrings = (
+ ("""""", """"""), # empty
+ ("""Begins on the first line.
+
+ Middle line indented.
+
+ Last line unindented.
+ """,
+ """\
+Begins on the first line.
+
+ Middle line indented.
+
+Last line unindented."""),
+ ("""
+ Begins on the second line.
+
+ Middle line indented.
+
+ Last line unindented.""",
+ """\
+Begins on the second line.
+
+ Middle line indented.
+
+Last line unindented."""),
+ ("""All on one line.""", """All on one line."""))
+
+ def test_trim_docstring(self):
+ for docstring, expected in self.docstrings:
+ self.assertEquals(trim_docstring(docstring), expected)
+ self.assertEquals(trim_docstring('\n ' + docstring),
+ expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_readers/test_python/test_parser.py b/test/test_readers/test_python/test_parser.py
new file mode 100755
index 000000000..1ccfbdc10
--- /dev/null
+++ b/test/test_readers/test_python/test_parser.py
@@ -0,0 +1,989 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils/readers/python/moduleparser.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.PythonModuleParserTestSuite()
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['module'] = [
+['''\
+''',
+'''\
+<module_section filename="test data">
+'''],
+['''\
+"""docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ docstring
+'''],
+['''\
+u"""Unicode docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ Unicode docstring
+'''],
+['''\
+"""docstring"""
+"""additional docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ docstring
+ <docstring lineno="2">
+ additional docstring
+'''],
+['''\
+"""docstring"""
+# comment
+"""additional docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ docstring
+ <docstring lineno="3">
+ additional docstring
+'''],
+['''\
+"""docstring"""
+1
+"""not an additional docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ docstring
+'''],
+]
+
+totest['import'] = [
+['''\
+import module
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_name>
+ module
+'''],
+['''\
+import module as local
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_name>
+ module
+ <import_alias>
+ local
+'''],
+['''\
+import module.name
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_name>
+ module.name
+'''],
+['''\
+import module.name as local
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_name>
+ module.name
+ <import_alias>
+ local
+'''],
+['''\
+import module
+"""not documentable"""
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_name>
+ module
+'''],
+]
+
+totest['from'] = [
+['''\
+from module import name
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module
+ <import_name>
+ name
+'''],
+['''\
+from module import name as local
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module
+ <import_name>
+ name
+ <import_alias>
+ local
+'''],
+['''\
+from module import name1, name2 as local2
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module
+ <import_name>
+ name1
+ <import_name>
+ name2
+ <import_alias>
+ local2
+'''],
+['''\
+from module.sub import name
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module.sub
+ <import_name>
+ name
+'''],
+['''\
+from module.sub import name as local
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module.sub
+ <import_name>
+ name
+ <import_alias>
+ local
+'''],
+['''\
+from module import *
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ module
+ <import_name>
+ *
+'''],
+['''\
+from __future__ import division
+''',
+'''\
+<module_section filename="test data">
+ <import_group lineno="1">
+ <import_from>
+ __future__
+ <import_name>
+ division
+'''],
+]
+
+totest['assign'] = [
+['''\
+a = 1
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1
+'''],
+['''a = 1''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1
+'''],
+['''\
+a = 1
+"""a docstring"""
+''', #"
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1
+ <docstring lineno="2">
+ a docstring
+'''],
+['''\
+a = 1
+"""a docstring"""
+"""additional docstring"""
+''', #"
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1
+ <docstring lineno="2">
+ a docstring
+ <docstring lineno="3">
+ additional docstring
+'''], #'
+['''\
+a = 1 + 2 * 3 / 4 ** 5
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1 + 2 * 3 / 4 ** 5
+'''],
+['''\
+a = 1 \\
+ + 2
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1 + 2
+'''],
+['''\
+a = not 1 and 2 or 3
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ not 1 and 2 or 3
+'''],
+['''\
+a = ~ 1 & 2 | 3 ^ 4
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ ~ 1 & 2 | 3 ^ 4
+'''],
+['''\
+a = `1 & 2`
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ `1 & 2`
+'''],
+['''\
+very_long_name = \\
+ x
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ very_long_name
+ <expression_value>
+ x
+'''],
+['''\
+very_long_name \\
+ = x
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ very_long_name
+ <expression_value>
+ x
+'''],
+['''\
+very_long_name = \\
+ another_long_name = \\
+ x
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ very_long_name
+ <expression_value>
+ x
+ <attribute lineno="2">
+ <object_name>
+ another_long_name
+ <expression_value>
+ x
+'''],
+['''\
+a = (1
+ + 2)
+b = a.b[1 +
+ fn(x, y,
+ z, {'key': (1 + 2
+ + 3)})][4]
+c = """first line
+second line
+ third"""
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ (1 + 2)
+ <attribute lineno="3">
+ <object_name>
+ b
+ <expression_value>
+ a.b[1 + fn(x, y, z, {'key': (1 + 2 + 3)})][4]
+ <attribute lineno="7">
+ <object_name>
+ c
+ <expression_value>
+ """first line
+ second line
+ third"""
+'''],
+['''\
+a, b, c = range(3)
+(d, e,
+ f) = a, b, c
+g, h, i = j = a, b, c
+k.a, k.b.c, k.d.e.f = a, b, c
+''',
+'''\
+<module_section filename="test data">
+ <attribute_tuple lineno="1">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <attribute lineno="1">
+ <object_name>
+ b
+ <attribute lineno="1">
+ <object_name>
+ c
+ <expression_value>
+ range(3)
+ <attribute_tuple lineno="2">
+ <attribute lineno="2">
+ <object_name>
+ d
+ <attribute lineno="2">
+ <object_name>
+ e
+ <attribute lineno="3">
+ <object_name>
+ f
+ <expression_value>
+ a, b, c
+ <attribute_tuple lineno="4">
+ <attribute lineno="4">
+ <object_name>
+ g
+ <attribute lineno="4">
+ <object_name>
+ h
+ <attribute lineno="4">
+ <object_name>
+ i
+ <expression_value>
+ a, b, c
+ <attribute lineno="4">
+ <object_name>
+ j
+ <expression_value>
+ a, b, c
+ <attribute_tuple lineno="5">
+ <attribute lineno="5">
+ <object_name>
+ k.a
+ <attribute lineno="5">
+ <object_name>
+ k.b.c
+ <attribute lineno="5">
+ <object_name>
+ k.d.e.f
+ <expression_value>
+ a, b, c
+'''],
+['''\
+a = 1 ; b = 2
+print ; c = 3
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ 1
+ <attribute lineno="1">
+ <object_name>
+ b
+ <expression_value>
+ 2
+ <attribute lineno="2">
+ <object_name>
+ c
+ <expression_value>
+ 3
+'''],
+['''\
+a.b = 1
+"""This assignment is noted but ignored unless ``a`` is a function."""
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a.b
+ <expression_value>
+ 1
+ <docstring lineno="2">
+ This assignment is noted but ignored unless ``a`` is a function.
+'''],
+['''\
+a[b] = 1
+"""Subscript assignments are ignored."""
+''',
+'''\
+<module_section filename="test data">
+'''],
+['''\
+a = foo(b=1)
+''',
+'''\
+<module_section filename="test data">
+ <attribute lineno="1">
+ <object_name>
+ a
+ <expression_value>
+ foo(b=1)
+'''],
+# ['''\
+# a = 1
+#
+# """Because of the blank above, this is a module docstring."""
+# ''',
+# '''\
+# <module_section filename="test data">
+# <attribute lineno="1">
+# <object_name>
+# a
+# <expression_value>
+# 1
+# <docstring lineno="3">
+# Because of the blank above, this is a module docstring.
+# '''],
+]
+
+totest['def'] = [
+['''\
+def f():
+ """Function f docstring"""
+ """Additional docstring"""
+ local = 1
+ """Not a docstring, since ``local`` is local."""
+''', # "
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <docstring lineno="1">
+ Function f docstring
+ <docstring lineno="3">
+ Additional docstring
+'''], # '
+['''\
+def f(a, b):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter>
+ <object_name>
+ a
+ <parameter>
+ <object_name>
+ b
+'''],
+['''\
+def f(a=None, b=1):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter>
+ <object_name>
+ a
+ <parameter_default>
+ None
+ <parameter>
+ <object_name>
+ b
+ <parameter_default>
+ 1
+'''],
+['''\
+def f(a, (b, c, d)=range(3),
+ e=None):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter>
+ <object_name>
+ a
+ <parameter_tuple>
+ <parameter>
+ <object_name>
+ b
+ <parameter>
+ <object_name>
+ c
+ <parameter>
+ <object_name>
+ d
+ <parameter_default>
+ range(3)
+ <parameter>
+ <object_name>
+ e
+ <parameter_default>
+ None
+'''],
+['''\
+def f(*args):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter excess_positional="1">
+ <object_name>
+ args
+'''],
+['''\
+def f(**kwargs):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter excess_keyword="1">
+ <object_name>
+ kwargs
+'''],
+['''\
+def f(a, b=None, *args, **kwargs):
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter>
+ <object_name>
+ a
+ <parameter>
+ <object_name>
+ b
+ <parameter_default>
+ None
+ <parameter excess_positional="1">
+ <object_name>
+ args
+ <parameter excess_keyword="1">
+ <object_name>
+ kwargs
+'''],
+['''\
+def f():
+ pass
+f.attrib = 1
+"""f.attrib docstring"""
+''', # "
+# @@@ When should the attribute move inside the Function?
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+ <attribute lineno="3">
+ <object_name>
+ f.attrib
+ <expression_value>
+ 1
+ <docstring lineno="4">
+ f.attrib docstring
+'''],
+['''\
+def f():
+ def g():
+ pass
+ """Not a docstring"""
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <function_section lineno="1">
+ <object_name>
+ f
+'''],
+]
+
+totest['class'] = [
+['''\
+class C:
+ """class C docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+ <docstring lineno="1">
+ class C docstring
+'''],
+['''\
+class C(Super):
+ pass
+
+class D(SuperD, package.module.SuperD):
+ pass
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+ <class_base>
+ <object_name>
+ Super
+ <class_section lineno="4">
+ <object_name>
+ D
+ <class_base>
+ <object_name>
+ SuperD
+ <class_base>
+ <object_name>
+ package.module.SuperD
+'''],
+['''\
+class C:
+ class D:
+ pass
+ """Not a docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+'''],
+['''\
+class C:
+ def f(self):
+ self.local = 1
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+ <method_section lineno="2">
+ <object_name>
+ f
+ <parameter_list>
+ <parameter>
+ <object_name>
+ self
+'''],
+['''\
+class C:
+ def __init__(self):
+ self.local = 1
+ local = 1
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+ <method_section lineno="2">
+ <object_name>
+ __init__
+ <parameter_list>
+ <parameter>
+ <object_name>
+ self
+ <attribute lineno="3">
+ <object_name>
+ self.local
+ <expression_value>
+ 1
+ <attribute lineno="4">
+ <object_name>
+ local
+ <expression_value>
+ 1
+'''],
+['''\
+class C:
+ def __init__(self):
+ local = foo(a=1)
+''',
+'''\
+<module_section filename="test data">
+ <class_section lineno="1">
+ <object_name>
+ C
+ <method_section lineno="2">
+ <object_name>
+ __init__
+ <parameter_list>
+ <parameter>
+ <object_name>
+ self
+ <attribute lineno="3">
+ <object_name>
+ local
+ <expression_value>
+ foo(a=1)
+'''],
+]
+
+totest['ignore'] = [
+['''\
+1 + 2
+''',
+'''\
+<module_section filename="test data">
+'''],
+['''\
+del a
+''',
+'''\
+<module_section filename="test data">
+'''],
+]
+
+totest['comments'] = [
+# ['''\
+# # Comment
+# ''',
+# '''\
+# <module_section filename="test data">
+# <Comment lineno="1">
+# # Comment
+# '''],
+]
+
+# @@@ we don't parse comments yet
+totest['everything'] = [
+['''\
+# comment
+
+"""Docstring"""
+
+"""Additional docstring"""
+
+__docformat__ = 'reStructuredText'
+
+a = 1
+"""Attribute docstring"""
+
+class C(Super):
+
+ """C docstring"""
+
+ class_attribute = 1
+ """class_attribute docstring"""
+
+ def __init__(self, text=None):
+ """__init__ docstring"""
+
+ self.instance_attribute = (text * 7
+ + ' whaddyaknow')
+ """instance_attribute docstring"""
+
+
+def f(x, # parameter x
+ y=a*5, # parameter y
+ *args): # parameter args
+ """f docstring"""
+ return [x + item for item in args]
+
+f.function_attribute = 1
+"""f.function_attribute docstring"""
+''',
+'''\
+<module_section filename="test data">
+ <docstring>
+ Docstring
+ <docstring lineno="5">
+ Additional docstring
+ <attribute lineno="7">
+ <object_name>
+ __docformat__
+ <expression_value>
+ 'reStructuredText'
+ <attribute lineno="9">
+ <object_name>
+ a
+ <expression_value>
+ 1
+ <docstring lineno="10">
+ Attribute docstring
+ <class_section lineno="12">
+ <object_name>
+ C
+ <class_base>
+ <object_name>
+ Super
+ <docstring lineno="12">
+ C docstring
+ <attribute lineno="16">
+ <object_name>
+ class_attribute
+ <expression_value>
+ 1
+ <docstring lineno="17">
+ class_attribute docstring
+ <method_section lineno="19">
+ <object_name>
+ __init__
+ <docstring lineno="19">
+ __init__ docstring
+ <parameter_list>
+ <parameter>
+ <object_name>
+ self
+ <parameter>
+ <object_name>
+ text
+ <parameter_default>
+ None
+ <attribute lineno="22">
+ <object_name>
+ self.instance_attribute
+ <expression_value>
+ (text * 7 + ' whaddyaknow')
+ <docstring lineno="24">
+ instance_attribute docstring
+ <function_section lineno="27">
+ <object_name>
+ f
+ <docstring lineno="27">
+ f docstring
+ <parameter_list>
+ <parameter>
+ <object_name>
+ x
+ <parameter>
+ <object_name>
+ y
+ <parameter_default>
+ a * 5
+ <parameter excess_positional="1">
+ <object_name>
+ args
+ <attribute lineno="33">
+ <object_name>
+ f.function_attribute
+ <expression_value>
+ 1
+ <docstring lineno="34">
+ f.function_attribute docstring
+'''],
+]
+
+"""
+['''\
+''',
+'''\
+'''],
+"""
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_readers/test_python/test_token_parser.py b/test/test_readers/test_python/test_token_parser.py
new file mode 100755
index 000000000..23015a7dc
--- /dev/null
+++ b/test/test_readers/test_python/test_token_parser.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils/readers/python/moduleparser.py.
+"""
+
+from __init__ import DocutilsTestSupport
+
+
+def suite():
+ s = DocutilsTestSupport.PythonModuleParserTestSuite()
+ s.generateTests(totest, testmethod='test_token_parser_rhs')
+ return s
+
+totest = {}
+
+totest['expressions'] = [
+['''a = 1''', '''1'''],
+['''a = b = 1''', '''1'''],
+['''\
+a = (
+ 1 + 2
+ + 3
+ )
+''',
+'''(1 + 2 + 3)'''],
+['''\
+a = """\\
+line one
+line two"""
+''',
+'''"""\\\nline one\nline two"""'''],
+['''a = `1`''', '''`1`'''],
+['''a = `1`+`2`''', '''`1` + `2`'''],
+]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_settings.py b/test/test_settings.py
new file mode 100755
index 000000000..c18d613de
--- /dev/null
+++ b/test/test_settings.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests of runtime settings.
+"""
+
+import sys
+import os
+import docutils_difflib
+import pprint
+import warnings
+import unittest
+from types import StringType
+import DocutilsTestSupport # must be imported before docutils
+from docutils import frontend, utils
+from docutils.writers import html4css1, pep_html
+from docutils.parsers import rst
+
+
+warnings.filterwarnings(action='ignore',
+ category=frontend.ConfigDeprecationWarning)
+
+def fixpath(path):
+ return os.path.abspath(os.path.join(*(path.split('/'))))
+
+
+class ConfigFileTests(unittest.TestCase):
+
+ config_files = {'old': fixpath('data/config_old.txt'),
+ 'one': fixpath('data/config_1.txt'),
+ 'two': fixpath('data/config_2.txt'),
+ 'list': fixpath('data/config_list.txt'),
+ 'list2': fixpath('data/config_list_2.txt'),
+ 'error': fixpath('data/config_error_handler.txt')}
+
+ settings = {
+ 'old': {'datestamp': '%Y-%m-%d %H:%M UTC',
+ 'generator': 1,
+ 'no_random': 1,
+ 'python_home': 'http://www.python.org',
+ 'source_link': 1,
+ 'stylesheet': None,
+ 'stylesheet_path': fixpath('data/stylesheets/pep.css'),
+ 'template': fixpath('data/pep-html-template')},
+ 'one': {'datestamp': '%Y-%m-%d %H:%M UTC',
+ 'generator': 1,
+ 'no_random': 1,
+ 'python_home': 'http://www.python.org',
+ 'record_dependencies': utils.DependencyList(),
+ 'source_link': 1,
+ 'stylesheet': None,
+ 'stylesheet_path': fixpath('data/stylesheets/pep.css'),
+ 'tab_width': 8,
+ 'template': fixpath('data/pep-html-template'),
+ 'trim_footnote_reference_space': 1},
+ 'two': {'footnote_references': 'superscript',
+ 'generator': 0,
+ 'record_dependencies': utils.DependencyList(),
+ 'stylesheet': None,
+ 'stylesheet_path': fixpath('data/test.css'),
+ 'trim_footnote_reference_space': None},
+ 'list': {'expose_internals': ['a', 'b', 'c', 'd', 'e']},
+ 'list2': {'expose_internals': ['a', 'b', 'c', 'd', 'e', 'f']},
+ 'error': {'error_encoding': 'ascii',
+ 'error_encoding_error_handler': 'strict'},
+ }
+
+ compare = docutils_difflib.Differ().compare
+ """Comparison method shared by all tests."""
+
+ def setUp(self):
+ self.option_parser = frontend.OptionParser(
+ components=(pep_html.Writer, rst.Parser), read_config_files=None)
+
+ def files_settings(self, *names):
+ settings = frontend.Values()
+ for name in names:
+ settings.update(self.option_parser.get_config_file_settings(
+ self.config_files[name]), self.option_parser)
+ return settings.__dict__
+
+ def expected_settings(self, *names):
+ expected = {}
+ for name in names:
+ expected.update(self.settings[name])
+ return expected
+
+ def compare_output(self, result, expected):
+ """`result` and `expected` should both be dicts."""
+ self.assert_(result.has_key('record_dependencies'))
+ if not expected.has_key('record_dependencies'):
+ # Delete it if we don't want to test it.
+ del result['record_dependencies']
+ result = pprint.pformat(result) + '\n'
+ expected = pprint.pformat(expected) + '\n'
+ try:
+ self.assertEquals(result, expected)
+ except AssertionError:
+ print >>sys.stderr, '\n%s\n' % (self,)
+ print >>sys.stderr, '-: expected\n+: result'
+ print >>sys.stderr, ''.join(self.compare(expected.splitlines(1),
+ result.splitlines(1)))
+ raise
+
+ def test_nofiles(self):
+ self.compare_output(self.files_settings(),
+ self.expected_settings())
+
+ def test_old(self):
+ self.compare_output(self.files_settings('old'),
+ self.expected_settings('old'))
+
+ def test_one(self):
+ self.compare_output(self.files_settings('one'),
+ self.expected_settings('one'))
+
+ def test_multiple(self):
+ self.compare_output(self.files_settings('one', 'two'),
+ self.expected_settings('one', 'two'))
+
+ def test_old_and_new(self):
+ self.compare_output(self.files_settings('old', 'two'),
+ self.expected_settings('old', 'two'))
+
+ def test_list(self):
+ self.compare_output(self.files_settings('list'),
+ self.expected_settings('list'))
+
+ def test_list2(self):
+ self.compare_output(self.files_settings('list', 'list2'),
+ self.expected_settings('list2'))
+
+ def test_error_handler(self):
+ self.compare_output(self.files_settings('error'),
+ self.expected_settings('error'))
+
+
+class ConfigEnvVarFileTests(ConfigFileTests):
+
+ """
+ Repeats the tests of `ConfigFileTests` using the ``DOCUTILSCONFIG``
+ environment variable and the standard Docutils config file mechanism.
+ """
+
+ def setUp(self):
+ ConfigFileTests.setUp(self)
+ self.orig_environ = os.environ
+ os.environ = os.environ.copy()
+
+ def files_settings(self, *names):
+ files = [self.config_files[name] for name in names]
+ os.environ['DOCUTILSCONFIG'] = os.pathsep.join(files)
+ settings = self.option_parser.get_standard_config_settings()
+ return settings.__dict__
+
+ def tearDown(self):
+ os.environ = self.orig_environ
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_statemachine.py b/test/test_statemachine.py
new file mode 100755
index 000000000..4ca2a0144
--- /dev/null
+++ b/test/test_statemachine.py
@@ -0,0 +1,283 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for statemachine.py.
+"""
+
+import unittest
+import sys
+import re
+from DocutilsTestSupport import statemachine
+
+
+debug = 0
+testtext = statemachine.string2lines("""\
+First paragraph.
+
+- This is a bullet list. First list item.
+ Second line of first para.
+
+ Second para.
+
+ block quote
+
+- Second list item. Example::
+
+ a
+ literal
+ block
+
+Last paragraph.""")
+expected = ('StateMachine1 text1 blank1 bullet1 known_indent1 '
+ 'StateMachine2 text2 text2 blank2 text2 blank2 indent2 '
+ 'StateMachine3 text3 blank3 finished3 finished2 '
+ 'bullet1 known_indent1 '
+ 'StateMachine2 text2 blank2 literalblock2(4) finished2 '
+ 'text1 finished1').split()
+para1 = testtext[:2]
+item1 = [line[2:] for line in testtext[2:9]]
+item2 = [line[2:] for line in testtext[9:-1]]
+lbindent = 6
+literalblock = [line[lbindent:] for line in testtext[11:-1]]
+para2 = testtext[-1]
+
+
+class MockState(statemachine.StateWS):
+
+ patterns = {'bullet': re.compile(r'- '),
+ 'text': ''}
+ initial_transitions = ['bullet', ['text']]
+ levelholder = [0]
+
+ def bof(self, context):
+ self.levelholder[0] += 1
+ self.level = self.levelholder[0]
+ if self.debug: print >>sys.stderr, 'StateMachine%s' % self.level
+ return [], ['StateMachine%s' % self.level]
+
+ def blank(self, match, context, next_state):
+ result = ['blank%s' % self.level]
+ if self.debug: print >>sys.stderr, 'blank%s' % self.level
+ if context and context[-1] and context[-1][-2:] == '::':
+ result.extend(self.literalblock())
+ return [], None, result
+
+ def indent(self, match, context, next_state):
+ if self.debug: print >>sys.stderr, 'indent%s' % self.level
+ context, next_state, result = statemachine.StateWS.indent(
+ self, match, context, next_state)
+ return context, next_state, ['indent%s' % self.level] + result
+
+ def known_indent(self, match, context, next_state):
+ if self.debug: print >>sys.stderr, 'known_indent%s' % self.level
+ context, next_state, result = statemachine.StateWS.known_indent(
+ self, match, context, next_state)
+ return context, next_state, ['known_indent%s' % self.level] + result
+
+ def bullet(self, match, context, next_state):
+ if self.debug: print >>sys.stderr, 'bullet%s' % self.level
+ context, next_state, result \
+ = self.known_indent(match, context, next_state)
+ return [], next_state, ['bullet%s' % self.level] + result
+
+ def text(self, match, context, next_state):
+ if self.debug: print >>sys.stderr, 'text%s' % self.level
+ return [match.string], next_state, ['text%s' % self.level]
+
+ def literalblock(self):
+ indented, indent, offset, good = self.state_machine.get_indented()
+ if self.debug: print >>sys.stderr, 'literalblock%s(%s)' % (self.level,
+ indent)
+ return ['literalblock%s(%s)' % (self.level, indent)]
+
+ def eof(self, context):
+ self.levelholder[0] -= 1
+ if self.debug: print >>sys.stderr, 'finished%s' % self.level
+ return ['finished%s' % self.level]
+
+
+class EmptySMTests(unittest.TestCase):
+
+ def setUp(self):
+ self.sm = statemachine.StateMachine(
+ state_classes=[], initial_state='State')
+ self.sm.debug = debug
+
+ def test_add_state(self):
+ self.sm.add_state(statemachine.State)
+ self.assert_(len(self.sm.states) == 1)
+ self.assertRaises(statemachine.DuplicateStateError, self.sm.add_state,
+ statemachine.State)
+ self.sm.add_state(statemachine.StateWS)
+ self.assert_(len(self.sm.states) == 2)
+
+ def test_add_states(self):
+ self.sm.add_states((statemachine.State, statemachine.StateWS))
+ self.assertEqual(len(self.sm.states), 2)
+
+ def test_get_state(self):
+ self.assertRaises(statemachine.UnknownStateError, self.sm.get_state)
+ self.sm.add_states((statemachine.State, statemachine.StateWS))
+ self.assertRaises(statemachine.UnknownStateError, self.sm.get_state,
+ 'unknownState')
+ self.assert_(isinstance(self.sm.get_state('State'),
+ statemachine.State))
+ self.assert_(isinstance(self.sm.get_state('StateWS'),
+ statemachine.State))
+ self.assertEqual(self.sm.current_state, 'StateWS')
+
+
+class EmptySMWSTests(EmptySMTests):
+
+ def setUp(self):
+ self.sm = statemachine.StateMachineWS(
+ state_classes=[], initial_state='State')
+ self.sm.debug = debug
+
+
+class SMWSTests(unittest.TestCase):
+
+ def setUp(self):
+ self.sm = statemachine.StateMachineWS([MockState], 'MockState',
+ debug=debug)
+ self.sm.debug = debug
+ self.sm.states['MockState'].levelholder[0] = 0
+
+ def tearDown(self):
+ self.sm.unlink()
+
+ def test___init__(self):
+ self.assertEquals(self.sm.states.keys(), ['MockState'])
+ self.assertEquals(len(self.sm.states['MockState'].transitions), 4)
+
+ def test_get_indented(self):
+ self.sm.input_lines = statemachine.StringList(testtext)
+ self.sm.line_offset = -1
+ self.sm.next_line(3)
+ indented, offset, good = self.sm.get_known_indented(2)
+ self.assertEquals(indented, item1)
+ self.assertEquals(offset, len(para1))
+ self.failUnless(good)
+ self.sm.next_line()
+ indented, offset, good = self.sm.get_known_indented(2)
+ self.assertEquals(indented, item2)
+ self.assertEquals(offset, len(para1) + len(item1))
+ self.failUnless(good)
+ self.sm.previous_line(3)
+ if self.sm.debug:
+ print '\ntest_get_indented: self.sm.line:\n', self.sm.line
+ indented, indent, offset, good = self.sm.get_indented()
+ if self.sm.debug:
+ print '\ntest_get_indented: indented:\n', indented
+ self.assertEquals(indent, lbindent)
+ self.assertEquals(indented, literalblock)
+ self.assertEquals(offset, (len(para1) + len(item1) + len(item2)
+ - len(literalblock)))
+ self.failUnless(good)
+
+ def test_get_text_block(self):
+ self.sm.input_lines = statemachine.StringList(testtext)
+ self.sm.line_offset = -1
+ self.sm.next_line()
+ textblock = self.sm.get_text_block()
+ self.assertEquals(textblock, testtext[:1])
+ self.sm.next_line(2)
+ textblock = self.sm.get_text_block()
+ self.assertEquals(textblock, testtext[2:4])
+
+ def test_get_text_block_flush_left(self):
+ self.sm.input_lines = statemachine.StringList(testtext)
+ self.sm.line_offset = -1
+ self.sm.next_line()
+ textblock = self.sm.get_text_block(flush_left=1)
+ self.assertEquals(textblock, testtext[:1])
+ self.sm.next_line(2)
+ self.assertRaises(statemachine.UnexpectedIndentationError,
+ self.sm.get_text_block, flush_left=1)
+
+ def test_run(self):
+ self.assertEquals(self.sm.run(testtext), expected)
+
+
+class EmptyClass:
+ pass
+
+
+class EmptyStateTests(unittest.TestCase):
+
+ def setUp(self):
+ self.state = statemachine.State(EmptyClass(), debug=debug)
+ self.state.patterns = {'nop': 'dummy',
+ 'nop2': 'dummy',
+ 'nop3': 'dummy',
+ 'bogus': 'dummy'}
+ self.state.nop2 = self.state.nop3 = self.state.nop
+
+ def test_add_transitions(self):
+ self.assertEquals(len(self.state.transitions), 0)
+ self.state.add_transitions(['None'], {'None': None})
+ self.assertEquals(len(self.state.transitions), 1)
+ self.assertRaises(statemachine.UnknownTransitionError,
+ self.state.add_transitions, ['bogus'], {})
+ self.assertRaises(statemachine.DuplicateTransitionError,
+ self.state.add_transitions, ['None'],
+ {'None': None})
+
+ def test_add_transition(self):
+ self.assertEquals(len(self.state.transitions), 0)
+ self.state.add_transition('None', None)
+ self.assertEquals(len(self.state.transitions), 1)
+ self.assertRaises(statemachine.DuplicateTransitionError,
+ self.state.add_transition, 'None', None)
+
+ def test_remove_transition(self):
+ self.assertEquals(len(self.state.transitions), 0)
+ self.state.add_transition('None', None)
+ self.assertEquals(len(self.state.transitions), 1)
+ self.state.remove_transition('None')
+ self.assertEquals(len(self.state.transitions), 0)
+ self.assertRaises(statemachine.UnknownTransitionError,
+ self.state.remove_transition, 'None')
+
+ def test_make_transition(self):
+ dummy = re.compile('dummy')
+ self.assertEquals(self.state.make_transition('nop', 'bogus'),
+ (dummy, self.state.nop, 'bogus'))
+ self.assertEquals(self.state.make_transition('nop'),
+ (dummy, self.state.nop,
+ self.state.__class__.__name__))
+ self.assertRaises(statemachine.TransitionPatternNotFound,
+ self.state.make_transition, 'None')
+ self.assertRaises(statemachine.TransitionMethodNotFound,
+ self.state.make_transition, 'bogus')
+
+ def test_make_transitions(self):
+ dummy = re.compile('dummy')
+ self.assertEquals(self.state.make_transitions(('nop', ['nop2'],
+ ('nop3', 'bogus'))),
+ (['nop', 'nop2', 'nop3'],
+ {'nop': (dummy, self.state.nop,
+ self.state.__class__.__name__),
+ 'nop2': (dummy, self.state.nop2,
+ self.state.__class__.__name__),
+ 'nop3': (dummy, self.state.nop3, 'bogus')}))
+
+
+class MiscTests(unittest.TestCase):
+
+ s2l_string = "hello\tthere\thow are\tyou?\n\tI'm fine\tthanks.\n"
+ s2l_expected = ['hello there how are you?',
+ " I'm fine thanks."]
+ def test_string2lines(self):
+ self.assertEquals(statemachine.string2lines(self.s2l_string),
+ self.s2l_expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_transforms/__init__.py b/test/test_transforms/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_transforms/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_transforms/test___init__.py b/test/test_transforms/test___init__.py
new file mode 100755
index 000000000..30e60afd3
--- /dev/null
+++ b/test/test_transforms/test___init__.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for transforms/__init__.py.
+"""
+
+from __init__ import DocutilsTestSupport # must be imported before docutils
+from docutils import transforms, utils
+import unittest
+
+
+class TestTransform(transforms.Transform):
+
+ default_priority = 100
+
+ applied = 0
+
+ def apply(self, **kwargs):
+ self.applied += 1
+ assert kwargs == {'foo': 42}
+
+
+class KwargsTestCase(unittest.TestCase):
+
+ def test_kwargs(self):
+ transformer = transforms.Transformer(utils.new_document('test data'))
+ transformer.add_transform(TestTransform, foo=42)
+ transformer.apply_transforms()
+ self.assertEqual(len(transformer.applied), 1)
+ self.assertEqual(len(transformer.applied[0]), 4)
+ transform_record = transformer.applied[0]
+ self.assertEqual(transform_record[1], TestTransform)
+ self.assertEqual(transform_record[3], {'foo': 42})
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_transforms/test_class.py b/test/test_transforms/test_class.py
new file mode 100755
index 000000000..4cd874ea3
--- /dev/null
+++ b/test/test_transforms/test_class.py
@@ -0,0 +1,191 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for `docutils.transforms.misc.ClassAttribute`.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['class'] = ((), [
+["""\
+.. class:: one
+
+paragraph
+""",
+"""\
+<document source="test data">
+ <paragraph classes="one">
+ paragraph
+"""],
+["""\
+.. class:: two
+..
+
+ Block quote
+""",
+"""\
+<document source="test data">
+ <comment xml:space="preserve">
+ <block_quote classes="two">
+ <paragraph>
+ Block quote
+"""],
+["""\
+ Block quote
+
+ .. class:: three
+
+Paragraph
+""",
+"""\
+<document source="test data">
+ <block_quote>
+ <paragraph>
+ Block quote
+ <paragraph classes="three">
+ Paragraph
+"""],
+["""\
+.. class:: four
+
+Section Title
+=============
+
+Paragraph
+""",
+"""\
+<document source="test data">
+ <section classes="four" ids="section-title" names="section\ title">
+ <title>
+ Section Title
+ <paragraph>
+ Paragraph
+"""],
+["""\
+.. class:: multiple
+
+ paragraph 1
+
+ paragraph 2
+""",
+"""\
+<document source="test data">
+ <paragraph classes="multiple">
+ paragraph 1
+ <paragraph classes="multiple">
+ paragraph 2
+"""],
+["""\
+.. class:: multiple
+
+ .. Just a comment. It's silly, but possible
+""",
+"""\
+<document source="test data">
+ <comment classes="multiple" xml:space="preserve">
+ Just a comment. It's silly, but possible
+"""],
+["""\
+.. class::
+
+.. class:: 99
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Error in "class" directive:
+ 1 argument(s) required, 0 supplied.
+ <literal_block xml:space="preserve">
+ .. class::
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Invalid class attribute value for "class" directive: "99".
+ <literal_block xml:space="preserve">
+ .. class:: 99
+"""],
+["""\
+.. class:: one
+.. class:: two
+
+multiple class values may be assigned to one element
+""",
+"""\
+<document source="test data">
+ <paragraph classes="one two">
+ multiple class values may be assigned to one element
+"""],
+["""\
+.. class:: one two
+
+multiple class values may be assigned to one element
+""",
+"""\
+<document source="test data">
+ <paragraph classes="one two">
+ multiple class values may be assigned to one element
+"""],
+["""\
+.. class:: fancy
+
+2. List starts at 2.
+3. Class should apply to list, not to system message.
+""",
+"""\
+<document source="test data">
+ <enumerated_list classes="fancy" enumtype="arabic" prefix="" start="2" suffix=".">
+ <list_item>
+ <paragraph>
+ List starts at 2.
+ <list_item>
+ <paragraph>
+ Class should apply to list, not to system message.
+ <system_message level="1" line="3" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "2" (ordinal 2)
+"""],
+["""\
+2. List starts at 2.
+3. Class should apply to next paragraph, not to system message.
+
+ .. class:: fancy
+
+A paragraph.
+""",
+"""\
+<document source="test data">
+ <enumerated_list enumtype="arabic" prefix="" start="2" suffix=".">
+ <list_item>
+ <paragraph>
+ List starts at 2.
+ <list_item>
+ <paragraph>
+ Class should apply to next paragraph, not to system message.
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Enumerated list start value not ordinal-1: "2" (ordinal 2)
+ <paragraph classes="fancy">
+ A paragraph.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_contents.py b/test/test_transforms/test_contents.py
new file mode 100755
index 000000000..19705b5ba
--- /dev/null
+++ b/test/test_transforms/test_contents.py
@@ -0,0 +1,434 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for `docutils.transforms.parts.Contents` (via
+`docutils.transforms.universal.LastReaderPending`).
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import Substitutions
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['tables_of_contents'] = ((Substitutions,), [
+["""\
+.. contents::
+
+Title 1
+=======
+Paragraph 1.
+
+Title_ 2
+--------
+Paragraph 2.
+
+_`Title` 3
+``````````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-1">
+ Title 1
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-2">
+ Title
+ 2
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id3" refid="title-3">
+ Title
+ 3
+ <list_item>
+ <paragraph>
+ <reference ids="id4" refid="title-4">
+ Title 4
+ <section ids="title-1" names="title\ 1">
+ <title refid="id1">
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ <reference name="Title" refname="title">
+ Title
+ 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title refid="id3">
+ <target ids="title" names="title">
+ Title
+ 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title refid="id4">
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. contents:: Table of Contents
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-1">
+ Title 1
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-2">
+ Title 2
+ <section ids="title-1" names="title\ 1">
+ <title refid="id1">
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title refid="id2">
+ Title 2
+ <paragraph>
+ Paragraph 2.
+"""],
+["""\
+.. contents:: There's an image in Title 2
+
+Title 1
+=======
+Paragraph 1.
+
+|Title 2|
+=========
+Paragraph 2.
+
+.. |Title 2| image:: title2.png
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="there-s-an-image-in-title-2" names="there's\ an\ image\ in\ title\ 2">
+ <title>
+ There's an image in Title 2
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-1">
+ Title 1
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-2">
+ Title 2
+ <section ids="title-1" names="title\ 1">
+ <title refid="id1">
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title refid="id2">
+ <image alt="Title 2" uri="title2.png">
+ <paragraph>
+ Paragraph 2.
+ <substitution_definition names="Title\ 2">
+ <image alt="Title 2" uri="title2.png">
+"""], # emacs cruft: "
+["""\
+.. contents::
+ :depth: 2
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-1">
+ Title 1
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-2">
+ Title 2
+ <list_item>
+ <paragraph>
+ <reference ids="id3" refid="title-4">
+ Title 4
+ <section ids="title-1" names="title\ 1">
+ <title refid="id1">
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title refid="id2">
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title refid="id3">
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+Title 1
+=======
+
+.. contents::
+ :local:
+
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <topic classes="contents local" ids="contents" names="contents">
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-2">
+ Title 2
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-3">
+ Title 3
+ <list_item>
+ <paragraph>
+ <reference ids="id3" refid="title-4">
+ Title 4
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title refid="id1">
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title refid="id2">
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title refid="id3">
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. contents::
+ :local:
+
+Test duplicate name "Contents".
+
+Section
+--------
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents local" ids="contents" names="contents">
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="section">
+ Section
+ <paragraph>
+ Test duplicate name "Contents".
+ <section ids="section" names="section">
+ <title refid="id1">
+ Section
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. contents::
+ :backlinks: top
+
+Section
+--------
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="section">
+ Section
+ <section ids="section" names="section">
+ <title refid="contents">
+ Section
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. contents::
+ :backlinks: none
+
+Section
+--------
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="section">
+ Section
+ <section ids="section" names="section">
+ <title>
+ Section
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+.. contents::
+
+Degenerate case, no table of contents generated.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Degenerate case, no table of contents generated.
+"""],
+["""\
+Title 1
+=======
+
+Paragraph 1.
+
+.. sidebar:: Contents
+
+ .. contents::
+ :local:
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+""",
+"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title>
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <sidebar>
+ <title>
+ Contents
+ <topic classes="contents local" ids="contents" names="contents">
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-2">
+ Title 2
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-3">
+ Title 3
+ <section ids="title-2" names="title\ 2">
+ <title refid="id1">
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title refid="id2">
+ Title 3
+ <paragraph>
+ Paragraph 3.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_docinfo.py b/test/test_transforms/test_docinfo.py
new file mode 100755
index 000000000..994d034ea
--- /dev/null
+++ b/test/test_transforms/test_docinfo.py
@@ -0,0 +1,334 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.frontmatter.DocInfo.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.frontmatter import DocInfo
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['bibliographic_field_lists'] = ((DocInfo,), [
+["""\
+.. Bibliographic element extraction.
+
+:Abstract:
+ There can only be one abstract.
+
+ It is automatically moved to the end of the other bibliographic elements.
+
+:Author: Me
+:Version: 1
+:Date: 2001-08-11
+:Parameter i: integer
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <author>
+ Me
+ <version>
+ 1
+ <date>
+ 2001-08-11
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ integer
+ <topic classes="abstract">
+ <title>
+ Abstract
+ <paragraph>
+ There can only be one abstract.
+ <paragraph>
+ It is automatically moved to the end of the other bibliographic elements.
+ <comment xml:space="preserve">
+ Bibliographic element extraction.
+"""],
+["""\
+.. Bibliographic element extraction.
+
+:Abstract: Abstract 1.
+:Author: Me
+:Address: 123 My Street
+ Example, EX
+:Contact: me@my.org
+:Version: 1
+:Abstract: Abstract 2 (should generate a warning).
+:Date: 2001-08-11
+:Parameter i: integer
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <author>
+ Me
+ <address xml:space="preserve">
+ 123 My Street
+ Example, EX
+ <contact>
+ <reference refuri="mailto:me@my.org">
+ me@my.org
+ <version>
+ 1
+ <field>
+ <field_name>
+ Abstract
+ <field_body>
+ <paragraph>
+ Abstract 2 (should generate a warning).
+ <system_message level="2" line="9" source="test data" type="WARNING">
+ <paragraph>
+ There can only be one "Abstract" field.
+ <date>
+ 2001-08-11
+ <field>
+ <field_name>
+ Parameter i
+ <field_body>
+ <paragraph>
+ integer
+ <topic classes="abstract">
+ <title>
+ Abstract
+ <paragraph>
+ Abstract 1.
+ <comment xml:space="preserve">
+ Bibliographic element extraction.
+"""],
+["""\
+:Author: - must be a paragraph
+:Status: a *simple* paragraph
+:Date: But only one
+
+ paragraph.
+:Version:
+
+.. and not empty either
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <field>
+ <field_name>
+ Author
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ must be a paragraph
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Cannot extract bibliographic field "Author" containing anything other than a single paragraph.
+ <status>
+ a \n\
+ <emphasis>
+ simple
+ paragraph
+ <field>
+ <field_name>
+ Date
+ <field_body>
+ <paragraph>
+ But only one
+ <paragraph>
+ paragraph.
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Cannot extract compound bibliographic field "Date".
+ <field>
+ <field_name>
+ Version
+ <field_body>
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Cannot extract empty bibliographic field "Version".
+ <comment xml:space="preserve">
+ and not empty either
+"""],
+["""\
+:Authors: Me, Myself, **I**
+:Authors: PacMan; Ms. PacMan; PacMan, Jr.
+:Authors:
+ Here
+
+ There
+
+ *Everywhere*
+:Authors: - First
+ - Second
+ - Third
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <authors>
+ <author>
+ Me
+ <author>
+ Myself
+ <author>
+ I
+ <authors>
+ <author>
+ PacMan
+ <author>
+ Ms. PacMan
+ <author>
+ PacMan, Jr.
+ <authors>
+ <author>
+ Here
+ <author>
+ There
+ <author>
+ <emphasis>
+ Everywhere
+ <authors>
+ <author>
+ First
+ <author>
+ Second
+ <author>
+ Third
+"""],
+["""\
+:Authors: Only One
+:Authors: One, Only;
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <authors>
+ <author>
+ Only One
+ <authors>
+ <author>
+ One, Only
+"""],
+["""\
+:Authors:
+
+:Authors: 1. One
+ 2. Two
+
+:Authors:
+ -
+ -
+
+:Authors:
+ - One
+
+ Two
+
+:Authors:
+ - One
+
+ Two
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Cannot extract empty bibliographic field "Authors".
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <enumerated_list enumtype="arabic" prefix="" suffix=".">
+ <list_item>
+ <paragraph>
+ One
+ <list_item>
+ <paragraph>
+ Two
+ <system_message level="2" line="3" source="test data" type="WARNING">
+ <paragraph>
+ Bibliographic field "Authors" incompatible with extraction: it must contain either a single paragraph (with authors separated by one of ";,"), multiple paragraphs (one per author), or a bullet list with one paragraph (one author) per item.
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <list_item>
+ <system_message level="2" line="6" source="test data" type="WARNING">
+ <paragraph>
+ Bibliographic field "Authors" incompatible with extraction: it must contain either a single paragraph (with authors separated by one of ";,"), multiple paragraphs (one per author), or a bullet list with one paragraph (one author) per item.
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ One
+ <paragraph>
+ Two
+ <system_message level="2" line="10" source="test data" type="WARNING">
+ <paragraph>
+ Bibliographic field "Authors" incompatible with extraction: it must contain either a single paragraph (with authors separated by one of ";,"), multiple paragraphs (one per author), or a bullet list with one paragraph (one author) per item.
+ <field>
+ <field_name>
+ Authors
+ <field_body>
+ <bullet_list bullet="-">
+ <list_item>
+ <paragraph>
+ One
+ <paragraph>
+ Two
+ <system_message level="2" line="15" source="test data" type="WARNING">
+ <paragraph>
+ Bibliographic field "Authors" incompatible with extraction: it must contain either a single paragraph (with authors separated by one of ";,"), multiple paragraphs (one per author), or a bullet list with one paragraph (one author) per item.
+"""],
+["""\
+.. RCS keyword extraction.
+
+:Status: (some text) $""" + """RCSfile: test_docinfo.py,v $ (more text)
+:Date: (some text) $""" + """Date: 2002/10/08 01:34:23 $ (more text)
+:Date: (some text) $""" + """Date: 2005-03-26T16:21:28.693201Z $ (more text)
+:Version: (some text) $""" + """Revision: 1.1 $ (more text)
+""",
+"""\
+<document source="test data">
+ <docinfo>
+ <status>
+ (some text) test_docinfo.py (more text)
+ <date>
+ (some text) 2002-10-08 (more text)
+ <date>
+ (some text) 2005-03-26 (more text)
+ <version>
+ (some text) 1.1 (more text)
+ <comment xml:space="preserve">
+ RCS keyword extraction.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_doctitle.py b/test/test_transforms/test_doctitle.py
new file mode 100755
index 000000000..3000f53a5
--- /dev/null
+++ b/test/test_transforms/test_doctitle.py
@@ -0,0 +1,231 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.frontmatter.DocTitle.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.frontmatter import DocTitle, SectionSubTitle
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['section_headers'] = ((DocTitle, SectionSubTitle), [
+["""\
+.. test title promotion
+
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document ids="title" names="title" source="test data" title="Title">
+ <title>
+ Title
+ <comment xml:space="preserve">
+ test title promotion
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Title
+=====
+Paragraph (no blank line).
+""",
+"""\
+<document ids="title" names="title" source="test data" title="Title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph (no blank line).
+"""],
+["""\
+Paragraph.
+
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Paragraph.
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+Title
+=====
+
+Subtitle
+--------
+
+.. title:: Another Title
+
+Test title, subtitle, and title metadata.
+""",
+"""\
+<document ids="title" names="title" source="test data" title="Another Title">
+ <title>
+ Title
+ <subtitle ids="subtitle" names="subtitle">
+ Subtitle
+ <paragraph>
+ Test title, subtitle, and title metadata.
+"""],
+["""\
+Title
+====
+
+Test short underline.
+""",
+"""\
+<document ids="title" names="title" source="test data" title="Title">
+ <title>
+ Title
+ <system_message level="2" line="2" source="test data" type="WARNING">
+ <paragraph>
+ Title underline too short.
+ <literal_block xml:space="preserve">
+ Title
+ ====
+ <paragraph>
+ Test short underline.
+"""],
+["""\
+=======
+ Long Title
+=======
+
+Test long title and space normalization.
+The system_message should move after the document title
+(it was before the beginning of the section).
+""",
+"""\
+<document ids="long-title" names="long\ title" source="test data" title="Long Title">
+ <title>
+ Long Title
+ <system_message level="2" line="1" source="test data" type="WARNING">
+ <paragraph>
+ Title overline too short.
+ <literal_block xml:space="preserve">
+ =======
+ Long Title
+ =======
+ <paragraph>
+ Test long title and space normalization.
+ The system_message should move after the document title
+ (it was before the beginning of the section).
+"""],
+["""\
+.. Test multiple second-level titles.
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+-------
+Paragraph 3.
+""",
+"""\
+<document ids="title-1" names="title\ 1" source="test data" title="Title 1">
+ <title>
+ Title 1
+ <comment xml:space="preserve">
+ Test multiple second-level titles.
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title>
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+"""],
+["""\
+.. |foo| replace:: bar
+
+.. _invisible target:
+
+Title
+=====
+This title should be the document title despite the
+substitution_definition.
+""",
+"""\
+<document ids="title" names="title" source="test data" title="Title">
+ <title>
+ Title
+ <substitution_definition names="foo">
+ bar
+ <target ids="invisible-target" names="invisible\ target">
+ <paragraph>
+ This title should be the document title despite the
+ substitution_definition.
+"""],
+["""\
+(Because of this paragraph, the following is not a doc title.)
+
+===============
+ Section Title
+===============
+
+Subtitle
+========
+
+-----------------
+ Another Section
+-----------------
+
+Another Subtitle
+----------------
+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ (Because of this paragraph, the following is not a doc title.)
+ <section ids="section-title" names="section\ title">
+ <title>
+ Section Title
+ <subtitle ids="subtitle" names="subtitle">
+ Subtitle
+ <section ids="another-section" names="another\ section">
+ <title>
+ Another Section
+ <subtitle ids="another-subtitle" names="another\ subtitle">
+ Another Subtitle
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_expose_internals.py b/test/test_transforms/test_expose_internals.py
new file mode 100755
index 000000000..69193246a
--- /dev/null
+++ b/test/test_transforms/test_expose_internals.py
@@ -0,0 +1,42 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for universal.ExposeInternals transform.
+"""
+
+
+from __init__ import DocutilsTestSupport # must be imported before docutils
+from docutils.transforms.universal import ExposeInternals
+from docutils.parsers.rst import Parser
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(
+ parser, suite_settings={'expose_internals': ['rawsource', 'source']})
+ s.generateTests(totest)
+ return s
+
+
+totest = {}
+
+totest['transitions'] = ((ExposeInternals,), [
+["""\
+This is a test.
+""",
+"""\
+<document internal:rawsource="" source="test data">
+ <paragraph internal:rawsource="This is a test." internal:source="test data">
+ This is a test.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_filter.py b/test/test_transforms/test_filter.py
new file mode 100755
index 000000000..009600d81
--- /dev/null
+++ b/test/test_transforms/test_filter.py
@@ -0,0 +1,41 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.components.Filter.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['meta'] = ((), [
+["""\
+.. meta::
+ :description: The reStructuredText plaintext markup language
+ :keywords: plaintext,markup language
+""",
+"""\
+<document source="test data">
+ <meta content="The reStructuredText plaintext markup language" name="description">
+ <meta content="plaintext,markup language" name="keywords">
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_footnotes.py b/test/test_transforms/test_footnotes.py
new file mode 100755
index 000000000..86cbd2110
--- /dev/null
+++ b/test/test_transforms/test_footnotes.py
@@ -0,0 +1,545 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.references.Footnotes.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import Footnotes
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['footnotes'] = ((Footnotes,), [
+["""\
+[#autolabel]_
+
+.. [#autolabel] text
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refid="autolabel">
+ 1
+ <footnote auto="1" backrefs="id1" ids="autolabel" names="autolabel">
+ <label>
+ 1
+ <paragraph>
+ text
+"""],
+["""\
+autonumber: [#]_
+
+.. [#] text
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ autonumber: \n\
+ <footnote_reference auto="1" ids="id1" refid="id2">
+ 1
+ <footnote auto="1" backrefs="id1" ids="id2" names="1">
+ <label>
+ 1
+ <paragraph>
+ text
+"""],
+["""\
+[#]_ is the first auto-numbered footnote reference.
+[#]_ is the second auto-numbered footnote reference.
+
+.. [#] Auto-numbered footnote 1.
+.. [#] Auto-numbered footnote 2.
+.. [#] Auto-numbered footnote 3.
+
+[#]_ is the third auto-numbered footnote reference.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refid="id3">
+ 1
+ is the first auto-numbered footnote reference.
+ <footnote_reference auto="1" ids="id2" refid="id4">
+ 2
+ is the second auto-numbered footnote reference.
+ <footnote auto="1" backrefs="id1" ids="id3" names="1">
+ <label>
+ 1
+ <paragraph>
+ Auto-numbered footnote 1.
+ <footnote auto="1" backrefs="id2" ids="id4" names="2">
+ <label>
+ 2
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" backrefs="id6" ids="id5" names="3">
+ <label>
+ 3
+ <paragraph>
+ Auto-numbered footnote 3.
+ <paragraph>
+ <footnote_reference auto="1" ids="id6" refid="id5">
+ 3
+ is the third auto-numbered footnote reference.
+"""],
+["""\
+[#third]_ is a reference to the third auto-numbered footnote.
+
+.. [#first] First auto-numbered footnote.
+.. [#second] Second auto-numbered footnote.
+.. [#third] Third auto-numbered footnote.
+
+[#second]_ is a reference to the second auto-numbered footnote.
+[#first]_ is a reference to the first auto-numbered footnote.
+[#third]_ is another reference to the third auto-numbered footnote.
+
+Here are some internal cross-references to the implicit targets
+generated by the footnotes: first_, second_, third_.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refid="third">
+ 3
+ is a reference to the third auto-numbered footnote.
+ <footnote auto="1" backrefs="id3" ids="first" names="first">
+ <label>
+ 1
+ <paragraph>
+ First auto-numbered footnote.
+ <footnote auto="1" backrefs="id2" ids="second" names="second">
+ <label>
+ 2
+ <paragraph>
+ Second auto-numbered footnote.
+ <footnote auto="1" backrefs="id1 id4" ids="third" names="third">
+ <label>
+ 3
+ <paragraph>
+ Third auto-numbered footnote.
+ <paragraph>
+ <footnote_reference auto="1" ids="id2" refid="second">
+ 2
+ is a reference to the second auto-numbered footnote.
+ <footnote_reference auto="1" ids="id3" refid="first">
+ 1
+ is a reference to the first auto-numbered footnote.
+ <footnote_reference auto="1" ids="id4" refid="third">
+ 3
+ is another reference to the third auto-numbered footnote.
+ <paragraph>
+ Here are some internal cross-references to the implicit targets
+ generated by the footnotes: \n\
+ <reference name="first" refname="first">
+ first
+ , \n\
+ <reference name="second" refname="second">
+ second
+ , \n\
+ <reference name="third" refname="third">
+ third
+ .
+"""],
+["""\
+Mixed anonymous and labelled auto-numbered footnotes:
+
+[#four]_ should be 4, [#]_ should be 1,
+[#]_ should be 3, [#]_ is one too many,
+[#two]_ should be 2, and [#six]_ doesn't exist.
+
+.. [#] Auto-numbered footnote 1.
+.. [#two] Auto-numbered footnote 2.
+.. [#] Auto-numbered footnote 3.
+.. [#four] Auto-numbered footnote 4.
+.. [#five] Auto-numbered footnote 5.
+.. [#five] Auto-numbered footnote 5 again (duplicate).
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed anonymous and labelled auto-numbered footnotes:
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refid="four">
+ 4
+ should be 4, \n\
+ <footnote_reference auto="1" ids="id2" refid="id7">
+ 1
+ should be 1,
+ <footnote_reference auto="1" ids="id3" refid="id8">
+ 3
+ should be 3, \n\
+ <problematic ids="id11 id4" refid="id10">
+ [#]_
+ is one too many,
+ <footnote_reference auto="1" ids="id5" refid="two">
+ 2
+ should be 2, and \n\
+ <footnote_reference auto="1" ids="id6" refname="six">
+ doesn't exist.
+ <footnote auto="1" backrefs="id2" ids="id7" names="1">
+ <label>
+ 1
+ <paragraph>
+ Auto-numbered footnote 1.
+ <footnote auto="1" backrefs="id5" ids="two" names="two">
+ <label>
+ 2
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" backrefs="id3" ids="id8" names="3">
+ <label>
+ 3
+ <paragraph>
+ Auto-numbered footnote 3.
+ <footnote auto="1" backrefs="id1" ids="four" names="four">
+ <label>
+ 4
+ <paragraph>
+ Auto-numbered footnote 4.
+ <footnote auto="1" dupnames="five" ids="five">
+ <label>
+ 5
+ <paragraph>
+ Auto-numbered footnote 5.
+ <footnote auto="1" dupnames="five" ids="id9">
+ <label>
+ 6
+ <system_message backrefs="id9" level="2" line="12" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "five".
+ <paragraph>
+ Auto-numbered footnote 5 again (duplicate).
+ <system_message backrefs="id11" ids="id10" level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Too many autonumbered footnote references: only 2 corresponding footnotes available.
+"""],
+["""\
+Mixed auto-numbered and manual footnotes:
+
+.. [1] manually numbered
+.. [#] auto-numbered
+.. [#label] autonumber-labeled
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed auto-numbered and manual footnotes:
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ manually numbered
+ <footnote auto="1" ids="id2" names="2">
+ <label>
+ 2
+ <paragraph>
+ auto-numbered
+ <footnote auto="1" ids="label" names="label">
+ <label>
+ 3
+ <paragraph>
+ autonumber-labeled
+"""],
+["""\
+A labeled autonumbered footnote referece: [#footnote]_.
+
+An unlabeled autonumbered footnote referece: [#]_.
+
+.. [#] Unlabeled autonumbered footnote.
+.. [#footnote] Labeled autonumbered footnote.
+ Note that the footnotes are not in the same
+ order as the references.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A labeled autonumbered footnote referece: \n\
+ <footnote_reference auto="1" ids="id1" refid="footnote">
+ 2
+ .
+ <paragraph>
+ An unlabeled autonumbered footnote referece: \n\
+ <footnote_reference auto="1" ids="id2" refid="id3">
+ 1
+ .
+ <footnote auto="1" backrefs="id2" ids="id3" names="1">
+ <label>
+ 1
+ <paragraph>
+ Unlabeled autonumbered footnote.
+ <footnote auto="1" backrefs="id1" ids="footnote" names="footnote">
+ <label>
+ 2
+ <paragraph>
+ Labeled autonumbered footnote.
+ Note that the footnotes are not in the same
+ order as the references.
+"""],
+["""\
+Mixed manually-numbered, anonymous auto-numbered,
+and labelled auto-numbered footnotes:
+
+[#four]_ should be 4, [#]_ should be 2,
+[1]_ is 1, [3]_ is 3,
+[#]_ should be 6, [#]_ is one too many,
+[#five]_ should be 5, and [#eight]_ doesn't exist.
+
+.. [1] Manually-numbered footnote 1.
+.. [#] Auto-numbered footnote 2.
+.. [#four] Auto-numbered footnote 4.
+.. [3] Manually-numbered footnote 3
+.. [#five] Auto-numbered footnote 5.
+.. [#] Auto-numbered footnote 6.
+.. [#five] Auto-numbered footnote 5 again (duplicate).
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Mixed manually-numbered, anonymous auto-numbered,
+ and labelled auto-numbered footnotes:
+ <paragraph>
+ <footnote_reference auto="1" ids="id1" refid="four">
+ 4
+ should be 4, \n\
+ <footnote_reference auto="1" ids="id2" refid="id10">
+ 2
+ should be 2,
+ <footnote_reference ids="id3" refid="id9">
+ 1
+ is 1, \n\
+ <footnote_reference ids="id4" refid="id11">
+ 3
+ is 3,
+ <footnote_reference auto="1" ids="id5" refid="id12">
+ 6
+ should be 6, \n\
+ <problematic ids="id15 id6" refid="id14">
+ [#]_
+ is one too many,
+ <footnote_reference auto="1" ids="id7" refname="five">
+ should be 5, and \n\
+ <footnote_reference auto="1" ids="id8" refname="eight">
+ doesn't exist.
+ <footnote backrefs="id3" ids="id9" names="1">
+ <label>
+ 1
+ <paragraph>
+ Manually-numbered footnote 1.
+ <footnote auto="1" backrefs="id2" ids="id10" names="2">
+ <label>
+ 2
+ <paragraph>
+ Auto-numbered footnote 2.
+ <footnote auto="1" backrefs="id1" ids="four" names="four">
+ <label>
+ 4
+ <paragraph>
+ Auto-numbered footnote 4.
+ <footnote backrefs="id4" ids="id11" names="3">
+ <label>
+ 3
+ <paragraph>
+ Manually-numbered footnote 3
+ <footnote auto="1" dupnames="five" ids="five">
+ <label>
+ 5
+ <paragraph>
+ Auto-numbered footnote 5.
+ <footnote auto="1" backrefs="id5" ids="id12" names="6">
+ <label>
+ 6
+ <paragraph>
+ Auto-numbered footnote 6.
+ <footnote auto="1" dupnames="five" ids="id13">
+ <label>
+ 7
+ <system_message backrefs="id13" level="2" line="15" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "five".
+ <paragraph>
+ Auto-numbered footnote 5 again (duplicate).
+ <system_message backrefs="id15" ids="id14" level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Too many autonumbered footnote references: only 2 corresponding footnotes available.
+"""],
+["""\
+Referencing a footnote by symbol [*]_.
+
+.. [*] This is an auto-symbol footnote.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Referencing a footnote by symbol \n\
+ <footnote_reference auto="*" ids="id1" refid="id2">
+ *
+ .
+ <footnote auto="*" backrefs="id1" ids="id2">
+ <label>
+ *
+ <paragraph>
+ This is an auto-symbol footnote.
+"""],
+["""\
+A sequence of symbol footnote references:
+[*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_ [*]_.
+
+.. [*] Auto-symbol footnote 1.
+.. [*] Auto-symbol footnote 2.
+.. [*] Auto-symbol footnote 3.
+.. [*] Auto-symbol footnote 4.
+.. [*] Auto-symbol footnote 5.
+.. [*] Auto-symbol footnote 6.
+.. [*] Auto-symbol footnote 7.
+.. [*] Auto-symbol footnote 8.
+.. [*] Auto-symbol footnote 9.
+.. [*] Auto-symbol footnote 10.
+.. [*] Auto-symbol footnote 11.
+.. [*] Auto-symbol footnote 12.
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ A sequence of symbol footnote references:
+ <footnote_reference auto="*" ids="id1" refid="id13">
+ *
+ \n\
+ <footnote_reference auto="*" ids="id2" refid="id14">
+ \u2020
+ \n\
+ <footnote_reference auto="*" ids="id3" refid="id15">
+ \u2021
+ \n\
+ <footnote_reference auto="*" ids="id4" refid="id16">
+ \u00A7
+ \n\
+ <footnote_reference auto="*" ids="id5" refid="id17">
+ \u00B6
+ \n\
+ <footnote_reference auto="*" ids="id6" refid="id18">
+ #
+ \n\
+ <footnote_reference auto="*" ids="id7" refid="id19">
+ \u2660
+ \n\
+ <footnote_reference auto="*" ids="id8" refid="id20">
+ \u2665
+ \n\
+ <footnote_reference auto="*" ids="id9" refid="id21">
+ \u2666
+ \n\
+ <footnote_reference auto="*" ids="id10" refid="id22">
+ \u2663
+ \n\
+ <footnote_reference auto="*" ids="id11" refid="id23">
+ **
+ \n\
+ <footnote_reference auto="*" ids="id12" refid="id24">
+ \u2020\u2020
+ .
+ <footnote auto="*" backrefs="id1" ids="id13">
+ <label>
+ *
+ <paragraph>
+ Auto-symbol footnote 1.
+ <footnote auto="*" backrefs="id2" ids="id14">
+ <label>
+ \u2020
+ <paragraph>
+ Auto-symbol footnote 2.
+ <footnote auto="*" backrefs="id3" ids="id15">
+ <label>
+ \u2021
+ <paragraph>
+ Auto-symbol footnote 3.
+ <footnote auto="*" backrefs="id4" ids="id16">
+ <label>
+ \u00A7
+ <paragraph>
+ Auto-symbol footnote 4.
+ <footnote auto="*" backrefs="id5" ids="id17">
+ <label>
+ \u00B6
+ <paragraph>
+ Auto-symbol footnote 5.
+ <footnote auto="*" backrefs="id6" ids="id18">
+ <label>
+ #
+ <paragraph>
+ Auto-symbol footnote 6.
+ <footnote auto="*" backrefs="id7" ids="id19">
+ <label>
+ \u2660
+ <paragraph>
+ Auto-symbol footnote 7.
+ <footnote auto="*" backrefs="id8" ids="id20">
+ <label>
+ \u2665
+ <paragraph>
+ Auto-symbol footnote 8.
+ <footnote auto="*" backrefs="id9" ids="id21">
+ <label>
+ \u2666
+ <paragraph>
+ Auto-symbol footnote 9.
+ <footnote auto="*" backrefs="id10" ids="id22">
+ <label>
+ \u2663
+ <paragraph>
+ Auto-symbol footnote 10.
+ <footnote auto="*" backrefs="id11" ids="id23">
+ <label>
+ **
+ <paragraph>
+ Auto-symbol footnote 11.
+ <footnote auto="*" backrefs="id12" ids="id24">
+ <label>
+ \u2020\u2020
+ <paragraph>
+ Auto-symbol footnote 12.
+"""],
+["""\
+Duplicate manual footnote labels:
+
+.. [1] Footnote.
+
+.. [1] Footnote.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate manual footnote labels:
+ <footnote dupnames="1" ids="id1">
+ <label>
+ 1
+ <paragraph>
+ Footnote.
+ <footnote dupnames="1" ids="id2">
+ <label>
+ 1
+ <system_message backrefs="id2" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "1".
+ <paragraph>
+ Footnote.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_hyperlinks.py b/test/test_transforms/test_hyperlinks.py
new file mode 100755
index 000000000..cef12a4f1
--- /dev/null
+++ b/test/test_transforms/test_hyperlinks.py
@@ -0,0 +1,845 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.references.Hyperlinks.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import PropagateTargets, \
+ AnonymousHyperlinks, IndirectHyperlinks, ExternalTargets, \
+ InternalTargets, DanglingReferences
+
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+# Exhaustive listing of hyperlink variations: every combination of
+# target/reference, direct/indirect, internal/external, and named/anonymous,
+# plus embedded URIs.
+totest['exhaustive_hyperlinks'] = ((PropagateTargets, AnonymousHyperlinks,
+ IndirectHyperlinks,
+ ExternalTargets, InternalTargets,
+ DanglingReferences), [
+["""\
+direct_ external
+
+.. _direct: http://direct
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="direct" refuri="http://direct">
+ direct
+ external
+ <target ids="direct" names="direct" refuri="http://direct">
+"""],
+["""\
+indirect_ external
+
+.. _indirect: xtarget_
+.. _xtarget: http://indirect
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="indirect" refuri="http://indirect">
+ indirect
+ external
+ <target ids="indirect" names="indirect" refuri="http://indirect">
+ <target ids="xtarget" names="xtarget" refuri="http://indirect">
+"""],
+["""\
+.. _direct:
+
+direct_ internal
+""",
+"""\
+<document source="test data">
+ <target refid="direct">
+ <paragraph ids="direct" names="direct">
+ <reference name="direct" refid="direct">
+ direct
+ internal
+"""],
+["""\
+.. _ztarget:
+
+indirect_ internal
+
+.. _indirect2: ztarget_
+.. _indirect: indirect2_
+""",
+"""\
+<document source="test data">
+ <target refid="ztarget">
+ <paragraph ids="ztarget" names="ztarget">
+ <reference name="indirect" refid="ztarget">
+ indirect
+ internal
+ <target ids="indirect2" names="indirect2" refid="ztarget">
+ <target ids="indirect" names="indirect" refid="ztarget">
+"""],
+["""\
+Implicit
+--------
+
+indirect_ internal
+
+.. _indirect: implicit_
+""",
+"""\
+<document source="test data">
+ <section ids="implicit" names="implicit">
+ <title>
+ Implicit
+ <paragraph>
+ <reference name="indirect" refid="implicit">
+ indirect
+ internal
+ <target ids="indirect" names="indirect" refid="implicit">
+"""],
+["""\
+Implicit
+--------
+
+`multiply-indirect`_ internal
+
+.. _multiply-indirect: indirect_
+.. _indirect: implicit_
+""",
+"""\
+<document source="test data">
+ <section ids="implicit" names="implicit">
+ <title>
+ Implicit
+ <paragraph>
+ <reference name="multiply-indirect" refid="implicit">
+ multiply-indirect
+ internal
+ <target ids="multiply-indirect" names="multiply-indirect" refid="implicit">
+ <target ids="indirect" names="indirect" refid="implicit">
+"""],
+["""\
+circular_ indirect reference
+
+.. _circular: indirect_
+.. _indirect: circular_
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id2" refid="id1">
+ circular_
+ indirect reference
+ <target ids="circular" names="circular" refid="circular">
+ <problematic ids="id3 indirect" names="indirect" refid="id1">
+ .. _indirect: circular_
+ <system_message backrefs="id2 id3" ids="id1" level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Indirect hyperlink target "circular" (id="circular") refers to target "indirect", forming a circular reference.
+"""],
+["""\
+Implicit
+--------
+
+Duplicate implicit targets.
+
+Implicit
+--------
+
+indirect_ internal
+
+.. _indirect: implicit_
+
+Direct internal reference: Implicit_
+""",
+"""\
+<document source="test data">
+ <section dupnames="implicit" ids="implicit">
+ <title>
+ Implicit
+ <paragraph>
+ Duplicate implicit targets.
+ <section dupnames="implicit" ids="id1">
+ <title>
+ Implicit
+ <system_message backrefs="id1" level="1" line="7" source="test data" type="INFO">
+ <paragraph>
+ Duplicate implicit target name: "implicit".
+ <paragraph>
+ <problematic ids="id3" refid="id2">
+ indirect_
+ internal
+ <target ids="indirect" names="indirect" refname="implicit">
+ <paragraph>
+ Direct internal reference:
+ <problematic ids="id5" refid="id4">
+ Implicit_
+ <system_message backrefs="id3" ids="id2" level="3" line="11" source="test data" type="ERROR">
+ <paragraph>
+ Indirect hyperlink target "indirect" (id="indirect") refers to target "implicit", which is a duplicate, and cannot be used as a unique reference.
+ <system_message backrefs="id5" ids="id4" level="3" line="13" source="test data" type="ERROR">
+ <paragraph>
+ Duplicate target name, cannot be used as a unique reference: "implicit".
+"""],
+["""\
+`direct external`__
+
+__ http://direct
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="direct external" refuri="http://direct">
+ direct external
+ <target anonymous="1" ids="id1" refuri="http://direct">
+"""],
+["""\
+`indirect external`__
+
+__ xtarget_
+.. _xtarget: http://indirect
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference anonymous="1" name="indirect external" refuri="http://indirect">
+ indirect external
+ <target anonymous="1" ids="id1" refuri="http://indirect">
+ <target ids="xtarget" names="xtarget" refuri="http://indirect">
+"""],
+["""\
+__
+
+`direct internal`__
+""",
+"""\
+<document source="test data">
+ <target anonymous="1" refid="id1">
+ <paragraph ids="id1">
+ <reference anonymous="1" name="direct internal" refid="id1">
+ direct internal
+"""],
+["""\
+.. _ztarget:
+
+`indirect internal`__
+
+__ ztarget_
+""",
+"""\
+<document source="test data">
+ <target refid="ztarget">
+ <paragraph ids="ztarget" names="ztarget">
+ <reference anonymous="1" name="indirect internal" refid="ztarget">
+ indirect internal
+ <target anonymous="1" ids="id1" refid="ztarget">
+"""],
+["""\
+.. _ztarget:
+
+First
+
+.. _ztarget:
+
+Second
+
+`indirect internal`__
+
+__ ztarget_
+""",
+"""\
+<document source="test data">
+ <target dupnames="ztarget" refid="ztarget">
+ <paragraph ids="ztarget">
+ First
+ <system_message backrefs="id1" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "ztarget".
+ <target dupnames="ztarget" refid="id1">
+ <paragraph ids="id1">
+ Second
+ <paragraph>
+ <problematic ids="id4" refid="id3">
+ `indirect internal`__
+ <target anonymous="1" ids="id2" refname="ztarget">
+ <system_message backrefs="id4" ids="id3" level="3" line="11" source="test data" type="ERROR">
+ <paragraph>
+ Indirect hyperlink target (id="id2") refers to target "ztarget", which is a duplicate, and cannot be used as a unique reference.
+"""],
+["""\
+The next anonymous hyperlink reference is parsed (and discarded) at
+some point, but nonetheless anonymous hyperlink references and targets
+match in this snippet.
+
+.. |invalid| replace:: anonymous__
+
+hyperlink__
+
+__ URL
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ The next anonymous hyperlink reference is parsed (and discarded) at
+ some point, but nonetheless anonymous hyperlink references and targets
+ match in this snippet.
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Substitution definition contains illegal element:
+ <literal_block xml:space="preserve">
+ <reference anonymous="1" name="anonymous">
+ anonymous
+ <literal_block xml:space="preserve">
+ .. |invalid| replace:: anonymous__
+ <paragraph>
+ <reference anonymous="1" name="hyperlink" refuri="URL">
+ hyperlink
+ <target anonymous="1" ids="id1" refuri="URL">
+"""],
+["""\
+An `embedded uri <http://direct>`_.
+
+Another reference to the same `embedded URI`_.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ An \n\
+ <reference name="embedded uri" refuri="http://direct">
+ embedded uri
+ <target ids="embedded-uri" names="embedded\ uri" refuri="http://direct">
+ .
+ <paragraph>
+ Another reference to the same \n\
+ <reference name="embedded URI" refuri="http://direct">
+ embedded URI
+ .
+"""],
+["""\
+An `anonymous embedded uri <http://direct>`__.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ An \n\
+ <reference name="anonymous embedded uri" refuri="http://direct">
+ anonymous embedded uri
+ .
+"""],
+["""\
+.. _target:
+
+.. [1] Footnote; target_
+""",
+"""\
+<document source="test data">
+ <target ids="target" names="target">
+ <footnote ids="id1" names="1">
+ <label>
+ 1
+ <paragraph>
+ Footnote; \n\
+ <reference name="target" refid="target">
+ target
+"""],
+["""\
+.. _target:
+
+.. [cit] Citation; target_
+""",
+"""\
+<document source="test data">
+ <target ids="target" names="target">
+ <citation ids="cit" names="cit">
+ <label>
+ cit
+ <paragraph>
+ Citation; \n\
+ <reference name="target" refid="target">
+ target
+"""],
+])
+
+totest['hyperlinks'] = ((PropagateTargets, AnonymousHyperlinks,
+ IndirectHyperlinks, ExternalTargets,
+ InternalTargets, DanglingReferences), [
+["""\
+.. _internal hyperlink:
+
+This paragraph referenced.
+
+By this `internal hyperlink`_ reference.
+""",
+"""\
+<document source="test data">
+ <target refid="internal-hyperlink">
+ <paragraph ids="internal-hyperlink" names="internal\ hyperlink">
+ This paragraph referenced.
+ <paragraph>
+ By this \n\
+ <reference name="internal hyperlink" refid="internal-hyperlink">
+ internal hyperlink
+ reference.
+"""],
+["""\
+.. _chained:
+.. _internal hyperlink:
+
+This paragraph referenced.
+
+By this `internal hyperlink`_ reference
+as well as by this chained_ reference.
+
+The results of the transform are not visible at the XML level.
+""",
+"""\
+<document source="test data">
+ <target refid="chained">
+ <target refid="internal-hyperlink">
+ <paragraph ids="internal-hyperlink chained" names="internal\ hyperlink chained">
+ This paragraph referenced.
+ <paragraph>
+ By this \n\
+ <reference name="internal hyperlink" refid="internal-hyperlink">
+ internal hyperlink
+ reference
+ as well as by this \n\
+ <reference name="chained" refid="chained">
+ chained
+ reference.
+ <paragraph>
+ The results of the transform are not visible at the XML level.
+"""],
+["""\
+.. _chained:
+__ http://anonymous
+
+Anonymous__ and chained_ both refer to the same URI.
+""",
+"""\
+<document source="test data">
+ <target refid="chained">
+ <target anonymous="1" ids="id1 chained" names="chained" refuri="http://anonymous">
+ <paragraph>
+ <reference anonymous="1" name="Anonymous" refuri="http://anonymous">
+ Anonymous
+ and \n\
+ <reference name="chained" refuri="http://anonymous">
+ chained
+ both refer to the same URI.
+"""],
+["""\
+.. _a:
+.. _b:
+
+x
+""",
+"""\
+<document source="test data">
+ <target refid="a">
+ <target refid="b">
+ <paragraph ids="b a" names="b a">
+ x
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Hyperlink target "a" is not referenced.
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Hyperlink target "b" is not referenced.
+"""],
+["""\
+.. _a:
+.. _b:
+
+a_
+""",
+"""\
+<document source="test data">
+ <target refid="a">
+ <target refid="b">
+ <paragraph ids="b a" names="b a">
+ <reference name="a" refid="a">
+ a
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Hyperlink target "b" is not referenced.
+"""],
+["""\
+.. _a:
+.. _b:
+
+b_
+""",
+"""\
+<document source="test data">
+ <target refid="a">
+ <target refid="b">
+ <paragraph ids="b a" names="b a">
+ <reference name="b" refid="b">
+ b
+ <system_message level="1" line="1" source="test data" type="INFO">
+ <paragraph>
+ Hyperlink target "a" is not referenced.
+"""],
+["""\
+.. _a:
+.. _b:
+
+a_\ b_
+""",
+"""\
+<document source="test data">
+ <target refid="a">
+ <target refid="b">
+ <paragraph ids="b a" names="b a">
+ <reference name="a" refid="a">
+ a
+ <reference name="b" refid="b">
+ b
+"""],
+["""\
+.. _external hyperlink: http://uri
+
+`External hyperlink`_ reference.
+""",
+"""\
+<document source="test data">
+ <target ids="external-hyperlink" names="external\ hyperlink" refuri="http://uri">
+ <paragraph>
+ <reference name="External hyperlink" refuri="http://uri">
+ External hyperlink
+ reference.
+"""],
+["""\
+.. _external hyperlink: http://uri
+.. _indirect target: `external hyperlink`_
+""",
+"""\
+<document source="test data">
+ <target ids="external-hyperlink" names="external\ hyperlink" refuri="http://uri">
+ <target ids="indirect-target" names="indirect\ target" refuri="http://uri">
+ <system_message level="1" line="2" source="test data" type="INFO">
+ <paragraph>
+ Hyperlink target "indirect target" is not referenced.
+"""],
+["""\
+.. _chained:
+.. _external hyperlink: http://uri
+
+`External hyperlink`_ reference
+and a chained_ reference too.
+""",
+"""\
+<document source="test data">
+ <target refid="chained">
+ <target ids="external-hyperlink chained" names="external\ hyperlink chained" refuri="http://uri">
+ <paragraph>
+ <reference name="External hyperlink" refuri="http://uri">
+ External hyperlink
+ reference
+ and a \n\
+ <reference name="chained" refuri="http://uri">
+ chained
+ reference too.
+"""],
+["""\
+.. _external hyperlink: http://uri
+.. _indirect hyperlink: `external hyperlink`_
+
+`Indirect hyperlink`_ reference.
+""",
+"""\
+<document source="test data">
+ <target ids="external-hyperlink" names="external\ hyperlink" refuri="http://uri">
+ <target ids="indirect-hyperlink" names="indirect\ hyperlink" refuri="http://uri">
+ <paragraph>
+ <reference name="Indirect hyperlink" refuri="http://uri">
+ Indirect hyperlink
+ reference.
+"""],
+["""\
+.. _external hyperlink: http://uri
+.. _chained:
+.. _indirect hyperlink: `external hyperlink`_
+
+Chained_ `indirect hyperlink`_ reference.
+""",
+"""\
+<document source="test data">
+ <target ids="external-hyperlink" names="external\ hyperlink" refuri="http://uri">
+ <target refuri="http://uri">
+ <target ids="indirect-hyperlink chained" names="indirect\ hyperlink chained" refuri="http://uri">
+ <paragraph>
+ <reference name="Chained" refuri="http://uri">
+ Chained
+ \n\
+ <reference name="indirect hyperlink" refuri="http://uri">
+ indirect hyperlink
+ reference.
+"""],
+["""\
+.. __: http://full
+__
+__ http://simplified
+.. _external: http://indirect.external
+__ external_
+__
+
+`Full syntax anonymous external hyperlink reference`__,
+`chained anonymous external reference`__,
+`simplified syntax anonymous external hyperlink reference`__,
+`indirect anonymous hyperlink reference`__,
+`internal anonymous hyperlink reference`__.
+""",
+"""\
+<document source="test data">
+ <target anonymous="1" ids="id1" refuri="http://full">
+ <target anonymous="1" refid="id2">
+ <target anonymous="1" ids="id3 id2" refuri="http://simplified">
+ <target ids="external" names="external" refuri="http://indirect.external">
+ <target anonymous="1" ids="id4" refuri="http://indirect.external">
+ <target anonymous="1" refid="id5">
+ <paragraph ids="id5">
+ <reference anonymous="1" name="Full syntax anonymous external hyperlink reference" refuri="http://full">
+ Full syntax anonymous external hyperlink reference
+ ,
+ <reference anonymous="1" name="chained anonymous external reference" refuri="http://simplified">
+ chained anonymous external reference
+ ,
+ <reference anonymous="1" name="simplified syntax anonymous external hyperlink reference" refuri="http://simplified">
+ simplified syntax anonymous external hyperlink reference
+ ,
+ <reference anonymous="1" name="indirect anonymous hyperlink reference" refuri="http://indirect.external">
+ indirect anonymous hyperlink reference
+ ,
+ <reference anonymous="1" name="internal anonymous hyperlink reference" refid="id5">
+ internal anonymous hyperlink reference
+ .
+"""],
+["""\
+Duplicate external target_'s (different URIs):
+
+.. _target: first
+
+.. _target: second
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate external \n\
+ <problematic ids="id3" refid="id2">
+ target_
+ 's (different URIs):
+ <target dupnames="target" ids="target" refuri="first">
+ <system_message backrefs="id1" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id1" refuri="second">
+ <system_message backrefs="id3" ids="id2" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Duplicate target name, cannot be used as a unique reference: "target".
+"""],
+["""\
+Duplicate external targets (different URIs) without reference:
+
+.. _target: first
+
+.. _target: second
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate external targets (different URIs) without reference:
+ <target dupnames="target" ids="target" refuri="first">
+ <system_message backrefs="id1" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "target".
+ <target dupnames="target" ids="id1" refuri="second">
+"""],
+["""\
+Several__ anonymous__ hyperlinks__, but not enough targets.
+
+__ http://example.org
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <problematic ids="id3" refid="id2">
+ Several__
+ \n\
+ <problematic ids="id4" refid="id2">
+ anonymous__
+ \n\
+ <problematic ids="id5" refid="id2">
+ hyperlinks__
+ , but not enough targets.
+ <target anonymous="1" ids="id1" refuri="http://example.org">
+ <system_message backrefs="id3 id4 id5" ids="id2" level="3" source="test data" type="ERROR">
+ <paragraph>
+ Anonymous hyperlink mismatch: 3 references but 1 targets.
+ See "backrefs" attribute for IDs.
+"""],
+["""\
+.. _external: http://uri
+.. _indirect: external_
+.. _internal:
+
+.. image:: picture.png
+ :target: external_
+
+.. image:: picture.png
+ :target: indirect_
+
+.. image:: picture.png
+ :target: internal_
+""",
+"""\
+<document source="test data">
+ <target ids="external" names="external" refuri="http://uri">
+ <target ids="indirect" names="indirect" refuri="http://uri">
+ <target refid="internal">
+ <reference ids="internal" name="external" names="internal" refuri="http://uri">
+ <image uri="picture.png">
+ <reference name="indirect" refuri="http://uri">
+ <image uri="picture.png">
+ <reference name="internal" refid="internal">
+ <image uri="picture.png">
+"""],
+["""\
+.. contents:: Table of Contents
+.. _indirect reference to the table of contents: `table of contents`_
+
+Section
+=======
+
+Testing an `indirect reference to the table of contents`_.
+""",
+"""\
+<document source="test data">
+ <topic classes="contents" ids="table-of-contents" names="table\ of\ contents">
+ <title>
+ Table of Contents
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="section">
+ Section
+ <target ids="indirect-reference-to-the-table-of-contents" names="indirect\ reference\ to\ the\ table\ of\ contents" refid="table-of-contents">
+ <section ids="section" names="section">
+ <title refid="id1">
+ Section
+ <paragraph>
+ Testing an
+ <reference name="indirect reference to the table of contents" refid="table-of-contents">
+ indirect reference to the table of contents
+ .
+"""],
+["""\
+.. _explicit target:
+
+Title
+-----
+
+Let's reference it (`explicit target`_) to avoid an irrelevant error.
+""",
+"""\
+<document source="test data">
+ <target refid="explicit-target">
+ <section ids="title explicit-target" names="title explicit\ target">
+ <title>
+ Title
+ <paragraph>
+ Let's reference it (
+ <reference name="explicit target" refid="explicit-target">
+ explicit target
+ ) to avoid an irrelevant error.
+"""],
+["""\
+target1_ should refer to target2_, not the Title.
+
+.. _target1:
+.. _target2: URI
+
+Title
+=====
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ <reference name="target1" refuri="URI">
+ target1
+ should refer to \n\
+ <reference name="target2" refuri="URI">
+ target2
+ , not the Title.
+ <target refid="target1">
+ <target ids="target2 target1" names="target2 target1" refuri="URI">
+ <section ids="title" names="title">
+ <title>
+ Title
+"""],
+["""\
+Unknown reference_.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Unknown \n\
+ <problematic ids="id2" refid="id1">
+ reference_
+ .
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Unknown target name: "reference".
+"""],
+["""\
+Duplicate manual footnote labels, with reference ([1]_):
+
+.. [1] Footnote.
+
+.. [1] Footnote.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Duplicate manual footnote labels, with reference (
+ <problematic ids="id5 id1" refid="id4">
+ [1]_
+ ):
+ <footnote dupnames="1" ids="id2">
+ <label>
+ 1
+ <paragraph>
+ Footnote.
+ <footnote dupnames="1" ids="id3">
+ <label>
+ 1
+ <system_message backrefs="id3" level="2" line="5" source="test data" type="WARNING">
+ <paragraph>
+ Duplicate explicit target name: "1".
+ <paragraph>
+ Footnote.
+ <system_message backrefs="id5" ids="id4" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Duplicate target name, cannot be used as a unique reference: "1".
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_messages.py b/test/test_transforms/test_messages.py
new file mode 100755
index 000000000..6ff8c9987
--- /dev/null
+++ b/test/test_transforms/test_messages.py
@@ -0,0 +1,66 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.universal.Messages.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.universal import Messages
+from docutils.transforms.references import Substitutions
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['system_message_sections'] = ((Substitutions, Messages), [
+["""\
+This |unknown substitution| will generate a system message, thanks to
+the ``Substitutions`` transform. The ``Messages`` transform will
+generate a "System Messages" section.
+
+(A second copy of the system message is tacked on to the end of the
+document by the test framework.)
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ This \n\
+ <problematic ids="id2" refid="id1">
+ |unknown substitution|
+ will generate a system message, thanks to
+ the \n\
+ <literal>
+ Substitutions
+ transform. The \n\
+ <literal>
+ Messages
+ transform will
+ generate a "System Messages" section.
+ <paragraph>
+ (A second copy of the system message is tacked on to the end of the
+ document by the test framework.)
+ <section classes="system-messages">
+ <title>
+ Docutils System Messages
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Undefined substitution referenced: "unknown substitution".
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_peps.py b/test/test_transforms/test_peps.py
new file mode 100755
index 000000000..5e34aea80
--- /dev/null
+++ b/test/test_transforms/test_peps.py
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.peps.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.peps import TargetNotes
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['target_notes'] = ((TargetNotes,), [
+["""\
+No references or targets exist, therefore
+no "References" section should be generated.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ No references or targets exist, therefore
+ no "References" section should be generated.
+"""],
+["""\
+A target exists, here's the reference_.
+A "References" section should be generated.
+
+.. _reference: http://www.example.org
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A target exists, here's the \n\
+ <reference name="reference" refname="reference">
+ reference
+ \n\
+ <footnote_reference auto="1" ids="id3" refname="TARGET_NOTE: id2">
+ .
+ A "References" section should be generated.
+ <target ids="reference" names="reference" refuri="http://www.example.org">
+ <section ids="id1">
+ <title>
+ References
+ <footnote auto="1" ids="id2" names="TARGET_NOTE:\ id2">
+ <paragraph>
+ <reference refuri="http://www.example.org">
+ http://www.example.org
+"""],
+])
+
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_sectnum.py b/test/test_transforms/test_sectnum.py
new file mode 100755
index 000000000..60237cea1
--- /dev/null
+++ b/test/test_transforms/test_sectnum.py
@@ -0,0 +1,381 @@
+#! /usr/bin/env python
+
+# Author: David Goodger, Dmitry Jemerov
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for `docutils.transforms.parts.SectNum` (via
+`docutils.transforms.universal.LastReaderPending`).
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import Substitutions
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['section_numbers'] = ((Substitutions,), [
+["""\
+.. sectnum::
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1.1\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1.1.1\u00a0\u00a0\u00a0
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1.2\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. sectnum::
+
+**Bold Title**
+==============
+Paragraph 1.
+""",
+u"""\
+<document source="test data">
+ <section ids="bold-title" names="bold\ title">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1\u00a0\u00a0\u00a0
+ <strong>
+ Bold Title
+ <paragraph>
+ Paragraph 1.
+"""],
+["""\
+.. sectnum:: :depth: 2
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1.1\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title>
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1">
+ <generated classes="sectnum">
+ 1.2\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. contents::
+.. sectnum:: :depth: 2
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <topic classes="contents" ids="contents" names="contents">
+ <title>
+ Contents
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id1" refid="title-1">
+ <generated classes="sectnum">
+ 1\u00a0\u00a0\u00a0
+ Title 1
+ <bullet_list classes="auto-toc">
+ <list_item>
+ <paragraph>
+ <reference ids="id2" refid="title-2">
+ <generated classes="sectnum">
+ 1.1\u00a0\u00a0\u00a0
+ Title 2
+ <bullet_list>
+ <list_item>
+ <paragraph>
+ <reference ids="id3" refid="title-3">
+ Title 3
+ <list_item>
+ <paragraph>
+ <reference ids="id4" refid="title-4">
+ <generated classes="sectnum">
+ 1.2\u00a0\u00a0\u00a0
+ Title 4
+ <section ids="title-1" names="title\ 1">
+ <title auto="1" refid="id1">
+ <generated classes="sectnum">
+ 1\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1" refid="id2">
+ <generated classes="sectnum">
+ 1.1\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title refid="id3">
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1" refid="id4">
+ <generated classes="sectnum">
+ 1.2\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. sectnum::
+ :prefix: Arbitrary-
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title auto="1">
+ <generated classes="sectnum">
+ Arbitrary-1\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1">
+ <generated classes="sectnum">
+ Arbitrary-1.1\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title auto="1">
+ <generated classes="sectnum">
+ Arbitrary-1.1.1\u00a0\u00a0\u00a0
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1">
+ <generated classes="sectnum">
+ Arbitrary-1.2\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. sectnum::
+ :start: 3
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title auto="1">
+ <generated classes="sectnum">
+ 3\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1">
+ <generated classes="sectnum">
+ 3.1\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title auto="1">
+ <generated classes="sectnum">
+ 3.1.1\u00a0\u00a0\u00a0
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1">
+ <generated classes="sectnum">
+ 3.2\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+["""\
+.. sectnum::
+ :prefix: (5.9.
+ :suffix: )
+ :start: 3
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+
+Title 3
+```````
+Paragraph 3.
+
+Title 4
+-------
+Paragraph 4.
+""",
+u"""\
+<document source="test data">
+ <section ids="title-1" names="title\ 1">
+ <title auto="1">
+ <generated classes="sectnum">
+ (5.9.3)\u00a0\u00a0\u00a0
+ Title 1
+ <paragraph>
+ Paragraph 1.
+ <section ids="title-2" names="title\ 2">
+ <title auto="1">
+ <generated classes="sectnum">
+ (5.9.3.1)\u00a0\u00a0\u00a0
+ Title 2
+ <paragraph>
+ Paragraph 2.
+ <section ids="title-3" names="title\ 3">
+ <title auto="1">
+ <generated classes="sectnum">
+ (5.9.3.1.1)\u00a0\u00a0\u00a0
+ Title 3
+ <paragraph>
+ Paragraph 3.
+ <section ids="title-4" names="title\ 4">
+ <title auto="1">
+ <generated classes="sectnum">
+ (5.9.3.2)\u00a0\u00a0\u00a0
+ Title 4
+ <paragraph>
+ Paragraph 4.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_strip_comments.py b/test/test_transforms/test_strip_comments.py
new file mode 100755
index 000000000..e3efc1e14
--- /dev/null
+++ b/test/test_transforms/test_strip_comments.py
@@ -0,0 +1,49 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.universal.StripComments.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.universal import StripComments
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(
+ parser, suite_settings={'strip_comments': 1})
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['strip_comments'] = ((StripComments,), [
+["""\
+.. this is a comment
+
+Title
+=====
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <section ids="title" names="title">
+ <title>
+ Title
+ <paragraph>
+ Paragraph.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_substitutions.py b/test/test_transforms/test_substitutions.py
new file mode 100755
index 000000000..196bec9a1
--- /dev/null
+++ b/test/test_transforms/test_substitutions.py
@@ -0,0 +1,353 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for docutils.transforms.references.Substitutions.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import Substitutions
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['substitutions'] = ((Substitutions,), [
+["""\
+The |biohazard| symbol is deservedly scary-looking.
+
+.. |biohazard| image:: biohazard.png
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ The \n\
+ <image alt="biohazard" uri="biohazard.png">
+ symbol is deservedly scary-looking.
+ <substitution_definition names="biohazard">
+ <image alt="biohazard" uri="biohazard.png">
+"""],
+["""\
+Here's an |unknown| substitution.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Here's an \n\
+ <problematic ids="id2" refid="id1">
+ |unknown|
+ substitution.
+ <system_message backrefs="id2" ids="id1" level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Undefined substitution referenced: "unknown".
+"""],
+[u"""\
+Substitutions support case differences:
+
+.. |eacute| replace:: \u00E9
+.. |Eacute| replace:: \u00C9
+
+|Eacute|\\t\\ |eacute|, and even |EACUTE|.
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Substitutions support case differences:
+ <substitution_definition names="eacute">
+ \u00E9
+ <substitution_definition names="Eacute">
+ \u00C9
+ <paragraph>
+ \u00C9
+ t
+ \u00E9
+ , and even \n\
+ \u00C9
+ .
+"""],
+[u"""\
+Indirect substitution definitions with multiple references:
+
+|substitute| my coke for gin
+|substitute| you for my mum
+at least I'll get my washing done
+
+.. |substitute| replace:: |replace|
+.. |replace| replace:: swap
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Indirect substitution definitions with multiple references:
+ <paragraph>
+ swap
+ my coke for gin
+ swap
+ you for my mum
+ at least I'll get my washing done
+ <substitution_definition names="substitute">
+ swap
+ <substitution_definition names="replace">
+ swap
+"""],
+["""\
+.. |l| unicode:: U+00AB .. left chevron
+.. |r| unicode:: U+00BB .. right chevron
+.. |.| replace:: |l|\ ``.``\ |r|
+
+.. Delete either of the following lines, and there is no error.
+
+Regular expression |.| will match any character
+
+.. Note:: Note that |.| matches *exactly* one character
+""",
+u"""\
+<document source="test data">
+ <substitution_definition names="l">
+ \xab
+ <substitution_definition names="r">
+ \xbb
+ <substitution_definition names=".">
+ \xab
+ <literal>
+ .
+ \xbb
+ <comment xml:space="preserve">
+ Delete either of the following lines, and there is no error.
+ <paragraph>
+ Regular expression \n\
+ \xab
+ <literal>
+ .
+ \xbb
+ will match any character
+ <note>
+ <paragraph>
+ Note that \n\
+ \xab
+ <literal>
+ .
+ \xbb
+ matches \n\
+ <emphasis>
+ exactly
+ one character
+"""],
+["""\
+.. |sub| replace:: |sub|
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" names="sub" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |sub| replace:: |sub|
+"""],
+["""\
+.. |sub| replace:: |indirect1|
+.. |indirect1| replace:: |indirect2|
+.. |indirect2| replace:: |Sub|
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" names="sub" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |sub| replace:: |indirect1|
+ <system_message level="3" line="2" names="indirect1" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |indirect1| replace:: |indirect2|
+ <system_message level="3" line="3" names="indirect2" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |indirect2| replace:: |Sub|
+"""],
+["""\
+.. |indirect1| replace:: |indirect2|
+.. |indirect2| replace:: |Sub|
+.. |sub| replace:: |indirect1|
+
+Use |sub| and |indirect1| and |sub| again (and |sub| one more time).
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" names="indirect1" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |indirect1| replace:: |indirect2|
+ <system_message level="3" line="2" names="indirect2" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |indirect2| replace:: |Sub|
+ <system_message level="3" line="3" names="sub" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition detected:
+ <literal_block xml:space="preserve">
+ .. |sub| replace:: |indirect1|
+ <paragraph>
+ Use \n\
+ <problematic ids="id8" refid="id7">
+ and \n\
+ <problematic ids="id2" refid="id1">
+ |indirect1|
+ and \n\
+ <problematic ids="id4" refid="id3">
+ |sub|
+ again (and \n\
+ <problematic ids="id6" refid="id5">
+ |sub|
+ one more time).
+ <system_message backrefs="id2" ids="id1" level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition referenced: "indirect1".
+ <system_message backrefs="id4" ids="id3" level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition referenced: "sub".
+ <system_message backrefs="id6" ids="id5" level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition referenced: "sub".
+ <system_message backrefs="id8" ids="id7" level="3" source="test data" type="ERROR">
+ <paragraph>
+ Circular substitution definition referenced: "Sub".
+"""],
+])
+
+totest['unicode'] = ((Substitutions,), [
+["""\
+Insert an em-dash (|mdash|), a copyright symbol (|copy|), a non-breaking
+space (|nbsp|), a backwards-not-equals (|bne|), and a captial omega (|Omega|).
+
+.. |mdash| unicode:: 0x02014
+.. |copy| unicode:: \\u00A9
+.. |nbsp| unicode:: &#x000A0;
+.. |bne| unicode:: U0003D U020E5
+.. |Omega| unicode:: U+003A9
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Insert an em-dash (
+ \u2014
+ ), a copyright symbol (
+ \u00a9
+ ), a non-breaking
+ space (
+ \u00a0
+ ), a backwards-not-equals (
+ =
+ \u20e5
+ ), and a captial omega (
+ \u03a9
+ ).
+ <substitution_definition names="mdash">
+ \u2014
+ <substitution_definition names="copy">
+ \u00a9
+ <substitution_definition names="nbsp">
+ \u00a0
+ <substitution_definition names="bne">
+ =
+ \u20e5
+ <substitution_definition names="Omega">
+ \u03a9
+"""],
+["""
+Testing comments and extra text.
+
+Copyright |copy| 2003, |BogusMegaCorp (TM)|.
+
+.. |copy| unicode:: 0xA9 .. copyright sign
+.. |BogusMegaCorp (TM)| unicode:: BogusMegaCorp U+2122
+ .. with trademark sign
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Testing comments and extra text.
+ <paragraph>
+ Copyright \n\
+ \u00a9
+ 2003, \n\
+ BogusMegaCorp
+ \u2122
+ .
+ <substitution_definition names="copy">
+ \u00a9
+ <substitution_definition names="BogusMegaCorp\ (TM)">
+ BogusMegaCorp
+ \u2122
+"""],
+["""\
+Insert an em-dash |---| automatically trimming whitespace.
+Some substitutions |TM| only need trimming on one side.
+
+.. |---| unicode:: U+02014
+ :trim:
+.. |TM| unicode:: U+02122
+ :ltrim:
+""",
+u"""\
+<document source="test data">
+ <paragraph>
+ Insert an em-dash
+ \u2014
+ automatically trimming whitespace.
+ Some substitutions
+ \u2122
+ only need trimming on one side.
+ <substitution_definition ltrim="1" names="---" rtrim="1">
+ \u2014
+ <substitution_definition ltrim="1" names="TM">
+ \u2122
+"""],
+["""\
+Substitution definition with an illegal element:
+
+.. |target| replace:: _`target`
+
+Make sure this substitution definition is not registered: |target|
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Substitution definition with an illegal element:
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Substitution definition contains illegal element:
+ <literal_block xml:space="preserve">
+ <target ids="target" names="target">
+ target
+ <literal_block xml:space="preserve">
+ .. |target| replace:: _`target`
+ <paragraph>
+ Make sure this substitution definition is not registered: \n\
+ <problematic ids="id2" refid="id1">
+ |target|
+ <system_message backrefs="id2" ids="id1" level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Undefined substitution referenced: "target".
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_target_notes.py b/test/test_transforms/test_target_notes.py
new file mode 100755
index 000000000..cf625572d
--- /dev/null
+++ b/test/test_transforms/test_target_notes.py
@@ -0,0 +1,84 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for `docutils.transforms.references.TargetNotes` (via
+`docutils.transforms.universal.LastReaderPending`).
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils.transforms.references import PropagateTargets, \
+ AnonymousHyperlinks, IndirectHyperlinks, ExternalTargets, \
+ InternalTargets, DanglingReferences, Footnotes
+from docutils.parsers.rst import Parser
+
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['tables_of_contents'] = ((PropagateTargets, AnonymousHyperlinks,
+ IndirectHyperlinks,
+ ExternalTargets, InternalTargets,
+ DanglingReferences,
+ ), [
+["""\
+.. _target: http://exammple.org
+
+A reference to a target_.
+
+.. target-notes::
+""",
+"""\
+<document source="test data">
+ <target ids="target" names="target" refuri="http://exammple.org">
+ <paragraph>
+ A reference to a \n\
+ <reference name="target" refuri="http://exammple.org">
+ target
+ \n\
+ <footnote_reference auto="1" ids="id2" refid="id1">
+ .
+ <footnote auto="1" ids="id1" names="TARGET_NOTE:\\ id1">
+ <paragraph>
+ <reference refuri="http://exammple.org">
+ http://exammple.org
+"""],
+["""\
+.. _target: http://exammple.org
+
+A reference to a target_.
+
+.. target-notes:: :class: custom
+""",
+"""\
+<document source="test data">
+ <target ids="target" names="target" refuri="http://exammple.org">
+ <paragraph>
+ A reference to a \n\
+ <reference name="target" refuri="http://exammple.org">
+ target
+ <inline classes="custom">
+ \n\
+ <footnote_reference auto="1" classes="custom" ids="id2" refid="id1">
+ .
+ <footnote auto="1" ids="id1" names="TARGET_NOTE:\\ id1">
+ <paragraph>
+ <reference refuri="http://exammple.org">
+ http://exammple.org
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_transitions.py b/test/test_transforms/test_transitions.py
new file mode 100755
index 000000000..098c8bba3
--- /dev/null
+++ b/test/test_transforms/test_transitions.py
@@ -0,0 +1,308 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for misc.Transitions transform.
+"""
+
+from __init__ import DocutilsTestSupport # must be imported before docutils
+from docutils.transforms.misc import Transitions
+from docutils.parsers.rst import Parser
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+
+totest = {}
+
+totest['transitions'] = ((Transitions,), [
+["""\
+Section 1
+=========
+
+Subsection 1
+------------
+
+Some text.
+
+----------
+
+Section 2
+=========
+
+Some text.
+""",
+"""\
+<document source="test data">
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <section ids="subsection-1" names="subsection\ 1">
+ <title>
+ Subsection 1
+ <paragraph>
+ Some text.
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <paragraph>
+ Some text.
+"""],
+["""\
+A paragraph.
+
+----------
+
+Section 1
+=========
+
+Paragraph.
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph.
+ <transition>
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <paragraph>
+ Paragraph.
+"""],
+["""\
+--------
+
+A section or document may not begin with a transition.
+
+The DTD specifies that two transitions may not
+be adjacent:
+
+--------
+
+--------
+
+--------
+
+The DTD also specifies that a section or document
+may not end with a transition.
+
+--------
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <paragraph>
+ A section or document may not begin with a transition.
+ <paragraph>
+ The DTD specifies that two transitions may not
+ be adjacent:
+ <transition>
+ <system_message level="3" line="10" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="12" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <paragraph>
+ The DTD also specifies that a section or document
+ may not end with a transition.
+ <transition>
+ <system_message level="3" line="17" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+["""\
+Sections with transitions at beginning and end.
+
+Section 1
+=========
+
+----------
+
+The next transition is legal:
+
+----------
+
+Section 2
+=========
+
+----------
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ Sections with transitions at beginning and end.
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <system_message level="3" line="6" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <paragraph>
+ The next transition is legal:
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <system_message level="3" line="15" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <system_message level="3" line="15" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+["""\
+A paragraph and two transitions.
+
+----------
+
+----------
+""", # the same:
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph and two transitions.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+["""\
+A paragraph, two transitions, and a blank line.
+
+----------
+
+----------
+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph, two transitions, and a blank line.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+["""\
+----------
+
+Document beginning with a transition.
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <paragraph>
+ Document beginning with a transition.
+"""],
+["""\
+Section 1
+=========
+
+----------
+
+----------
+
+----------
+
+Section 2
+=========
+
+Some text.
+""",
+"""\
+<document source="test data">
+ <section ids="section-1" names="section\ 1">
+ <title>
+ Section 1
+ <system_message level="3" line="4" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <system_message level="3" line="6" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="8" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <section ids="section-2" names="section\ 2">
+ <title>
+ Section 2
+ <paragraph>
+ Some text.
+"""],
+["""\
+----------
+
+----------
+
+----------
+""",
+"""\
+<document source="test data">
+ <system_message level="3" line="1" source="test data" type="ERROR">
+ <paragraph>
+ Document or section may not begin with a transition.
+ <transition>
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ At least one body element must separate transitions; adjacent transitions are not allowed.
+ <transition>
+ <system_message level="3" line="5" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+["""\
+A paragraph.
+
+----------
+
+""",
+"""\
+<document source="test data">
+ <paragraph>
+ A paragraph.
+ <transition>
+ <system_message level="3" line="3" source="test data" type="ERROR">
+ <paragraph>
+ Document may not end with a transition.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_transforms/test_writer_aux.py b/test/test_transforms/test_writer_aux.py
new file mode 100755
index 000000000..5ec040a69
--- /dev/null
+++ b/test/test_transforms/test_writer_aux.py
@@ -0,0 +1,57 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for writer_aux transforms.
+"""
+
+from __init__ import DocutilsTestSupport # must be imported before docutils
+from docutils.transforms import writer_aux
+from docutils.parsers.rst import Parser
+
+def suite():
+ parser = Parser()
+ s = DocutilsTestSupport.TransformTestSuite(parser)
+ s.generateTests(totest)
+ return s
+
+
+totest = {}
+
+totest['compound'] = ((writer_aux.Compound,), [
+["""\
+.. class:: compound
+
+.. compound::
+
+ .. class:: paragraph1
+
+ Paragraph 1.
+
+ .. class:: paragraph2
+
+ Paragraph 2.
+
+ Block quote.
+""",
+"""\
+<document source="test data">
+ <paragraph classes="paragraph1 compound">
+ Paragraph 1.
+ <paragraph classes="paragraph2 continued">
+ Paragraph 2.
+ <block_quote classes="continued">
+ <paragraph>
+ Block quote.
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_utils.py b/test/test_utils.py
new file mode 100755
index 000000000..006495ac9
--- /dev/null
+++ b/test/test_utils.py
@@ -0,0 +1,213 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for utils.py.
+"""
+
+import unittest
+import StringIO
+import sys
+from DocutilsTestSupport import utils, nodes
+
+
+class ReporterTests(unittest.TestCase):
+
+ stream = StringIO.StringIO()
+ reporter = utils.Reporter('test data', 2, 4, stream, 1)
+
+ def setUp(self):
+ self.stream.seek(0)
+ self.stream.truncate()
+
+ def test_level0(self):
+ sw = self.reporter.system_message(0, 'debug output')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="0" source="test data" type="DEBUG">
+ <paragraph>
+ debug output
+""")
+ self.assertEquals(self.stream.getvalue(),
+ 'test data:: (DEBUG/0) debug output\n')
+
+ def test_level1(self):
+ sw = self.reporter.system_message(1, 'a little reminder')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="1" source="test data" type="INFO">
+ <paragraph>
+ a little reminder
+""")
+ self.assertEquals(self.stream.getvalue(), '')
+
+ def test_level2(self):
+ sw = self.reporter.system_message(2, 'a warning')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="2" source="test data" type="WARNING">
+ <paragraph>
+ a warning
+""")
+ self.assertEquals(self.stream.getvalue(),
+ 'test data:: (WARNING/2) a warning\n')
+
+ def test_level3(self):
+ sw = self.reporter.system_message(3, 'an error')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="3" source="test data" type="ERROR">
+ <paragraph>
+ an error
+""")
+ self.assertEquals(self.stream.getvalue(),
+ 'test data:: (ERROR/3) an error\n')
+
+ def test_level4(self):
+ self.assertRaises(utils.SystemMessage, self.reporter.system_message, 4,
+ 'a severe error, raises an exception')
+ self.assertEquals(self.stream.getvalue(), 'test data:: (SEVERE/4) '
+ 'a severe error, raises an exception\n')
+
+
+class QuietReporterTests(unittest.TestCase):
+
+ stream = StringIO.StringIO()
+ reporter = utils.Reporter('test data', 5, 5, stream, 0)
+
+ def setUp(self):
+ self.stream.seek(0)
+ self.stream.truncate()
+
+ def test_debug(self):
+ sw = self.reporter.debug('a debug message')
+ # None because debug is disabled.
+ self.assertEquals(sw, None)
+ self.assertEquals(self.stream.getvalue(), '')
+
+ def test_info(self):
+ sw = self.reporter.info('an informational message')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="1" source="test data" type="INFO">
+ <paragraph>
+ an informational message
+""")
+ self.assertEquals(self.stream.getvalue(), '')
+
+ def test_warning(self):
+ sw = self.reporter.warning('a warning')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="2" source="test data" type="WARNING">
+ <paragraph>
+ a warning
+""")
+ self.assertEquals(self.stream.getvalue(), '')
+
+ def test_error(self):
+ sw = self.reporter.error('an error')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="3" source="test data" type="ERROR">
+ <paragraph>
+ an error
+""")
+ self.assertEquals(self.stream.getvalue(), '')
+
+ def test_severe(self):
+ sw = self.reporter.severe('a severe error')
+ self.assertEquals(sw.pformat(), """\
+<system_message level="4" source="test data" type="SEVERE">
+ <paragraph>
+ a severe error
+""")
+ self.assertEquals(self.stream.getvalue(), '')
+
+
+class NameValueTests(unittest.TestCase):
+
+ def test_extract_name_value(self):
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ '=hello')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello=')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello="')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello="something')
+ self.assertRaises(utils.NameValueError, utils.extract_name_value,
+ 'hello="something"else')
+ output = utils.extract_name_value(
+ """att1=val1 att2=val2 att3="value number '3'" att4=val4""")
+ self.assertEquals(output, [('att1', 'val1'), ('att2', 'val2'),
+ ('att3', "value number '3'"),
+ ('att4', 'val4')])
+
+
+class ExtensionOptionTests(unittest.TestCase):
+
+ optionspec = {'a': int, 'bbb': float, 'cdef': (lambda x: x),
+ 'empty': (lambda x: x)}
+
+ def test_assemble_option_dict(self):
+ input = utils.extract_name_value('a=1 bbb=2.0 cdef=hol%s' % chr(224))
+ self.assertEquals(
+ utils.assemble_option_dict(input, self.optionspec),
+ {'a': 1, 'bbb': 2.0, 'cdef': ('hol%s' % chr(224))})
+ input = utils.extract_name_value('a=1 b=2.0 c=hol%s' % chr(224))
+ self.assertRaises(KeyError, utils.assemble_option_dict,
+ input, self.optionspec)
+ input = utils.extract_name_value('a=1 bbb=two cdef=hol%s' % chr(224))
+ self.assertRaises(ValueError, utils.assemble_option_dict,
+ input, self.optionspec)
+
+ def test_extract_extension_options(self):
+ field_list = nodes.field_list()
+ field_list += nodes.field(
+ '', nodes.field_name('', 'a'),
+ nodes.field_body('', nodes.paragraph('', '1')))
+ field_list += nodes.field(
+ '', nodes.field_name('', 'bbb'),
+ nodes.field_body('', nodes.paragraph('', '2.0')))
+ field_list += nodes.field(
+ '', nodes.field_name('', 'cdef'),
+ nodes.field_body('', nodes.paragraph('', 'hol%s' % chr(224))))
+ field_list += nodes.field(
+ '', nodes.field_name('', 'empty'), nodes.field_body())
+ self.assertEquals(
+ utils.extract_extension_options(field_list, self.optionspec),
+ {'a': 1, 'bbb': 2.0, 'cdef': ('hol%s' % chr(224)),
+ 'empty': None})
+ self.assertRaises(KeyError, utils.extract_extension_options,
+ field_list, {})
+ field_list += nodes.field(
+ '', nodes.field_name('', 'cdef'),
+ nodes.field_body('', nodes.paragraph('', 'one'),
+ nodes.paragraph('', 'two')))
+ self.assertRaises(utils.BadOptionDataError,
+ utils.extract_extension_options,
+ field_list, self.optionspec)
+ field_list[-1] = nodes.field(
+ '', nodes.field_name('', 'cdef bad'),
+ nodes.field_body('', nodes.paragraph('', 'no arguments')))
+ self.assertRaises(utils.BadOptionError,
+ utils.extract_extension_options,
+ field_list, self.optionspec)
+ field_list[-1] = nodes.field(
+ '', nodes.field_name('', 'cdef'),
+ nodes.field_body('', nodes.paragraph('', 'duplicate')))
+ self.assertRaises(utils.DuplicateOptionError,
+ utils.extract_extension_options,
+ field_list, self.optionspec)
+ field_list[-2] = nodes.field(
+ '', nodes.field_name('', 'unkown'),
+ nodes.field_body('', nodes.paragraph('', 'unknown')))
+ self.assertRaises(KeyError, utils.extract_extension_options,
+ field_list, self.optionspec)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_viewlist.py b/test/test_viewlist.py
new file mode 100755
index 000000000..85164b148
--- /dev/null
+++ b/test/test_viewlist.py
@@ -0,0 +1,166 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test module for the ViewList class from statemachine.py.
+"""
+
+import unittest
+import sys
+import re
+from DocutilsTestSupport import statemachine
+
+
+class ViewListTests(unittest.TestCase):
+
+ a_list = list('abcdefg')
+ b_list = list('AEIOU')
+ c_list = list('XYZ')
+
+ def setUp(self):
+ self.a = statemachine.ViewList(self.a_list, 'a')
+ self.b = statemachine.ViewList(self.b_list, 'b')
+ self.c = statemachine.ViewList(self.c_list, 'c')
+
+ def test_lists(self):
+ self.assertEqual(self.a, self.a_list)
+ self.assertEqual(str(self.a), str(self.a_list))
+ self.assertEqual(self.b, self.b_list)
+ self.assertEqual(self.c, self.c_list)
+ self.assertEqual(self.a.items,
+ zip('a' * len(self.a_list), range(len(self.a_list))))
+
+ def test_get_slice(self):
+ a = self.a[1:-1]
+ a_list = self.a_list[1:-1]
+ self.assertEqual(a, a_list)
+ self.assertEqual(a.items,
+ zip('a' * len(a_list), range(1, len(a_list) + 1)))
+ self.assertEqual(a.parent, self.a)
+
+ def test_set_slice(self):
+ a = statemachine.ViewList(self.a[:])
+ s = a[2:-2]
+ s[2:2] = self.b
+ s_list = self.a_list[2:-2]
+ s_list[2:2] = self.b_list
+ self.assertEqual(s, s_list)
+ self.assertEqual(s, a[2:-2])
+ self.assertEqual(s.items, a[2:-2].items)
+
+ def test_del_slice(self):
+ a = statemachine.ViewList(self.a[:])
+ s = a[2:]
+ s_list = self.a_list[2:]
+ del s[3:5]
+ del s_list[3:5]
+ self.assertEqual(s, s_list)
+ self.assertEqual(s, a[2:])
+ self.assertEqual(s.items, a[2:].items)
+
+ def test_insert(self):
+ a_list = self.a_list[:]
+ a_list.insert(2, 'Q')
+ a_list[4:4] = self.b_list
+ a = self.a[:]
+ self.assert_(isinstance(a, statemachine.ViewList))
+ a.insert(2, 'Q', 'runtime')
+ a.insert(4, self.b)
+ self.assertEqual(a, a_list)
+ self.assertEqual(a.info(2), ('runtime', 0))
+ self.assertEqual(a.info(5), ('b', 1))
+
+ def test_append(self):
+ a_list = self.a_list[:]
+ a_list.append('Q')
+ a_list.extend(self.b_list)
+ a = statemachine.ViewList(self.a)
+ a.append('Q', 'runtime')
+ a.append(self.b)
+ self.assertEqual(a, a_list)
+ self.assertEqual(a.info(len(self.a)), ('runtime', 0))
+ self.assertEqual(a.info(-2), ('b', len(self.b) - 2))
+
+ def test_extend(self):
+ a_list = self.a_list[:]
+ a_list.extend(self.b_list)
+ a = statemachine.ViewList(self.a)
+ a.extend(self.b)
+ self.assertEqual(a, a_list)
+ self.assertEqual(a.info(len(self.a) + 1), ('b', 1))
+
+ def test_view(self):
+ a = statemachine.ViewList(self.a[:])
+ a.insert(4, self.b)
+ s = a[2:-2]
+ s.insert(5, self.c)
+ self.assertEqual(s, a[2:-2])
+ self.assertEqual(s.items, a[2:-2].items)
+ s.pop()
+ self.assertEqual(s, a[2:-2])
+ self.assertEqual(s.items, a[2:-2].items)
+ s.remove('X')
+ self.assertEqual(s, a[2:-2])
+ self.assertEqual(s.items, a[2:-2].items)
+
+ def test_trim(self):
+ a = statemachine.ViewList(self.a[:])
+ s = a[1:-1]
+ s.trim_start(1)
+ self.assertEquals(a, self.a)
+ self.assertEquals(s, a[2:-1])
+ s.trim_end(1)
+ self.assertEquals(a, self.a)
+ self.assertEquals(s, a[2:-2])
+
+
+# print
+# print a
+# print s
+# print a.items
+# print s.items
+
+
+class StringList(unittest.TestCase):
+
+ text = """\
+This is some
+example text.
+
+ Here is some
+ indented text.
+
+Unindented text.
+"""
+
+ indented_string = """\
+ a
+ literal
+ block"""
+
+
+ def setUp(self):
+ self.a_list = self.text.splitlines(1)
+ self.a = statemachine.StringList(self.a_list, 'a')
+
+ def test_trim_left(self):
+ s = self.a[3:5]
+ s.trim_left(4)
+ self.assertEqual(s, [line.lstrip() for line in self.a_list[3:5]])
+
+ def test_get_indented(self):
+ self.assertEquals(self.a.get_indented(),
+ ([], 0, 0))
+ block = statemachine.StringList(
+ statemachine.string2lines(self.indented_string))
+ self.assertEquals(block.get_indented(),
+ ([s[6:] for s in block], 6, 1))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_writers/__init__.py b/test/test_writers/__init__.py
new file mode 100644
index 000000000..46fc50e06
--- /dev/null
+++ b/test/test_writers/__init__.py
@@ -0,0 +1,14 @@
+import os
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
+prev = ''
+while sys.path[0] != prev:
+ try:
+ import DocutilsTestSupport
+ break
+ except ImportError:
+ prev = sys.path[0]
+ sys.path[0] = os.path.dirname(prev)
+sys.path.pop(0)
diff --git a/test/test_writers/test_docutils_xml.py b/test/test_writers/test_docutils_xml.py
new file mode 100755
index 000000000..c51d71379
--- /dev/null
+++ b/test/test_writers/test_docutils_xml.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test for docutils XML writer.
+"""
+
+from __init__ import DocutilsTestSupport
+
+import docutils
+import docutils.core
+
+
+class DocutilsXMLTestCase(DocutilsTestSupport.StandardTestCase):
+
+ input = """\
+Test
+
+----------
+
+Test. \xc3\xa4\xc3\xb6\xc3\xbc\xe2\x82\xac"""
+ xmldecl = '<?xml version="1.0" encoding="iso-8859-1"?>\n'
+ doctypedecl = '<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">\n'
+ generatedby = '<!-- Generated by Docutils %s -->\n' % docutils.__version__
+ bodynormal = '<document source="&lt;string&gt;"><paragraph>Test</paragraph><transition/><paragraph>Test. \xe4\xf6\xfc&#8364;</paragraph></document>'
+ bodynewlines = """\
+<document source="&lt;string&gt;">
+<paragraph>
+Test
+</paragraph>
+<transition/>
+<paragraph>
+Test. \xe4\xf6\xfc&#8364;
+</paragraph>
+</document>
+"""
+ bodyindents = """\
+<document source="&lt;string&gt;">
+ <paragraph>
+ Test
+ </paragraph>
+ <transition/>
+ <paragraph>
+ Test. \xe4\xf6\xfc&#8364;
+ </paragraph>
+</document>
+"""
+
+ def test_publish(self):
+ settings = {'input_encoding': 'utf8',
+ 'output_encoding': 'iso-8859-1',
+ '_disable_config': 1}
+ for settings['newlines'] in 0, 1:
+ for settings['indents'] in 0, 1:
+ for settings['xml_declaration'] in 0, 1:
+ for settings['doctype_declaration'] in 0, 1:
+
+ expected = ''
+ if settings['xml_declaration']:
+ expected += self.xmldecl
+ if settings['doctype_declaration']:
+ expected += self.doctypedecl
+ expected += self.generatedby
+ if settings['indents']:
+ expected += self.bodyindents
+ elif settings['newlines']:
+ expected += self.bodynewlines
+ else:
+ expected += self.bodynormal
+
+ self.assertEqual(docutils.core.publish_string
+ (source=self.input,
+ reader_name='standalone',
+ writer_name='docutils_xml',
+ settings_overrides=settings),
+ expected)
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
diff --git a/test/test_writers/test_html4css1.py b/test/test_writers/test_html4css1.py
new file mode 100755
index 000000000..7d87ee324
--- /dev/null
+++ b/test/test_writers/test_html4css1.py
@@ -0,0 +1,373 @@
+#! /usr/bin/env python
+
+# Author: reggie dugard
+# Contact: reggie@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test for fragment code in HTML writer.
+
+Note: the 'body' and 'whole' entries have been removed from the parts
+dictionaries (redundant), along with 'meta' and 'stylesheet' entries with
+standard values, and any entries with empty values.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils import core
+
+def suite():
+ s = DocutilsTestSupport.HtmlPublishPartsTestSuite()
+ s.generateTests(totest)
+ return s
+
+
+totest = {}
+
+totest['Title promotion'] = ({'stylesheet_path': '',
+ 'embed_stylesheet': 0}, [
+["""\
+Simple String
+""",
+"""\
+{'fragment': '''<p>Simple String</p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String</p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+Simple String with *markup*
+""",
+"""\
+{'fragment': '''<p>Simple String with <em>markup</em></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String with <em>markup</em></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+Simple String with an even simpler ``inline literal``
+""",
+"""\
+{'fragment': '''<p>Simple String with an even simpler <tt class="docutils literal"><span class="pre">inline</span> <span class="pre">literal</span></tt></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String with an even simpler <tt class="docutils literal"><span class="pre">inline</span> <span class="pre">literal</span></tt></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+A simple `anonymous reference`__
+
+__ http://www.test.com/test_url
+""",
+"""\
+{'fragment': '''<p>A simple <a class="reference" href="http://www.test.com/test_url">anonymous reference</a></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>A simple <a class="reference" href="http://www.test.com/test_url">anonymous reference</a></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+One paragraph.
+
+Two paragraphs.
+""",
+"""\
+{'fragment': '''<p>One paragraph.</p>
+<p>Two paragraphs.</p>\\n''',
+ 'html_body': '''<div class="document">
+<p>One paragraph.</p>
+<p>Two paragraphs.</p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+A simple `named reference`_ with stuff in between the
+reference and the target.
+
+.. _`named reference`: http://www.test.com/test_url
+""",
+"""\
+{'fragment': '''<p>A simple <a class="reference" href="http://www.test.com/test_url">named reference</a> with stuff in between the
+reference and the target.</p>\\n''',
+ 'html_body': '''<div class="document">
+<p>A simple <a class="reference" href="http://www.test.com/test_url">named reference</a> with stuff in between the
+reference and the target.</p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
++++++
+Title
++++++
+
+Subtitle
+========
+
+Some stuff
+
+Section
+-------
+
+Some more stuff
+
+Another Section
+...............
+
+And even more stuff
+""",
+"""\
+{'fragment': '''<p>Some stuff</p>
+<div class="section">
+<h1><a id="section" name="section">Section</a></h1>
+<p>Some more stuff</p>
+<div class="section">
+<h2><a id="another-section" name="another-section">Another Section</a></h2>
+<p>And even more stuff</p>
+</div>
+</div>\\n''',
+ 'html_body': '''<div class="document" id="title">
+<h1 class="title">Title</h1>
+<h2 class="subtitle" id="subtitle">Subtitle</h2>
+<p>Some stuff</p>
+<div class="section">
+<h1><a id="section" name="section">Section</a></h1>
+<p>Some more stuff</p>
+<div class="section">
+<h2><a id="another-section" name="another-section">Another Section</a></h2>
+<p>And even more stuff</p>
+</div>
+</div>
+</div>\\n''',
+ 'html_head': '''...<title>Title</title>\\n''',
+ 'html_subtitle': '''<h2 class="subtitle" id="subtitle">Subtitle</h2>\\n''',
+ 'html_title': '''<h1 class="title">Title</h1>\\n''',
+ 'subtitle': '''Subtitle''',
+ 'title': '''Title'''}
+"""],
+["""\
++++++
+Title
++++++
+
+:author: me
+
+Some stuff
+""",
+"""\
+{'docinfo': '''<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>me</td></tr>
+</tbody>
+</table>\\n''',
+ 'fragment': '''<p>Some stuff</p>\\n''',
+ 'html_body': '''<div class="document" id="title">
+<h1 class="title">Title</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr><th class="docinfo-name">Author:</th>
+<td>me</td></tr>
+</tbody>
+</table>
+<p>Some stuff</p>
+</div>\\n''',
+ 'html_head': '''...<title>Title</title>
+<meta name="author" content="me" />\\n''',
+ 'html_title': '''<h1 class="title">Title</h1>\\n''',
+ 'meta': '''<meta name="author" content="me" />\\n''',
+ 'title': '''Title'''}
+"""]
+])
+
+totest['No title promotion'] = ({'doctitle_xform' : 0,
+ 'stylesheet_path': '',
+ 'embed_stylesheet': 0}, [
+["""\
+Simple String
+""",
+"""\
+{'fragment': '''<p>Simple String</p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String</p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+Simple String with *markup*
+""",
+"""\
+{'fragment': '''<p>Simple String with <em>markup</em></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String with <em>markup</em></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+Simple String with an even simpler ``inline literal``
+""",
+"""\
+{'fragment': '''<p>Simple String with an even simpler <tt class="docutils literal"><span class="pre">inline</span> <span class="pre">literal</span></tt></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>Simple String with an even simpler <tt class="docutils literal"><span class="pre">inline</span> <span class="pre">literal</span></tt></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+A simple `anonymous reference`__
+
+__ http://www.test.com/test_url
+""",
+"""\
+{'fragment': '''<p>A simple <a class="reference" href="http://www.test.com/test_url">anonymous reference</a></p>\\n''',
+ 'html_body': '''<div class="document">
+<p>A simple <a class="reference" href="http://www.test.com/test_url">anonymous reference</a></p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+A simple `named reference`_ with stuff in between the
+reference and the target.
+
+.. _`named reference`: http://www.test.com/test_url
+""",
+"""\
+{'fragment': '''<p>A simple <a class="reference" href="http://www.test.com/test_url">named reference</a> with stuff in between the
+reference and the target.</p>\\n''',
+ 'html_body': '''<div class="document">
+<p>A simple <a class="reference" href="http://www.test.com/test_url">named reference</a> with stuff in between the
+reference and the target.</p>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
++++++
+Title
++++++
+
+Not A Subtitle
+==============
+
+Some stuff
+
+Section
+-------
+
+Some more stuff
+
+Another Section
+...............
+
+And even more stuff
+""",
+"""\
+{'fragment': '''<div class="section">
+<h1><a id="title" name="title">Title</a></h1>
+<div class="section">
+<h2><a id="not-a-subtitle" name="not-a-subtitle">Not A Subtitle</a></h2>
+<p>Some stuff</p>
+<div class="section">
+<h3><a id="section" name="section">Section</a></h3>
+<p>Some more stuff</p>
+<div class="section">
+<h4><a id="another-section" name="another-section">Another Section</a></h4>
+<p>And even more stuff</p>
+</div>
+</div>
+</div>
+</div>\\n''',
+ 'html_body': '''<div class="document">
+<div class="section">
+<h1><a id="title" name="title">Title</a></h1>
+<div class="section">
+<h2><a id="not-a-subtitle" name="not-a-subtitle">Not A Subtitle</a></h2>
+<p>Some stuff</p>
+<div class="section">
+<h3><a id="section" name="section">Section</a></h3>
+<p>Some more stuff</p>
+<div class="section">
+<h4><a id="another-section" name="another-section">Another Section</a></h4>
+<p>And even more stuff</p>
+</div>
+</div>
+</div>
+</div>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+* bullet
+* list
+""",
+"""\
+{'fragment': '''<ul class="simple">
+<li>bullet</li>
+<li>list</li>
+</ul>\\n''',
+ 'html_body': '''<div class="document">
+<ul class="simple">
+<li>bullet</li>
+<li>list</li>
+</ul>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+["""\
+Not a docinfo.
+
+:This: .. _target:
+
+ is
+:a:
+:simple:
+:field: list
+""",
+"""\
+{'fragment': '''<p>Not a docinfo.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">This:</th><td class="field-body"><p class="first last" id="target">is</p>
+</td>
+</tr>
+<tr class="field"><th class="field-name">a:</th><td class="field-body"></td>
+</tr>
+<tr class="field"><th class="field-name">simple:</th><td class="field-body"></td>
+</tr>
+<tr class="field"><th class="field-name">field:</th><td class="field-body">list</td>
+</tr>
+</tbody>
+</table>\\n''',
+ 'html_body': '''<div class="document">
+<p>Not a docinfo.</p>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">This:</th><td class="field-body"><p class="first last" id="target">is</p>
+</td>
+</tr>
+<tr class="field"><th class="field-name">a:</th><td class="field-body"></td>
+</tr>
+<tr class="field"><th class="field-name">simple:</th><td class="field-body"></td>
+</tr>
+<tr class="field"><th class="field-name">field:</th><td class="field-body">list</td>
+</tr>
+</tbody>
+</table>
+</div>\\n''',
+ 'html_head': '''...<title></title>\\n'''}
+"""],
+])
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_writers/test_html4css1_misc.py b/test/test_writers/test_html4css1_misc.py
new file mode 100755
index 000000000..8b63d6f1c
--- /dev/null
+++ b/test/test_writers/test_html4css1_misc.py
@@ -0,0 +1,36 @@
+#! /usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Miscellaneous HTML writer tests.
+"""
+
+from __init__ import DocutilsTestSupport
+from docutils import core
+
+
+class EncodingTestCase(DocutilsTestSupport.StandardTestCase):
+
+ def test_xmlcharrefreplace(self):
+ # Test that xmlcharrefreplace is the default output encoding
+ # error handler.
+ settings_overrides={
+ 'output_encoding': 'latin1',
+ 'stylesheet': '',
+ '_disable_config': 1,}
+ result = core.publish_string(
+ 'EUR = \xe2\x82\xac', writer_name='html4css1',
+ settings_overrides=settings_overrides)
+ # Encoding a euro sign with latin1 doesn't work, so the
+ # xmlcharrefreplcae handler is used.
+ self.assert_(result.find('EUR = &#8364;') != -1)
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()
diff --git a/test/test_writers/test_latex2e.py b/test/test_writers/test_latex2e.py
new file mode 100755
index 000000000..04448883a
--- /dev/null
+++ b/test/test_writers/test_latex2e.py
@@ -0,0 +1,377 @@
+#! /usr/bin/env python
+
+# Author: engelbert gruber
+# Contact: grubert@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Tests for latex2e writer.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.PublishTestSuite('latex')
+ s.generateTests(totest)
+ return s
+
+
+latex_head = """\
+\\documentclass[10pt,a4paper,english]{article}
+\\usepackage{babel}
+\\usepackage{ae}
+\\usepackage{aeguill}
+\\usepackage{shortvrb}
+\\usepackage[latin1]{inputenc}
+\\usepackage{tabularx}
+\\usepackage{longtable}
+\\setlength{\\extrarowheight}{2pt}
+\\usepackage{amsmath}
+\\usepackage{graphicx}
+\\usepackage{color}
+\\usepackage{multirow}
+\\usepackage{ifthen}
+\\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+\\usepackage[DIV12]{typearea}
+%% generator Docutils: http://docutils.sourceforge.net/
+\\newlength{\\admonitionwidth}
+\\setlength{\\admonitionwidth}{0.9\\textwidth}
+\\newlength{\\docinfowidth}
+\\setlength{\\docinfowidth}{0.9\\textwidth}
+\\newlength{\\locallinewidth}
+\\newcommand{\\optionlistlabel}[1]{\\bf #1 \\hfill}
+\\newenvironment{optionlist}[1]
+{\\begin{list}{}
+ {\\setlength{\\labelwidth}{#1}
+ \\setlength{\\rightmargin}{1cm}
+ \\setlength{\\leftmargin}{\\rightmargin}
+ \\addtolength{\\leftmargin}{\\labelwidth}
+ \\addtolength{\\leftmargin}{\\labelsep}
+ \\renewcommand{\\makelabel}{\\optionlistlabel}}
+}{\\end{list}}
+\\newlength{\\lineblockindentation}
+\\setlength{\\lineblockindentation}{2.5em}
+\\newenvironment{lineblock}[1]
+{\\begin{list}{}
+ {\\setlength{\\partopsep}{\\parskip}
+ \\addtolength{\\partopsep}{\\baselineskip}
+ \\topsep0pt\\itemsep0.15\\baselineskip\\parsep0pt
+ \\leftmargin#1}
+ \\raggedright}
+{\\end{list}}
+% begin: floats for footnotes tweaking.
+\\setlength{\\floatsep}{0.5em}
+\\setlength{\\textfloatsep}{\\fill}
+\\addtolength{\\textfloatsep}{3em}
+\\renewcommand{\\textfraction}{0.5}
+\\renewcommand{\\topfraction}{0.5}
+\\renewcommand{\\bottomfraction}{0.5}
+\\setcounter{totalnumber}{50}
+\\setcounter{topnumber}{50}
+\\setcounter{bottomnumber}{50}
+% end floats for footnotes
+% some commands, that could be overwritten in the style file.
+\\newcommand{\\rubric}[1]{\\subsection*{~\\hfill {\\it #1} \\hfill ~}}
+\\newcommand{\\titlereference}[1]{\\textsl{#1}}
+% end of "some commands"
+"""
+
+totest = {}
+
+totest['table_of_contents'] = [
+# input
+["""\
+.. contents:: Table of Contents
+
+Title 1
+=======
+Paragraph 1.
+
+Title 2
+-------
+Paragraph 2.
+""",
+## # expected output
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+\\hypertarget{table-of-contents}{}
+\\pdfbookmark[0]{Table of Contents}{table-of-contents}
+\\subsubsection*{~\\hfill Table of Contents\\hfill ~}
+\\begin{list}{}{}
+\\item {} \\href{\\#title-1}{Title 1}
+\\begin{list}{}{}
+\\item {} \\href{\#title-2}{Title 2}
+
+\\end{list}
+
+\\end{list}
+
+
+
+%___________________________________________________________________________
+
+\\hypertarget{title-1}{}
+\\pdfbookmark[0]{Title 1}{title-1}
+\\section*{Title 1}
+
+Paragraph 1.
+
+
+%___________________________________________________________________________
+
+\\hypertarget{title-2}{}
+\\pdfbookmark[1]{Title 2}{title-2}
+\\subsection*{Title 2}
+
+Paragraph 2.
+
+\\end{document}
+"""],
+
+]
+
+
+totest['enumerated_lists'] = [
+# input
+["""\
+1. Item 1.
+2. Second to the previous item this one will explain
+
+ a) nothing.
+ b) or some other.
+
+3. Third is
+
+ (I) having pre and postfixes
+ (II) in roman numerals.
+""",
+# expected output
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+\\newcounter{listcnt1}
+\\begin{list}{\\arabic{listcnt1}.}
+{
+\\usecounter{listcnt1}
+\\setlength{\\rightmargin}{\\leftmargin}
+}
+\\item {}
+Item 1.
+
+\\item {}
+Second to the previous item this one will explain
+
+\\end{list}
+\\begin{quote}
+\\newcounter{listcnt2}
+\\begin{list}{\\alph{listcnt2})}
+{
+\\usecounter{listcnt2}
+\\setlength{\\rightmargin}{\\leftmargin}
+}
+\\item {}
+nothing.
+
+\\item {}
+or some other.
+
+\\end{list}
+\\end{quote}
+\\newcounter{listcnt3}
+\\begin{list}{\\arabic{listcnt3}.}
+{
+\\usecounter{listcnt3}
+\\addtocounter{listcnt3}{2}
+\\setlength{\\rightmargin}{\\leftmargin}
+}
+\\item {}
+Third is
+
+\\end{list}
+\\begin{quote}
+\\newcounter{listcnt4}
+\\begin{list}{(\\Roman{listcnt4})}
+{
+\\usecounter{listcnt4}
+\\setlength{\\rightmargin}{\\leftmargin}
+}
+\\item {}
+having pre and postfixes
+
+\\item {}
+in roman numerals.
+
+\\end{list}
+\\end{quote}
+
+\\end{document}
+"""],
+]
+
+# BUG: need to test for quote replacing if language is de (ngerman).
+
+totest['quote_mangling'] = [
+# input
+["""\
+Depending on language quotes are converted for latex.
+Expecting "en" here.
+
+Inside literal blocks quotes should be left untouched
+(use only two quotes in test code makes life easier for
+the python interpreter running the test)::
+
+ ""
+ This is left "untouched" also *this*.
+ ""
+
+.. parsed-literal::
+
+ should get "quotes" and *italics*.
+
+
+Inline ``literal "quotes"`` should be kept.
+""",
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+
+Depending on language quotes are converted for latex.
+Expecting ``en'' here.
+
+Inside literal blocks quotes should be left untouched
+(use only two quotes in test code makes life easier for
+the python interpreter running the test):
+\\begin{quote}{\\ttfamily \\raggedright \\noindent
+"{}"~\\\\
+This~is~left~"untouched"~also~*this*.~\\\\
+"{}"
+}\\end{quote}
+\\begin{quote}{\\ttfamily \\raggedright \\noindent
+should~get~"quotes"~and~\\emph{italics}.
+}\\end{quote}
+
+Inline \\texttt{literal "quotes"} should be kept.
+
+\\end{document}
+"""],
+]
+
+totest['table_caption'] = [
+# input
+["""\
+.. table:: Foo
+
+ +-----+-----+
+ | | |
+ +-----+-----+
+ | | |
+ +-----+-----+
+""",
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+
+\\begin{longtable}[c]{|p{0.07\locallinewidth}|p{0.07\locallinewidth}|}
+\\caption{Foo}\\\\
+\\hline
+ & \\\\
+\hline
+ & \\\\
+\hline
+\\end{longtable}
+
+\\end{document}
+"""],
+]
+
+# In "\\\n[" the "[" needs to be protected (otherwise it will be seen as an option to "\\").
+totest['brackett_protection'] = [
+# input
+["""\
+::
+
+ something before to get a end of line.
+ [
+
+ the empty line gets tested too
+ ]
+""",
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+\\begin{quote}{\\ttfamily \\raggedright \\noindent
+something~before~to~get~a~end~of~line.~\\\\
+{[}~\\\\
+~\\\\
+the~empty~line~gets~tested~too~\\\\
+{]}
+}\\end{quote}
+
+\\end{document}
+"""],
+]
+
+totest['raw'] = [
+["""\
+.. raw:: latex
+
+ \\noindent
+
+A paragraph.
+
+.. |sub| raw:: latex
+
+ (some raw text)
+
+Foo |sub|
+same paragraph.
+""",
+latex_head + """\
+\\title{}
+\\author{}
+\\date{}
+\\raggedbottom
+\\begin{document}
+
+\\setlength{\\locallinewidth}{\\linewidth}
+\\noindent
+A paragraph.
+
+Foo (some raw text)
+same paragraph.
+
+\\end{document}
+"""],
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_writers/test_null.py b/test/test_writers/test_null.py
new file mode 100755
index 000000000..da385e565
--- /dev/null
+++ b/test/test_writers/test_null.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test for Null writer.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.PublishTestSuite('null')
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['basic'] = [
+["""\
+This is a paragraph.
+""",
+None]
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')
diff --git a/test/test_writers/test_pseudoxml.py b/test/test_writers/test_pseudoxml.py
new file mode 100755
index 000000000..db8bed7cb
--- /dev/null
+++ b/test/test_writers/test_pseudoxml.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+# Author: Felix Wiemann
+# Contact: Felix_Wiemann@ososo.de
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Test for pseudo-XML writer.
+"""
+
+from __init__ import DocutilsTestSupport
+
+def suite():
+ s = DocutilsTestSupport.PublishTestSuite('pseudoxml')
+ s.generateTests(totest)
+ return s
+
+totest = {}
+
+totest['basic'] = [
+# input
+["""\
+This is a paragraph.
+
+----------
+
+This is another paragraph.
+
+A Section
+---------
+
+Foo.
+""",
+# output
+"""\
+<document source="<string>">
+ <paragraph>
+ This is a paragraph.
+ <transition>
+ <paragraph>
+ This is another paragraph.
+ <section ids="a-section" names="a\ section">
+ <title>
+ A Section
+ <paragraph>
+ Foo.
+"""]
+]
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='suite')