wapdown/tests/test_xhtmlmp.py
2026-09-26 13:08:50 +03:00

159 lines
6.7 KiB
Python

"""XHTML-MP emission: prolog, head, block mapping, and well-formedness."""
from __future__ import annotations
from xml.etree import ElementTree
import pytest
from wapdown.renderers.xhtmlmp.renderer import XHTML_PROLOG
TWO_SECTIONS = "Intro.\n\n{.card One}\nFirst.\n\n{.card Two}\nSecond.\n"
def parse(markup: str) -> ElementTree.Element:
"""Parse the page, proving it is well-formed XML.
ElementTree honours the DOCTYPE declaration without trying to fetch the
external DTD, so this never depends on a network round trip to
wapforum.org.
"""
return ElementTree.fromstring(markup)
class TestDocumentShape:
def test_prolog_and_doctype(self, render_xhtmlmp):
markup = render_xhtmlmp("Body.\n")
assert markup.startswith(XHTML_PROLOG)
assert 'PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"' in markup
def test_root_element_is_html(self, render_xhtmlmp):
# ElementTree namespace-qualifies the tag because of the xhtml xmlns.
assert parse(render_xhtmlmp("Body.\n")).tag == "{http://www.w3.org/1999/xhtml}html"
def test_output_is_well_formed(self, render_xhtmlmp):
parse(render_xhtmlmp(TWO_SECTIONS))
def test_no_carriage_returns(self, render_xhtmlmp):
assert "\r" not in render_xhtmlmp(TWO_SECTIONS)
def test_card_breaks_do_not_split_the_page(self, render_xhtmlmp):
# Cards are a WAP 1.x screen-budget concern; XHTML-MP renders one
# continuous page and a {.card} marker draws nothing of its own.
markup = render_xhtmlmp(TWO_SECTIONS)
assert markup.count("<html") == 1
assert "First." in markup and "Second." in markup
def test_title_is_escaped_into_head(self, render_xhtmlmp):
markup = render_xhtmlmp("Body.\n", title="Fish & Chips")
assert "<title>Fish &amp; Chips</title>" in markup
class TestBlockMapping:
@pytest.mark.parametrize(
("source", "expected"),
[
("Just text.\n", "<p>Just text.</p>"),
("> quoted\n", "<blockquote><p>quoted</p></blockquote>"),
("```\ncode\n```\n", "<pre>code</pre>"),
("---\n", "<hr/>"),
],
)
def test_blocks(self, render_xhtmlmp, source, expected):
assert expected in render_xhtmlmp(source)
@pytest.mark.parametrize("level", [1, 2, 3, 4, 5, 6])
def test_headings_use_real_heading_elements(self, render_xhtmlmp, level):
markup = render_xhtmlmp(f"{'#' * level} Title\n")
assert f"<h{level}>Title</h{level}>" in markup
assert "<big>" not in markup # no FIGlet/WML-style banner substitute
def test_heading_level_beyond_six_clamps(self, render_xhtmlmp):
# Markdown itself caps at h6, but a manually-crafted payload
# shouldn't be able to emit an invalid element name.
markup = render_xhtmlmp("###### Deep\n")
assert "<h6>Deep</h6>" in markup
def test_unordered_list(self, render_xhtmlmp):
markup = render_xhtmlmp("- a\n- b\n")
assert "<ul><li>a</li><li>b</li></ul>" in markup
def test_ordered_list(self, render_xhtmlmp):
markup = render_xhtmlmp("1. a\n2. b\n")
assert "<ol><li>a</li><li>b</li></ol>" in markup
def test_nested_list_is_spliced_into_parent_item(self, render_xhtmlmp):
markup = render_xhtmlmp("- a\n - nested\n- b\n")
# The sub-list must sit *inside* its parent <li>, not after it, or
# the result is not a valid nested list.
assert "<li>a<ul><li>nested</li></ul></li>" in markup
parsed = parse(f"<root>{markup[markup.index('<ul'):markup.index('</body>')]}</root>")
outer_items = parsed.find("ul").findall("li")
assert len(outer_items) == 2
assert outer_items[0].find("ul/li").text == "nested"
def test_blank_line_does_not_split_a_list(self, render_xhtmlmp):
# A loose Markdown list (blank line between items) is still one
# list, matching the WML renderer's own convention.
markup = render_xhtmlmp("- a\n\n- b\n")
assert markup.count("<ul>") == 1
assert "<li>a</li><li>b</li>" in markup
def test_paragraph_between_list_items_closes_the_list(self, render_xhtmlmp):
markup = render_xhtmlmp("- a\n\nText.\n\n- b\n")
assert markup.count("<ul>") == 2
def test_table(self, render_xhtmlmp):
markup = render_xhtmlmp("| A | B |\n| --- | --- |\n| 1 | 2 |\n")
assert "<table><tr><th>A</th><th>B</th></tr><tr><td>1</td><td>2</td></tr></table>" in markup
def test_table_is_not_wrapped_in_a_paragraph(self, render_xhtmlmp):
# Unlike WML, <table> is valid body-level content in XHTML-MP, so
# no <p> wrapper is needed (or wanted).
markup = render_xhtmlmp("| A |\n| --- |\n| 1 |\n")
assert "<p><table" not in markup
class TestInlineMapping:
def test_bold_and_italic(self, render_xhtmlmp):
markup = render_xhtmlmp("**bold** and *italic*\n")
assert "<strong>bold</strong>" in markup
assert "<em>italic</em>" in markup
def test_code_span_becomes_code_element(self, render_xhtmlmp):
markup = render_xhtmlmp("Some `code` here.\n")
assert "<code>code</code>" in markup
def test_link(self, render_xhtmlmp):
markup = render_xhtmlmp("[go](http://x.test/)\n")
assert '<a href="http://x.test/">go</a>' in markup
def test_link_label_may_carry_emphasis(self, render_xhtmlmp):
# Unlike WML, whose <a> content model is (#PCDATA | br | img)* and
# so strips emphasis from the label, XHTML-MP's <a> allows it.
markup = render_xhtmlmp("[**go** now](http://x.test/)\n")
assert '<a href="http://x.test/"><strong>go</strong> now</a>' in markup
def test_underscore_in_url_is_not_shredded_into_emphasis(self, render_xhtmlmp):
# Regression guard for the stash-before-emphasis ordering: without
# it, `/a_b_c` inside the URL would be read as `_b_` -> <em>b</em>.
markup = render_xhtmlmp("[link](/a_b_c)\n")
assert '<a href="/a_b_c">link</a>' in markup
def test_asterisk_in_url_is_not_shredded_into_emphasis(self, render_xhtmlmp):
markup = render_xhtmlmp("[link](/a*b*c)\n")
assert '<a href="/a*b*c">link</a>' in markup
def test_image(self, render_xhtmlmp):
markup = render_xhtmlmp("![alt text](pic.png)\n")
assert '<img src="pic.png" alt="alt text"/>' in markup
def test_dollar_sign_is_not_doubled(self, render_xhtmlmp):
# XHTML-MP has none of WML's '$' -> '$$' variable-substitution
# quirk; a literal dollar sign should pass through as one.
markup = render_xhtmlmp("Permit fee: $5\n")
assert "Permit fee: $5" in markup
def test_entities_are_escaped(self, render_xhtmlmp):
markup = render_xhtmlmp('Fish & chips < > "\n')
assert "Fish &amp; chips &lt; &gt; &quot;" in markup