79 lines
2.7 KiB
Python
79 lines
2.7 KiB
Python
|
|
"""The DTD check, and the mapping from libxml2's messages to spec sections.
|
||
|
|
|
||
|
|
One test per message shape, so the mapping table in mews.lint stays pinned to
|
||
|
|
what libxml2 actually says.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from mews.lint import validate_bytes
|
||
|
|
|
||
|
|
# fixture name -> (section, level, code)
|
||
|
|
CASES = {
|
||
|
|
"script": ("4.1", "must", "dtd-element"),
|
||
|
|
"div": ("4.1", "must", "dtd-element"),
|
||
|
|
"sup": ("4.1", "must", "dtd-element"),
|
||
|
|
"style-element": ("5", "must", "dtd-styling"),
|
||
|
|
"style-attr": ("5", "must", "dtd-styling"),
|
||
|
|
"class-on-p": ("4.1", "must", "dtd-attribute"),
|
||
|
|
"img-width": ("4.1", "must", "dtd-attribute"),
|
||
|
|
"img-no-alt": ("4.1", "must", "dtd-required-attribute"),
|
||
|
|
"input-type-email": ("4.1", "must", "dtd-value"),
|
||
|
|
"nested-table": ("4.2", "must", "dtd-nested-table"),
|
||
|
|
"table-in-li": ("4.2", "must", "dtd-nested-table"),
|
||
|
|
"bad-body-class": ("5.3", "must", "dtd-variant"),
|
||
|
|
"empty-body": ("4.1", "must", "dtd-content"),
|
||
|
|
"head-link-before-meta": ("3.3", "must", "dtd-head"),
|
||
|
|
"link-bad-rel": ("3.3", "must", "link-rel"),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(("name", "expected"), CASES.items())
|
||
|
|
def test_dtd_failure_maps_to_its_section(fail_page, name, expected):
|
||
|
|
report = validate_bytes(fail_page(name))
|
||
|
|
section, level, code = expected
|
||
|
|
match = [f for f in report.findings if f.code == code]
|
||
|
|
assert match, f"{name}: no {code} finding in {[f.code for f in report.findings]}"
|
||
|
|
assert match[0].section == section
|
||
|
|
assert match[0].level == level
|
||
|
|
assert not report.conforms
|
||
|
|
|
||
|
|
|
||
|
|
def test_one_mistake_is_one_finding(fail_page):
|
||
|
|
"""A <script> makes libxml2 say three things; the author sees one."""
|
||
|
|
report = validate_bytes(fail_page("script"))
|
||
|
|
assert [f.code for f in report.findings] == ["dtd-element"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_findings_carry_a_line_number(fail_page):
|
||
|
|
report = validate_bytes(fail_page("div"))
|
||
|
|
assert report.findings[0].location.startswith("line ")
|
||
|
|
|
||
|
|
|
||
|
|
def test_messages_name_the_element(fail_page):
|
||
|
|
report = validate_bytes(fail_page("div"))
|
||
|
|
assert "<div>" in report.findings[0].message
|
||
|
|
|
||
|
|
|
||
|
|
def test_enumerated_values_come_from_the_dtd(fail_page):
|
||
|
|
report = validate_bytes(fail_page("input-type-email"))
|
||
|
|
message = report.findings[0].message
|
||
|
|
assert "text, password, checkbox, radio, submit, reset, hidden" in message
|
||
|
|
|
||
|
|
|
||
|
|
def test_unmapped_message_still_gets_a_section():
|
||
|
|
from mews.lint import _map_error
|
||
|
|
|
||
|
|
code, message = _map_error("Something libxml2 made up", set())
|
||
|
|
assert code == "dtd-other"
|
||
|
|
assert "Mews DTD" in message
|
||
|
|
|
||
|
|
|
||
|
|
def test_entities_the_doctype_defines_are_resolved(conforming):
|
||
|
|
report = validate_bytes(conforming(body="<p>a b—c</p>"))
|
||
|
|
assert report.conforms
|
||
|
|
|
||
|
|
|
||
|
|
def test_a_conforming_page_passes(conforming):
|
||
|
|
assert validate_bytes(conforming()).conforms
|