95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
|
|
"""Inline markup mapping and WML's escaping rules."""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from wapdown.renderers.wml.inline import escape_wml, process_inline
|
||
|
|
|
||
|
|
|
||
|
|
class TestEscaping:
|
||
|
|
def test_xml_significant_characters(self):
|
||
|
|
assert escape_wml('a & b < c > d "e"') == "a & b < c > d "e""
|
||
|
|
|
||
|
|
def test_dollar_is_doubled(self):
|
||
|
|
# WML uses $ to introduce a variable substitution, so a literal $
|
||
|
|
# must be written $$ or the device eats the following word.
|
||
|
|
assert escape_wml("Permit fee: $5") == "Permit fee: $$5"
|
||
|
|
|
||
|
|
def test_ampersand_escaped_before_other_entities(self):
|
||
|
|
assert escape_wml("<") == "<"
|
||
|
|
assert "&lt;" not in escape_wml("a & b")
|
||
|
|
|
||
|
|
|
||
|
|
class TestEmphasis:
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
("source", "expected"),
|
||
|
|
[
|
||
|
|
("**bold**", "<b>bold</b>"),
|
||
|
|
("__bold__", "<b>bold</b>"),
|
||
|
|
("*italic*", "<i>italic</i>"),
|
||
|
|
("_italic_", "<i>italic</i>"),
|
||
|
|
("~~struck~~", "struck"), # no WML equivalent, markers dropped
|
||
|
|
("`code`", "code"),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
def test_mapping(self, source, expected):
|
||
|
|
assert process_inline(source) == expected
|
||
|
|
|
||
|
|
def test_code_span_contents_are_not_reinterpreted(self):
|
||
|
|
assert process_inline("`a *b* c`") == "a *b* c"
|
||
|
|
|
||
|
|
|
||
|
|
class TestLinks:
|
||
|
|
def test_basic_link(self):
|
||
|
|
assert process_inline("[call](tel:+15555550123)") == (
|
||
|
|
'<a href="tel:+15555550123">call</a>'
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_underscores_in_url_survive(self):
|
||
|
|
# Regression: emphasis patterns used to run before LINK_RE, so
|
||
|
|
# UNDERLINE_EM_RE shredded `v1_2_3` into `v1<i>2</i>3` inside the href.
|
||
|
|
result = process_inline("[notes](https://example.com/v1_2_3/x.html)")
|
||
|
|
assert result == '<a href="https://example.com/v1_2_3/x.html">notes</a>'
|
||
|
|
assert "<i>" not in result
|
||
|
|
|
||
|
|
def test_asterisks_in_url_survive(self):
|
||
|
|
result = process_inline("[log](https://ci.example.com/job/a*b*c/log)")
|
||
|
|
assert "a*b*c" in result
|
||
|
|
assert "<i>" not in result
|
||
|
|
|
||
|
|
def test_label_emphasis_is_stripped_not_translated(self):
|
||
|
|
# WML 1.3 declares <a> as (#PCDATA | br | img)*: there is nowhere
|
||
|
|
# valid to put a <b> inside a link label.
|
||
|
|
assert process_inline("[**go** now](http://x.test/)") == (
|
||
|
|
'<a href="http://x.test/">go now</a>'
|
||
|
|
)
|
||
|
|
|
||
|
|
def test_url_is_escaped_for_attribute_use(self):
|
||
|
|
assert process_inline("[q](http://x.test/?a=1&b=2)") == (
|
||
|
|
'<a href="http://x.test/?a=1&b=2">q</a>'
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestImages:
|
||
|
|
def test_keep_is_the_default(self):
|
||
|
|
assert process_inline("") == '<img src="map.png" alt="Map"/>'
|
||
|
|
|
||
|
|
def test_alt_policy_replaces_non_wbmp(self, capsys):
|
||
|
|
assert process_inline("", images="alt") == "Map"
|
||
|
|
assert "non-WBMP" in capsys.readouterr().err
|
||
|
|
|
||
|
|
def test_drop_policy_removes_non_wbmp(self, capsys):
|
||
|
|
assert process_inline("", images="drop") == ""
|
||
|
|
assert "dropped" in capsys.readouterr().err
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("policy", ["alt", "drop"])
|
||
|
|
def test_wbmp_always_survives(self, policy):
|
||
|
|
result = process_inline("", images=policy)
|
||
|
|
assert result == '<img src="icon.wbmp" alt="Icon"/>'
|
||
|
|
|
||
|
|
def test_wbmp_detected_past_a_query_string(self):
|
||
|
|
assert '<img' in process_inline("", images="drop")
|
||
|
|
|
||
|
|
def test_image_is_not_parsed_as_a_link(self):
|
||
|
|
assert process_inline("").startswith("<img")
|