#! /usr/bin/env python3 # $Id: test_html4css1.py 10102 2025-04-23 15:54:44Z milde $ # Author: reggie dugard # Copyright: This module has been placed in the public domain. """Test HTML4 writer output ("fragment" part). This is the document body (not HTML ). """ from pathlib import Path 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.parsers.rst.directives.images import PIL from docutils.utils.code_analyzer import with_pygments from docutils.writers import html4css1 if with_pygments: import pygments if tuple(map(int, pygments.__version__.split('.')[: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() # Pillow/PIL is optional: if PIL: SCALING_OUTPUT = 'style="width: 32.0px; height: 32.0px;" ' else: SCALING_OUTPUT = '' class Html4WriterPublishPartsTestCase(unittest.TestCase): """Test case for "html4css1" writer via the publish_parts() interface.""" maxDiff = None def test_publish(self): for name, (settings_overrides, cases) in totest.items(): if name == 'syntax_highlight' and not with_pygments: self.skipTest('syntax highlight requires pygments') 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 """, '

Simple String

\n', ], ["""\ Simple String with *markup* """, '

Simple String with markup

\n', ], ["""\ Simple String with an even simpler ``inline literal`` """, '

Simple String with an even simpler inline literal

\n', ], ["""\ A simple `anonymous reference`__ __ http://www.test.com/test_url """, '

A simple anonymous reference

\n', ], ["""\ One paragraph. Two paragraphs. """, """\

One paragraph.

Two paragraphs.

""", ], ["""\ A simple `named reference`_ with stuff in between the reference and the target. .. _`named reference`: http://www.test.com/test_url """, """\

A simple named reference with stuff in between the reference and the target.

""", ], ["""\ .. [CIT2022] A citation. """, """\
[CIT2022]A citation.
""", ], ]) totest['no_title_promotion'] = ({'doctitle_xform': False}, [ ["""\ +++++ Title +++++ Not A Subtitle ============== Some stuff Section ------- Some more stuff Another Section ............... And even more stuff """, """\

Title

Not A Subtitle

Some stuff

Section

Some more stuff

Another Section

And even more stuff

""", ], ["""\ * bullet * list """, """\ """, ], ["""\ .. table:: :align: right :width: 320 +-----+-----+ | 1 | 2 | +-----+-----+ | 3 | 4 | +-----+-----+ """, """\
1 2
3 4
""", ], ["""\ Not a docinfo. :This: .. _target: is :a: :simple: :field: list """, """\

Not a docinfo.

This:

is

a:
simple:
field:list
""", ], ["""\ Not a docinfo. :This is: a :simple field list with loooong field: names """, """\

Not a docinfo.

This is:a
simple field list with loooong field:
 names
""", ], ["""\ Not a docinfo. .. class:: field-indent-200 :This: is a :simple: field list with custom indent. """, """\

Not a docinfo.

This:is a
simple:field list with custom indent.
""", ], ["""\ Not a docinfo. .. class:: field-indent-200uf :This: is a :simple: field list without custom indent, because the unit "uf" is invalid. """, """\

Not a docinfo.

This:is a
simple:field list without custom indent, because the unit "uf" is invalid.
""", ], ["""\ .. figure:: dummy.png :figname: fig:dummy The figure's caption. A legend. The legend's second paragraph. """, """\
dummy.png

The figure's caption.

A legend.

The legend's second paragraph.

""", ], ["""\ .. figure:: dummy.png The figure's caption, no legend. """, """\
dummy.png

The figure's caption, no legend.

""", ], ["""\ .. figure:: dummy.png .. A legend without caption. """, """\
dummy.png
A legend without caption.
""", ], ["""\ .. figure:: dummy.png No caption nor legend. """, """\
dummy.png

No caption nor legend.

""", ], [f"""\ .. include:: {DATA_ROOT}/multiple-term-definition.xml :parser: xml """, """\
New in Docutils 0.22

A definition list item may contain several terms with optional classifier(s).

However, there is currently no corresponding reStructuredText syntax.

term 2a
term 2b
definition 2
term 3a : classifier 3a : classifier 3aa
term 3b : classifier 3b
definition 3
""", ], ]) 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 """, """\

Lazy loading by default, overridden by :loading: option ("cannot embed" warning ignored).

dummy.png dummy.png
dummy.png
dummy.png
""", ], ]) totest['root_prefix'] = ({'root_prefix': ROOT_PREFIX, 'image_loading': 'embed', 'warning_stream': '', }, [ ["""\ .. image:: /data/blue%20square.png :scale: 100% .. figure:: /data/blue%20square.png """, f"""\ /data/blue%20square.png
/data/blue%20square.png
""" ], ]) 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 """, """\

Two footnotes [1] [2] and two citations [once] [twice].

The latter are referenced a second time [2] [twice].

[1]referenced once
[2]referenced twice
[once]citation referenced once
[twice]citation referenced twice
""", ], ]) totest['syntax_highlight'] = ({'syntax_highlight': 'short', }, [ ["""\ .. code:: shell cat < cat <<EOF Hello World EOF """, ], ["""\ .. role:: shell(code) :language: shell :shell:`cat <cat <<EOF Hello World EOF

""", ], ]) totest['system_messages'] = ({'math_output': 'mathml', 'warning_stream': '', }, [ # No warning with HTML4 ("embed" error is silently ignored). ["""\ .. image:: https://dummy.png :loading: embed """, """\ https://dummy.png """, ], # No error with HTML4 (silently ignored) [f"""\ .. image:: {DATA_ROOT.as_uri()}/circle-broken.svg :loading: embed """, f"""\ {DATA_ROOT.as_uri()}/circle-broken.svg """ ], [r"""Broken :math:`\sin \my`. """, """\

Broken \\sin \\my.

System Message: WARNING/2 (<string>, line 1)

Unknown LaTeX command "\\my".
"""], ]) totest['system_messages-PIL'] = ({'math_output': 'mathml', 'warning_stream': '', }, [ ["""\ .. image:: dummy.png :scale: 100% :loading: embed """, """\ dummy.png """, ], ["""\ .. image:: dummy.mp4 :scale: 100% """, """\ dummy.mp4 """, ], ["""\ .. image:: https://dummy.png :scale: 100% :loading: embed """, """\ 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% """, """\ dummy.png dummy.mp4 """, ], [f"""\ .. image:: {DATA_ROOT.as_uri()}/circle-broken.svg :loading: embed """, f"""\ {DATA_ROOT.as_uri()}/circle-broken.svg """], [r'Broken :math:`\sin \my`.', '

Broken \\sin \\my.

\n' ], ]) if __name__ == '__main__': unittest.main()