fix: ship the real DTD in the Pelican plugin
This commit is contained in:
parent
f54d350216
commit
884300f3cf
8 changed files with 483 additions and 74 deletions
|
|
@ -21,7 +21,15 @@ THEME = TESTS / "theme"
|
|||
|
||||
BASE_SETTINGS = {
|
||||
"ARTICLE_PATHS": [],
|
||||
"MARKDOWN": {"output_format": "xhtml"},
|
||||
# Tables and definition lists are both in the Mews subset, and both need
|
||||
# an extension turned on before python-markdown will emit them.
|
||||
"MARKDOWN": {
|
||||
"output_format": "xhtml",
|
||||
"extension_configs": {
|
||||
"markdown.extensions.tables": {},
|
||||
"markdown.extensions.def_list": {},
|
||||
},
|
||||
},
|
||||
"PAGE_PATHS": ["pages"],
|
||||
"PAGE_SAVE_AS": "{slug}.xhtml",
|
||||
"PAGE_URL": "{slug}.xhtml",
|
||||
|
|
|
|||
35
pelican-mews/tests/fixtures/structure/expected.xhtml
vendored
Normal file
35
pelican-mews/tests/fixtures/structure/expected.xhtml
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Structure</title>
|
||||
<meta name="mews-profile" content="0.1"/>
|
||||
<meta name="viewport" content="width=device-width"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/mews-0.1.css"/></head>
|
||||
<body>
|
||||
<p>A table, an ordered list and a definition list: everything the placeholder
|
||||
DTD used to throw away.</p>
|
||||
<table>
|
||||
<tr>
|
||||
|
||||
<th>Network</th>
|
||||
<th>Band</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td>GSM 900</td>
|
||||
<td>900 MHz</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second</li>
|
||||
</ol>
|
||||
<dl>
|
||||
<dt>Term</dt>
|
||||
<dd>Its meaning</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
16
pelican-mews/tests/fixtures/structure/input.md
vendored
Normal file
16
pelican-mews/tests/fixtures/structure/input.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Title: Structure
|
||||
Slug: page
|
||||
Date: 2026-10-11
|
||||
|
||||
A table, an ordered list and a definition list: everything the placeholder
|
||||
DTD used to throw away.
|
||||
|
||||
| Network | Band |
|
||||
| --- | --- |
|
||||
| GSM 900 | 900 MHz |
|
||||
|
||||
1. First
|
||||
2. Second
|
||||
|
||||
Term
|
||||
: Its meaning
|
||||
|
|
@ -18,7 +18,7 @@ PACKAGE = "pelican.plugins.mews"
|
|||
STRICT_OVERRIDES = {"MEWS_STRICT": True}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir"])
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir", "structure"])
|
||||
def test_written_page_matches_expected(tmp_path, case):
|
||||
"""The written page matches the fixture, whatever was stripped."""
|
||||
overrides = {"MEWS_CSS_DIR": "style"} if case == "cssdir" else {}
|
||||
|
|
@ -28,7 +28,7 @@ def test_written_page_matches_expected(tmp_path, case):
|
|||
assert normalize(page) == normalize(expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir"])
|
||||
@pytest.mark.parametrize("case", ["basic", "strip", "cssdir", "structure"])
|
||||
def test_css_is_copied(tmp_path, case):
|
||||
"""The bundled stylesheet lands under the configured directory."""
|
||||
overrides = {"MEWS_CSS_DIR": "style"} if case == "cssdir" else {}
|
||||
|
|
@ -81,13 +81,28 @@ def test_parallel_output_folder(tmp_path):
|
|||
assert not (output / "css").exists()
|
||||
|
||||
|
||||
# Section 4.1 of the specification keeps this many elements. The plugin lists
|
||||
# none of them itself; the DTD is the only place they are written down.
|
||||
SECTION_4_1_ELEMENTS = 51
|
||||
|
||||
|
||||
def test_allowlist_is_read_from_the_dtd():
|
||||
"""The subset comes from the DTD, not from code."""
|
||||
dtd = files(PACKAGE).joinpath("dtd", "mews.dtd").read_text(encoding="utf-8")
|
||||
allowlist = parse_allowlist(dtd)
|
||||
assert allowlist["p"] == {"id", "title", "xml:lang"}
|
||||
assert allowlist["html"] == {"dir", "id", "lang", "title", "xml:lang", "xmlns"}
|
||||
assert len(allowlist) == SECTION_4_1_ELEMENTS
|
||||
# The common attributes, including the two the profile adds to XHTML-MP.
|
||||
assert allowlist["p"] == {"dir", "id", "lang", "title", "xml:lang"}
|
||||
# html takes no id or title; section 4.1 gives it these four and no more.
|
||||
assert allowlist["html"] == {"dir", "lang", "xml:lang", "xmlns"}
|
||||
assert "href" in allowlist["a"]
|
||||
# class is permitted on body and nowhere else (section 5.3).
|
||||
assert "class" in allowlist["body"]
|
||||
assert not [
|
||||
name for name, attrs in allowlist.items() if name != "body" and "class" in attrs
|
||||
]
|
||||
# The parts the placeholder DTD lacked, which the plugin was stripping.
|
||||
assert {"table", "td", "ol", "dl", "form", "input", "address"} <= set(allowlist)
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("uv") is None, reason="uv is not installed")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue