fix: ship the real DTD in the Pelican plugin

This commit is contained in:
randogoth 2026-10-11 20:55:07 +03:00
parent f54d350216
commit 884300f3cf
8 changed files with 483 additions and 74 deletions

View file

@ -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")