SF.net SVN: docutils:[9916] trunk/docutils/test/test_writers

milde--- via Docutils-checkins <[email protected]>
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 9916
          http://sourceforge.net/p/docutils/code/9916
Author:   milde
Date:     2024-08-21 13:45:27 +0000 (Wed, 21 Aug 2024)
Log Message:
-----------
Refactor HTML4 writer tests.

New test script "test_html4css1.py":
Split basic output tests (which happen to use the "fragment" returned
by `publish_parts()` to get the interesting part of the output)
from other tests of `publish_parts()`

Really test all returned parts in "test_html4css1_parts.py".

Cf. "Refactor HTML5 writer tests".

Modified Paths:
--------------
    trunk/docutils/test/test_writers/test_html4css1_parts.py

Added Paths:
-----------
    trunk/docutils/test/test_writers/test_html4css1.py

Added: trunk/docutils/test/test_writers/test_html4css1.py
===================================================================
--- trunk/docutils/test/test_writers/test_html4css1.py	                        (rev 0)
+++ trunk/docutils/test/test_writers/test_html4css1.py	2024-08-21 13:45:27 UTC (rev 9916)
@@ -0,0 +1,596 @@
+#! /usr/bin/env python3
+
+# $Id$
+# Author: reggie dugard <[email protected]>
+# Copyright: This module has been placed in the public domain.
+
+"""Test HTML4 writer output ("fragment" part).
+
+This is the document body (not HTML <body>).
+"""
+
+from pathlib import Path
+import re
+import sys
+import unittest
+
+if __name__ == '__main__':
+    # prepend the "docutils root" to the Python library path
+    # so we import the local `docutils` package.
+    sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
+
+import docutils
+import docutils.core
+from docutils.utils.code_analyzer import with_pygments
+from docutils.writers import html4css1
+
+if with_pygments:
+    import pygments
+    _pv = re.match(r'^([0-9]+)\.([0-9]*)', pygments.__version__)
+    if (int(_pv[1]), int(_pv[2])) >= (2, 14):
+        # pygments output changed in version 2.14
+        with_pygments = False
+
+# TEST_ROOT is ./test/ from the docutils root
+TEST_ROOT = Path(__file__).parents[1]
+DATA_ROOT = TEST_ROOT / 'data'
+ROOT_PREFIX = (TEST_ROOT / 'functional/input').as_posix()
+
+
+class Html5WriterPublishPartsTestCase(unittest.TestCase):
+    """Test case for HTML5 writer via the publish_parts() interface."""
+
+    maxDiff = None
+
+    def test_publish(self):
+        if not with_pygments:
+            del totest['syntax_highlight']
+        for name, (settings_overrides, cases) in totest.items():
+            for casenum, (case_input, case_expected) in enumerate(cases):
+                with self.subTest(id=f'totest[{name!r}][{casenum}]'):
+                    parts = docutils.core.publish_parts(
+                        source=case_input,
+                        writer=html4css1.Writer(),
+                        settings_overrides={
+                            '_disable_config': True,
+                            'strict_visitor': True,
+                            'stylesheet_path': '',
+                            'section_self_link': True,
+                            **settings_overrides,
+                        }
+                    )
+                    self.assertEqual(case_expected, parts['body'])
+
+
+totest = {}
+
+totest['standard'] = ({}, [
+["""\
+Simple String
+""",
+'<p>Simple String</p>\n',
+],
+["""\
+Simple String with *markup*
+""",
+'<p>Simple String with <em>markup</em></p>\n',
+],
+["""\
+Simple String with an even simpler ``inline literal``
+""",
+'<p>Simple String with an even simpler <tt class="docutils literal">inline literal</tt></p>\n',
+],
+["""\
+A simple `anonymous reference`__
+
+__ http://www.test.com/test_url
+""",
+'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n',
+],
+["""\
+One paragraph.
+
+Two paragraphs.
+""",
+"""\
+<p>One paragraph.</p>
+<p>Two paragraphs.</p>
+""",
+],
+["""\
+A simple `named reference`_ with stuff in between the
+reference and the target.
+
+.. _`named reference`: http://www.test.com/test_url
+""",
+"""\
+<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the
+reference and the target.</p>
+""",
+],
+["""\
+.. [CIT2022] A citation.
+""",
+"""\
+<table class="docutils citation" frame="void" id="cit2022" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label">[CIT2022]</td><td>A citation.</td></tr>
+</tbody>
+</table>
+""",
+],
+])
+
+
+totest['no_title_promotion'] = ({'doctitle_xform': False}, [
+["""\
++++++
+Title
++++++
+
+Not A Subtitle
+==============
+
+Some stuff
+
+Section
+-------
+
+Some more stuff
+
+Another Section
+...............
+
+And even more stuff
+""",
+"""\
+<div class="section" id="title">
+<h1>Title</h1>
+<div class="section" id="not-a-subtitle">
+<h2>Not A Subtitle</h2>
+<p>Some stuff</p>
+<div class="section" id="section">
+<h3>Section</h3>
+<p>Some more stuff</p>
+<div class="section" id="another-section">
+<h4>Another Section</h4>
+<p>And even more stuff</p>
+</div>
+</div>
+</div>
+</div>
+""",
+],
+["""\
+* bullet
+* list
+""",
+"""\
+<ul class="simple">
+<li>bullet</li>
+<li>list</li>
+</ul>
+""",
+],
+["""\
+.. table::
+   :align: right
+
+   +-----+-----+
+   |  1  |  2  |
+   +-----+-----+
+   |  3  |  4  |
+   +-----+-----+
+""",
+"""\
+<table border="1" class="docutils align-right">
+<colgroup>
+<col width="50%" />
+<col width="50%" />
+</colgroup>
+<tbody valign="top">
+<tr><td>1</td>
+<td>2</td>
+</tr>
+<tr><td>3</td>
+<td>4</td>
+</tr>
+</tbody>
+</table>
+""",
+],
+["""\
+Not a docinfo.
+
+:This: .. _target:
+
+       is
+:a:
+:simple:
+:field: list
+""",
+"""\
+<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>
+""",
+],
+["""\
+Not a docinfo.
+
+:This is: a
+:simple field list with loooong field: names
+""",
+"""\
+<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 is:</th><td class="field-body">a</td>
+</tr>
+<tr class="field"><th class="field-name" colspan="2">simple field list with loooong field:</th></tr>
+<tr class="field"><td>&nbsp;</td><td class="field-body">names</td>
+</tr>
+</tbody>
+</table>
+""",
+],
+["""\
+Not a docinfo.
+
+.. class:: field-indent-200
+
+:This: is a
+:simple: field list with custom indent.
+""",
+"""\
+<p>Not a docinfo.</p>
+<table class="field-indent-200 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">is a</td>
+</tr>
+<tr class="field"><th class="field-name">simple:</th><td class="field-body">field list with custom indent.</td>
+</tr>
+</tbody>
+</table>
+""",
+],
+["""\
+Not a docinfo.
+
+.. class:: field-indent-200uf
+
+:This: is a
+:simple: field list without custom indent,
+         because the unit "uf" is invalid.
+""",
+"""\
+<p>Not a docinfo.</p>
+<table class="field-indent-200uf 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">is a</td>
+</tr>
+<tr class="field"><th class="field-name">simple:</th><td class="field-body">field list without custom indent,
+because the unit &quot;uf&quot; is invalid.</td>
+</tr>
+</tbody>
+</table>
+""",
+],
+["""\
+.. figure:: dummy.png
+
+   The figure's caption.
+
+   A legend.
+
+   The legend's second paragraph.
+""",
+"""\
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+<p class="caption">The figure's caption.</p>
+<div class="legend">
+<p>A legend.</p>
+<p>The legend's second paragraph.</p>
+</div>
+</div>
+""",
+],
+["""\
+.. figure:: dummy.png
+
+   The figure's caption, no legend.
+""",
+"""\
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+<p class="caption">The figure's caption, no legend.</p>
+</div>
+""",
+],
+["""\
+.. figure:: dummy.png
+
+   ..
+
+   A legend without caption.
+""",
+"""\
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+<div class="legend">
+A legend without caption.</div>
+</div>
+""",
+],
+["""\
+.. figure:: dummy.png
+
+No caption nor legend.
+""",
+"""\
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+</div>
+<p>No caption nor legend.</p>
+""",
+],
+[f"""\
+.. include:: {DATA_ROOT}/multiple-term-definition.xml
+   :parser: xml
+""",
+"""\
+<dl class="docutils">
+<dt>New in Docutils 0.22</dt>
+<dd><p class="first">A definition list item may contain several
+terms with optional classifier(s).</p>
+<p class="last">However, there is currently no corresponding
+reStructuredText syntax.</p>
+</dd>
+<dt>term 2a</dt>
+<dt>term 2b</dt>
+<dd>definition 2</dd>
+<dt>term 3a <span class="classifier-delimiter">:</span> <span class="classifier">classifier 3a</span> <span class="classifier-delimiter">:</span> <span class="classifier">classifier 3aa</span><dt>term 3b <span class="classifier-delimiter">:</span> <span class="classifier">classifier 3b</span></dt>
+<dd>definition 3</dd>
+</dl>
+""",
+],
+])
+
+
+totest['lazy_loading'] = ({'image_loading': 'lazy',
+                           'report_level': 4}, [
+["""\
+Lazy loading by default, overridden by :loading: option
+("cannot embed" warning ignored).
+
+.. image:: dummy.png
+.. image:: dummy.png
+   :loading: link
+.. figure:: dummy.png
+.. figure:: dummy.png
+   :loading: embed
+""",
+"""\
+<p>Lazy loading by default, overridden by :loading: option
+(&quot;cannot embed&quot; warning ignored).</p>
+<img alt="dummy.png" src="dummy.png" />
+<img alt="dummy.png" src="dummy.png" />
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+</div>
+<div class="figure">
+<img alt="dummy.png" src="dummy.png" />
+</div>
+""",
+],
+])
+
+
+totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX,
+                          'image_loading': 'embed',
+                          'warning_stream': '',
+                          }, [
+["""\
+.. image:: /data/blue%20square.png
+   :scale: 100%
+.. figure:: /data/blue%20square.png
+""",
+"""\
+<img alt="/data/blue%20square.png" src="/data/blue%20square.png" style="width: 32.0px; height: 32.0px;" />
+<div class="figure">
+<img alt="/data/blue%20square.png" src="/data/blue%20square.png" />
+</div>
+"""
+],
+])
+
+
+totest['no_backlinks'] = ({'footnote_backlinks': False}, [
+
+["""\
+Two footnotes [#f1]_ [#f2]_ and two citations [once]_ [twice]_.
+
+The latter are referenced a second time [#f2]_ [twice]_.
+
+.. [#f1] referenced once
+.. [#f2] referenced twice
+.. [once] citation referenced once
+.. [twice] citation referenced twice
+""",
+"""\
+<p>Two footnotes <a class="footnote-reference" href="#f1" id="footnote-reference-1">[1]</a> <a class="footnote-reference" href="#f2" id="footnote-reference-2">[2]</a> and two citations <a class="citation-reference" href="#once" id="citation-reference-1">[once]</a> <a class="citation-reference" href="#twice" id="citation-reference-2">[twice]</a>.</p>
+<p>The latter are referenced a second time <a class="footnote-reference" href="#f2" id="footnote-reference-3">[2]</a> <a class="citation-reference" href="#twice" id="citation-reference-3">[twice]</a>.</p>
+<table class="docutils footnote" frame="void" id="f1" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label">[1]</td><td>referenced once</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="f2" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label">[2]</td><td>referenced twice</td></tr>
+</tbody>
+</table>
+<table class="docutils citation" frame="void" id="once" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label">[once]</td><td>citation referenced once</td></tr>
+</tbody>
+</table>
+<table class="docutils citation" frame="void" id="twice" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label">[twice]</td><td>citation referenced twice</td></tr>
+</tbody>
+</table>
+""",
+],
+])
+
+
+totest['syntax_highlight'] = ({'syntax_highlight': 'short',
+                               }, [
+["""\
+.. code:: shell
+
+    cat <<EOF
+    Hello World
+    EOF
+""",
+"""\
+<pre class="code shell literal-block">
+cat <span class="s">&lt;&lt;EOF
+Hello World
+EOF</span>
+</pre>
+""",
+],
+["""\
+.. role:: shell(code)
+   :language: shell
+
+:shell:`cat <<EOF Hello World EOF`
+""",
+"""\
+<p><code class="shell">cat <span class="s">&lt;&lt;EOF Hello World EOF</span></code></p>
+""",
+],
+])
+
+
+totest['system_messages'] = ({'math_output': 'mathml',
+                              'warning_stream': '',
+                              }, [
+# No warning with HTML4 ("embed" error is silently ignored).
+["""\
+.. image:: https://dummy.png
+   :loading: embed
+""",
+"""\
+<img alt="https://dummy.png" src="https://dummy.png" />
+""",
+],
+# No error with HTML4 (silently ignored)
+[f"""\
+.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg
+   :loading: embed
+""",
+"""\
+<object data="file:///usr/local/src/docutils-git-svn/docutils/test/data/circle-broken.svg" type="image/svg+xml">file:///usr/local/src/docutils-git-svn/docutils/test/data/circle-broken.svg</object>
+"""
+],
+[r"""Broken :math:`\sin \my`.
+""",
+"""\
+<p>Broken <span class="math problematic">\\sin \\my</span>.</p>
+<div class="system-message">
+<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils">&lt;string&gt;</tt>, line 1)</p>
+Unknown LaTeX command &quot;\\my&quot;.</div>
+"""],
+])
+
+totest['system_messages-PIL'] = ({'math_output': 'mathml',
+                                  'warning_stream': '',
+                                  }, [
+["""\
+.. image:: dummy.png
+   :scale: 100%
+   :loading: embed
+""",
+"""\
+<img alt="dummy.png" src="dummy.png" />
+""",
+],
+["""\
+.. image:: dummy.mp4
+   :scale: 100%
+""",
+"""\
+<object data="dummy.mp4" type="video/mp4">dummy.mp4</object>
+""",
+],
+["""\
+.. image:: https://dummy.png
+   :scale: 100%
+   :loading: embed
+""",
+"""\
+<img alt="https://dummy.png" src="https://dummy.png" />
+""",
+],
+])
+
+totest['no_system_messages'] = ({'math_output': 'mathml',
+                                 'report_level': 4,
+                                 'warning_stream': '',
+                                 }, [
+["""\
+.. image:: dummy.png
+   :scale: 100%
+   :loading: embed
+
+.. image:: dummy.mp4
+   :scale: 100%
+""",
+"""\
+<img alt="dummy.png" src="dummy.png" />
+<object data="dummy.mp4" type="video/mp4">dummy.mp4</object>
+""",
+],
+[f"""\
+.. image:: {DATA_ROOT.as_uri()}/circle-broken.svg
+   :loading: embed
+""",
+"""\
+<object data="file:///usr/local/src/docutils-git-svn/docutils/test/data/circle-broken.svg" type="image/svg+xml">file:///usr/local/src/docutils-git-svn/docutils/test/data/circle-broken.svg</object>
+"""],
+[r'Broken :math:`\sin \my`.',
+'<p>Broken <tt class="math">\\sin \\my</tt>.</p>\n'
+],
+])
+
+
+if __name__ == '__main__':
+    unittest.main()


Property changes on: trunk/docutils/test/test_writers/test_html4css1.py
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Author Date Id Revision
\ No newline at end of property
Modified: trunk/docutils/test/test_writers/test_html4css1_parts.py
===================================================================
--- trunk/docutils/test/test_writers/test_html4css1_parts.py	2024-08-21 13:45:18 UTC (rev 9915)
+++ trunk/docutils/test/test_writers/test_html4css1_parts.py	2024-08-21 13:45:27 UTC (rev 9916)
@@ -5,11 +5,9 @@
 # Copyright: This module has been placed in the public domain.
 
 """
-Test for fragment code in HTML writer.
+Test `core.publish_parts()`__ with the html4css1 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.
+__ https://docutils.sourceforge.io/docs/api/publisher.html#publish-parts
 """
 
 from pathlib import Path
@@ -23,142 +21,145 @@
 
 import docutils
 import docutils.core
-from docutils.parsers.rst.directives.images import PIL
 from docutils.writers import html4css1
 
-ROOT_PREFIX = (Path(__file__).parent.parent/'functional'/'input').as_posix()
-if PIL:
-    SCALING_OUTPUT = 'style="width: 32.0px; height: 32.0px;" '
-else:
-    SCALING_OUTPUT = ''
+# TEST_ROOT is ./test/ from the docutils root
+TEST_ROOT = Path(__file__).parents[1]
+DATA_ROOT = TEST_ROOT / 'data'
+ROOT_PREFIX = (TEST_ROOT / 'functional/input').as_posix()
 
 
-class Html4WriterPublishPartsTestCase(unittest.TestCase):
-    """
-    Test case for HTML writer via the publish_parts interface.
-    """
+# Parts returned by `publish_parts()` for the HTML5 writer by default:
+#   * empty input string
+#   * default configuration settings.
+# See format_parts() below for the substitution of unresolved format markers.
+default_parts = {
+    'body': '{fragment}',
+    'body_pre_docinfo': '',
+    'body_prefix': '</head>\n<body>\n{header}<div class="document">\n',
+    'body_suffix': '</div>\n{footer}</body>\n</html>\n',
+    'docinfo': '',
+    'encoding': 'utf-8',
+    'errors': 'xmlcharrefreplace',
+    'footer': '',
+    'fragment': '',
+    'head': '{meta}<title>{metatitle}</title>\n',
+    'head_prefix':
+        '<?xml version="1.0" encoding="utf-8"?>\n'
+        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
+        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
+        '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
+        '<head>\n',
+    'header': '',
+    'html_body': '{header}<div class="document">\n{fragment}</div>\n{footer}',
+    'html_head': '{meta}<title>{metatitle}</title>\n',
+    'html_prolog':
+        '<?xml version="1.0" encoding="%s"?>\n'
+        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
+        ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n',
+    'html_subtitle': '',
+    'html_title': '',
+    'meta': '<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n'
+            f'<meta name="generator" content="Docutils {docutils.__version__}: https://docutils.sourceforge.io/" />\n',
+    'stylesheet': '',
+    'subtitle': '',
+    'title': '',
+    'version': f'{docutils.__version__}',
+    'whole':
+        '{head_prefix}\n'
+        '{head}\n'
+        '{stylesheet}\n'
+        '{body_prefix}\n'
+        '{body_pre_docinfo}\n'
+        '{docinfo}\n'
+        '{body}\n'
+        '{body_suffix}\n',
+    }
 
-    maxDiff = None
 
-    def test_publish(self):
-        for name, (settings_overrides, cases) in totest.items():
-            for casenum, (case_input, case_expected) in enumerate(cases):
-                with self.subTest(id=f'totest[{name!r}][{casenum}]'):
-                    parts = docutils.core.publish_parts(
-                        source=case_input,
-                        writer=html4css1.Writer(),
-                        settings_overrides={
-                            '_disable_config': True,
-                            'strict_visitor': True,
-                            'stylesheet_path': '',
-                            **settings_overrides,
-                        }
-                    )
-                    # if the formatted output is a just single fragment,
-                    # compare the text directly for a nicer diff on failure
-                    formatted = self.format_output(parts)
-                    if len(formatted) == 1 and 'fragment' in formatted:
-                        fragment = formatted['fragment']
-                        self.assertEqual(case_expected, fragment)
-                    else:
-                        self.assertEqual(case_expected, formatted)
+def format_parts(parts):
+    # fill in part values that depend on other parts
+    # https://docutils.sourceforge.io/docs/api/publisher.html#html4-writer
 
-    standard_content_type_template = ('<meta http-equiv="Content-Type"'
-                                      ' content="text/html; charset=%s" />\n')
-    standard_generator_template = (
-        '<meta name="generator"'
-        f' content="Docutils {docutils.__version__}: '
-        f'https://docutils.sourceforge.io/" />\n')
-    standard_html_meta_value = (
-        standard_content_type_template
-        + standard_generator_template)
-    standard_meta_value = standard_html_meta_value % 'utf-8'
-    standard_html_prolog = (
-        '<?xml version="1.0" encoding="%s"?>\n'
-        '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" '
-        '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n')
-    standard_html_body_template = '<div class="document">\n%s</div>\n'
+    # metadata title: either the visible title or document['source']
+    metatitle = parts['title'] or '&lt;string&gt;'
 
-    def format_output(self, parts):
-        """Minimize & standardize the output."""
-        # remove redundant parts & uninteresting parts:
-        del parts['whole']
-        assert parts['body'] == parts['fragment']
-        del parts['body']
-        del parts['body_pre_docinfo']
-        del parts['body_prefix']
-        del parts['body_suffix']
-        del parts['head']
-        del parts['head_prefix']
-        del parts['encoding']
-        del parts['errors']
-        del parts['version']
-        # 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_head'] = parts['html_head'].replace(
-            '...<title>&lt;string&gt;</title>\n', '')
-        parts['html_prolog'] = parts['html_prolog'].replace(
-            self.standard_html_prolog, '')
-        parts['html_body'] = parts['html_body'].replace(
-            self.standard_html_body_template % parts['fragment'], '')
-        # remove empty keys and return
-        return {k: v for k, v in parts.items() if v}
+    # "html_head" leaves the encoding unresolved, as "%s":
+    parts['html_head'] = parts['html_head'].format(metatitle=metatitle,
+                                                   **parts)
+    # now resolve encoding:
+    try:
+        parts['meta'] = parts['meta'] % parts['encoding']
+    except TypeError:  # charset-<meta> missing if encoding is 'unicode'
+        pass
+    parts['head'] = parts['head'].format(metatitle=metatitle, **parts)
+    parts['body_prefix'] = parts['body_prefix'].format(**parts)
+    parts['body'] = parts['body'].format(**parts)
+    parts['body_suffix'] = parts['body_suffix'].format(**parts)
+    parts['html_body'] = parts['html_body'].format(**parts)
+    # newlines are stripped when parts are used to expand the template file
+    parts['whole'] = parts['whole'].format(**{k: v.rstrip('\n')
+                                              for k, v in parts.items()})
+    return parts
 
 
-totest = {}
+class Html5WriterPublishPartsTestCase(unittest.TestCase):
+    """Test HTML5 writer `publish_parts()` interface."""
 
-totest['title_promotion'] = ({}, [
-["""\
-Simple String
-""",
-'<p>Simple String</p>\n',
-],
-["""\
-Simple String with *markup*
-""",
-'<p>Simple String with <em>markup</em></p>\n',
-],
-["""\
-Simple String with an even simpler ``inline literal``
-""",
-'<p>Simple String with an even simpler <tt class="docutils literal">inline literal</tt></p>\n',
-],
-["""\
-Simple ``inline\xA0literal`` with NBSP
-""",
-'<p>Simple <tt class="docutils literal">inline&nbsp;literal</tt> with NBSP</p>\n',
-],
-["""\
-A simple `anonymous reference`__
+    maxDiff = None
 
-__ http://www.test.com/test_url
-""",
-'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n',
-],
-["""\
-One paragraph.
+    def test_publish_parts(self):
+        for name, (settings_overrides, cases) in totest.items():
+            for casenum, (case_input, expected_parts) in enumerate(cases):
+                _stgns = {'_disable_config': True,
+                          'strict_visitor': True,
+                          'stylesheet_path': '',
+                          'section_self_link': True,
+                          **settings_overrides,
+                          }
+                parts = docutils.core.publish_parts(source=case_input,
+                                                    writer=html4css1.Writer(),
+                                                    settings_overrides=_stgns,
+                                                    )
+                expected = format_parts(default_parts | expected_parts)
+                for key in parts.keys():
+                    with self.subTest(id=f'totest[{name!r}][{casenum}][{key}]'):
+                        self.assertEqual(f'{expected[key]}',
+                                         f'{parts[key]}')
 
-Two paragraphs.
-""",
-"""\
-<p>One paragraph.</p>
-<p>Two paragraphs.</p>
-""",
-],
-["""\
-A simple `named reference`_ with stuff in between the
-reference and the target.
 
-.. _`named reference`: http://www.test.com/test_url
-""",
-"""\
-<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the
-reference and the target.</p>
-""",
-],
-["""\
+totest = {}
+
+totest['standard'] = ({}, [
+    ['',  # empty input string
+     {}   # results in default parts
+     ],
+    ['Simple String with *markup*',
+     {'fragment': '<p>Simple String with <em>markup</em></p>\n'}
+     ],
+    ['.. header:: custom document header\n\n'
+     'A paragraph.',
+     {'header': '<div class="header">\ncustom document header\n'
+                '<hr class="header"/>\n</div>\n',
+      'body_prefix': '</head>\n'
+                     '<body>\n'
+                     '<div class="header">\n'
+                     'custom document header\n'
+                     '<hr class="header"/>\n'
+                     '</div>\n'
+                     '<div class="document">\n',
+      'fragment': '<p>A paragraph.</p>\n',
+      }
+     ],
+    ['.. footer:: custom document footer\n\n'
+     'A paragraph.',
+     {'footer': '<div class="footer">\n'
+                '<hr class="footer" />\n'
+                'custom document footer\n</div>\n',
+      'fragment': '<p>A paragraph.</p>\n',
+      }
+     ],
+    ["""\
 +++++
 Title
 +++++
@@ -178,7 +179,10 @@
 
 And even more stuff
 """,
-{'fragment': """\
+    {'body_pre_docinfo': '<h1 class="title">Title</h1>\n'
+                         '<h2 class="subtitle" id="subtitle">Subtitle</h2>\n',
+     'body_prefix': '</head>\n<body>\n<div class="document" id="title">\n',
+     'fragment': """\
 <p>Some stuff</p>
 <div class="section" id="section">
 <h1>Section</h1>
@@ -189,7 +193,8 @@
 </div>
 </div>
 """,
- 'html_body': """<div class="document" id="title">
+     'html_body': """\
+<div class="document" id="title">
 <h1 class="title">Title</h1>
 <h2 class="subtitle" id="subtitle">Subtitle</h2>
 <p>Some stuff</p>
@@ -203,13 +208,12 @@
 </div>
 </div>
 """,
- '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'
-}],
-["""\
+     'html_subtitle': '<h2 class="subtitle" id="subtitle">Subtitle</h2>\n',
+     'html_title': '<h1 class="title">Title</h1>\n',
+     'subtitle': 'Subtitle',
+     'title': 'Title'
+     }],
+    ["""\
 +++++
 Title
 +++++
@@ -218,7 +222,10 @@
 
 Some stuff
 """,
-{'docinfo': """<table class="docinfo" frame="void" rules="none">
+    {'body_pre_docinfo': '<h1 class="title">Title</h1>\n',
+     'body_prefix': '</head>\n<body>\n<div class="document" id="title">\n',
+     'docinfo': """\
+<table class="docinfo" frame="void" rules="none">
 <col class="docinfo-name" />
 <col class="docinfo-content" />
 <tbody valign="top">
@@ -227,8 +234,9 @@
 </tbody>
 </table>
 """,
- 'fragment': '<p>Some stuff</p>\n',
- 'html_body': """<div class="document" id="title">
+     '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" />
@@ -241,50 +249,14 @@
 <p>Some stuff</p>
 </div>
 """,
- 'html_head': """...<meta name="author" content="me" />
-<title>Title</title>
-""",
- 'html_title': '<h1 class="title">Title</h1>\n',
- 'meta': '<meta name="author" content="me" />\n',
- 'title': 'Title'
-}]
-])
+     'html_title': '<h1 class="title">Title</h1>\n',
+     'meta': default_parts['meta'] + '<meta name="author" content="me" />\n',
+     'title': 'Title'
+     }],
+    ])
 
 totest['no_title_promotion'] = ({'doctitle_xform': False}, [
-["""\
-Simple String
-""",
-'<p>Simple String</p>\n',
-],
-["""\
-Simple String with *markup*
-""",
-'<p>Simple String with <em>markup</em></p>\n',
-],
-["""\
-Simple String with an even simpler ``inline literal``
-""",
-'<p>Simple String with an even simpler <tt class="docutils literal">inline literal</tt></p>\n',
-],
-["""\
-A simple `anonymous reference`__
-
-__ http://www.test.com/test_url
-""",
-'<p>A simple <a class="reference external" href="http://www.test.com/test_url">anonymous reference</a></p>\n',
-],
-["""\
-A simple `named reference`_ with stuff in between the
-reference and the target.
-
-.. _`named reference`: http://www.test.com/test_url
-""",
-"""\
-<p>A simple <a class="reference external" href="http://www.test.com/test_url">named reference</a> with stuff in between the
-reference and the target.</p>
-""",
-],
-["""\
+    ["""\
 +++++
 Title
 +++++
@@ -304,7 +276,7 @@
 
 And even more stuff
 """,
-"""\
+     {'fragment': """\
 <div class="section" id="title">
 <h1>Title</h1>
 <div class="section" id="not-a-subtitle">
@@ -320,109 +292,25 @@
 </div>
 </div>
 </div>
-""",
-],
-["""\
-* bullet
-* list
-""",
-"""\
-<ul class="simple">
-<li>bullet</li>
-<li>list</li>
-</ul>
-""",
-],
-["""\
-.. table::
-   :align: right
+"""},
+     ],
+    ])
 
-   +-----+-----+
-   |  1  |  2  |
-   +-----+-----+
-   |  3  |  4  |
-   +-----+-----+
-""",
-"""\
-<table border="1" class="docutils align-right">
-<colgroup>
-<col width="50%" />
-<col width="50%" />
-</colgroup>
-<tbody valign="top">
-<tr><td>1</td>
-<td>2</td>
-</tr>
-<tr><td>3</td>
-<td>4</td>
-</tr>
-</tbody>
-</table>
-""",
-],
-["""\
-Not a docinfo.
+totest['unknown-encoding'] = ({'output_encoding': 'unicode'}, [
+    ['Simple String\n',
+     {'encoding': 'unicode',
+      'fragment': '<p>Simple String</p>\n',
+      'head_prefix':
+          '<?xml version="1.0"?>\n'
+          '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
+          ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n'
+          '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
+          '<head>\n',
+      'html_head': f'{default_parts["meta"]}<title>{{metatitle}}</title>\n',
+      'meta': f'<meta name="generator" content="Docutils {docutils.__version__}: https://docutils.sourceforge.io/" />\n',
+      }],
+    ])
 
-:This: .. _target:
 
-       is
-:a:
-:simple:
-:field: list
-""",
-"""\
-<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>
-""",
-],
-["""\
-Not a docinfo.
-
-:This is: a
-:simple field list with loooong field: names
-""",
-"""\
-<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 is:</th><td class="field-body">a</td>
-</tr>
-<tr class="field"><th class="field-name" colspan="2">simple field list with loooong field:</th></tr>
-<tr class="field"><td>&nbsp;</td><td class="field-body">names</td>
-</tr>
-</tbody>
-</table>
-""",
-],
-])
-
-totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX}, [
-
-["""\
-.. image:: /data/blue%20square.png
-   :scale: 100%
-""",
-'<img alt="/data/blue%20square.png"'
-f' src="/data/blue%20square.png" {SCALING_OUTPUT}/>\n',
-],
-])
-
-
 if __name__ == '__main__':
     unittest.main()

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.