python-peps/pep_sphinx_extensions/tests/pep_lint/test_headers.py

409 lines
12 KiB
Python

import check_peps # NoQA: inserted into sys.modules in conftest.py
import pytest
@pytest.mark.parametrize(
("test_input", "expected"),
[
# capitalisation
("Header:", "Header"),
("header:", "header"),
("hEADER:", "hEADER"),
("hEaDeR:", "hEaDeR"),
# trailing spaces
("Header: ", "Header"),
("Header: ", "Header"),
("Header: \t", "Header"),
# trailing content
("Header: Text", "Header"),
("Header: 123", "Header"),
("Header: !", "Header"),
# separators
("Hyphenated-Header:", "Hyphenated-Header"),
],
)
def test_header_pattern(test_input, expected):
assert check_peps.HEADER_PATTERN.match(test_input)[1] == expected
@pytest.mark.parametrize(
"test_input",
[
# trailing content
"Header:Text",
"Header:123",
"Header:!",
# colon position
"Header",
"Header : ",
"Header :",
"SemiColonHeader;",
# separators
"Underscored_Header:",
"Spaced Header:",
"Plus+Header:",
],
)
def test_header_pattern_no_match(test_input):
assert check_peps.HEADER_PATTERN.match(test_input) is None
def test_validate_required_headers():
found_headers = dict.fromkeys(
("PEP", "Title", "Author", "Status", "Type", "Created")
)
warnings = [
warning for (_, warning) in check_peps._validate_required_headers(found_headers)
]
assert warnings == [], warnings
def test_validate_required_headers_missing():
found_headers = dict.fromkeys(("PEP", "Title", "Author", "Type"))
warnings = [
warning for (_, warning) in check_peps._validate_required_headers(found_headers)
]
assert warnings == [
"Must have required header: Status",
"Must have required header: Created",
], warnings
def test_validate_required_headers_order():
found_headers = dict.fromkeys(
("PEP", "Title", "Sponsor", "Author", "Type", "Status", "Replaces", "Created")
)
warnings = [
warning for (_, warning) in check_peps._validate_required_headers(found_headers)
]
assert warnings == [
"Headers must be in PEP 12 order. Correct order: PEP, Title, Author, Sponsor, Status, Type, Created, Replaces"
], warnings
@pytest.mark.parametrize(
"line",
[
"!",
"The Zen of Python",
"A title that is exactly 79 characters long, but shorter than 80 characters long",
],
)
def test_validate_title(line: str):
warnings = [warning for (_, warning) in check_peps._validate_title(1, line)]
assert warnings == [], warnings
def test_validate_title_blank():
warnings = [warning for (_, warning) in check_peps._validate_title(1, "-" * 80)]
assert warnings == ["PEP title must be less than 80 characters"], warnings
def test_validate_title_too_long():
warnings = [warning for (_, warning) in check_peps._validate_title(1, "")]
assert warnings == ["PEP must have a title"], warnings
@pytest.mark.parametrize(
"line",
[
"Accepted",
"Active",
"April Fool!",
"Deferred",
"Draft",
"Final",
"Provisional",
"Rejected",
"Superseded",
"Withdrawn",
],
)
def test_validate_status_valid(line: str):
warnings = [warning for (_, warning) in check_peps._validate_status(1, line)]
assert warnings == [], warnings
@pytest.mark.parametrize(
"line",
[
"Standards Track",
"Informational",
"Process",
"accepted",
"active",
"april fool!",
"deferred",
"draft",
"final",
"provisional",
"rejected",
"superseded",
"withdrawn",
],
)
def test_validate_status_invalid(line: str):
warnings = [warning for (_, warning) in check_peps._validate_status(1, line)]
assert warnings == ["Status must be a valid PEP status"], warnings
@pytest.mark.parametrize(
"line",
[
"Standards Track",
"Informational",
"Process",
],
)
def test_validate_type_valid(line: str):
warnings = [warning for (_, warning) in check_peps._validate_type(1, line)]
assert warnings == [], warnings
@pytest.mark.parametrize(
"line",
[
"standards track",
"informational",
"process",
"Accepted",
"Active",
"April Fool!",
"Deferred",
"Draft",
"Final",
"Provisional",
"Rejected",
"Superseded",
"Withdrawn",
],
)
def test_validate_type_invalid(line: str):
warnings = [warning for (_, warning) in check_peps._validate_type(1, line)]
assert warnings == ["Type must be a valid PEP type"], warnings
@pytest.mark.parametrize(
("line", "expected_warnings"),
[
# valid entries
("Governance", set()),
("Packaging", set()),
("Typing", set()),
("Release", set()),
("Governance, Packaging", set()),
("Packaging, Typing", set()),
# duplicates
("Governance, Governance", {"duplicates"}),
("Release, Release", {"duplicates"}),
("Packaging, Packaging", {"duplicates"}),
("Spam, Spam", {"duplicates", "valid"}),
("lobster, lobster", {"duplicates", "capitalisation", "valid"}),
("governance, governance", {"duplicates", "capitalisation"}),
# capitalisation
("governance", {"capitalisation"}),
("packaging", {"capitalisation"}),
("typing", {"capitalisation"}),
("release", {"capitalisation"}),
("Governance, release", {"capitalisation"}),
# validity
("Spam", {"valid"}),
("lobster", {"capitalisation", "valid"}),
# sorted
("Packaging, Governance", {"sorted"}),
("Typing, Release", {"sorted"}),
("Release, Governance", {"sorted"}),
("spam, packaging", {"capitalisation", "valid", "sorted"}),
],
# call str() on each parameterised value in the test ID.
ids=str,
)
def test_validate_topic(line: str, expected_warnings: set):
warnings = [warning for (_, warning) in check_peps._validate_topic(1, line)]
found_warnings = set()
if "duplicates" in expected_warnings:
found_warnings.add("duplicates")
expected = "Topic must not contain duplicates"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "capitalisation" in expected_warnings:
found_warnings.add("capitalisation")
expected = "Topic must be properly capitalised (Title Case)"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "valid" in expected_warnings:
found_warnings.add("valid")
expected = "Topic must be for a valid sub-index"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "sorted" in expected_warnings:
found_warnings.add("sorted")
expected = "Topic must be sorted lexicographically"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if expected_warnings == set():
assert warnings == [], warnings
assert found_warnings == expected_warnings
def test_validate_content_type_valid():
warnings = [
warning for (_, warning) in check_peps._validate_content_type(1, "text/x-rst")
]
assert warnings == [], warnings
@pytest.mark.parametrize(
"line",
[
"text/plain",
"text/markdown",
"text/csv",
"text/rtf",
"text/javascript",
"text/html",
"text/xml",
],
)
def test_validate_content_type_invalid(line: str):
warnings = [warning for (_, warning) in check_peps._validate_content_type(1, line)]
assert warnings == ["Content-Type must be 'text/x-rst'"], warnings
@pytest.mark.parametrize(
"line",
[
"0, 1, 8, 12, 20,",
"101, 801,",
"3099, 9999",
],
)
def test_validate_pep_references(line: str):
warnings = [
warning for (_, warning) in check_peps._validate_pep_references(1, line)
]
assert warnings == [], warnings
@pytest.mark.parametrize(
"line",
[
"0,1,8, 12, 20,",
"101,801,",
"3099, 9998,9999",
],
)
def test_validate_pep_references_separators(line: str):
warnings = [
warning for (_, warning) in check_peps._validate_pep_references(1, line)
]
assert warnings == [
"PEP references must be separated by comma-spaces (', ')"
], warnings
@pytest.mark.parametrize(
("line", "expected_warnings"),
[
# valid entries
("1.0, 2.4, 2.7, 2.8, 3.0, 3.1, 3.4, 3.7, 3.11, 3.14", set()),
("2.x", set()),
("3.x", set()),
("3.0.1", set()),
# segments
("", {"segments"}),
("1", {"segments"}),
("1.2.3.4", {"segments"}),
# major
("0.0", {"major"}),
("4.0", {"major"}),
("9.0", {"major"}),
# minor number
("3.a", {"minor numeric"}),
("3.spam", {"minor numeric"}),
("3.0+", {"minor numeric"}),
("3.0-9", {"minor numeric"}),
("9.Z", {"major", "minor numeric"}),
# minor leading zero
("3.01", {"minor zero"}),
("0.00", {"major", "minor zero"}),
# micro empty
("3.x.1", {"micro empty"}),
("9.x.1", {"major", "micro empty"}),
# micro leading zero
("3.3.0", {"micro zero"}),
("3.3.00", {"micro zero"}),
("3.3.01", {"micro zero"}),
("3.0.0", {"micro zero"}),
("3.00.0", {"minor zero", "micro zero"}),
("0.00.0", {"major", "minor zero", "micro zero"}),
# micro number
("3.0.a", {"micro numeric"}),
("0.3.a", {"major", "micro numeric"}),
],
# call str() on each parameterised value in the test ID.
ids=str,
)
def test_validate_python_version(line: str, expected_warnings: set):
warnings = [
warning for (_, warning) in check_peps._validate_python_version(1, line)
]
found_warnings = set()
if "segments" in expected_warnings:
found_warnings.add("segments")
expected = f"Python-Version must have two or three segments: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "major" in expected_warnings:
found_warnings.add("major")
expected = f"Python-Version major part must be 1, 2, or 3: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "minor numeric" in expected_warnings:
found_warnings.add("minor numeric")
expected = f"Python-Version minor part must be numeric: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "minor zero" in expected_warnings:
found_warnings.add("minor zero")
expected = f"Python-Version minor part must not have leading zeros: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "micro empty" in expected_warnings:
found_warnings.add("micro empty")
expected = (
f"Python-Version micro part must be empty if minor part is 'x': {line}"
)
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "micro zero" in expected_warnings:
found_warnings.add("micro zero")
expected = f"Python-Version micro part must not have leading zeros: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if "micro numeric" in expected_warnings:
found_warnings.add("micro numeric")
expected = f"Python-Version micro part must be numeric: {line}"
matching = [w for w in warnings if w == expected]
assert matching == [expected], warnings
if expected_warnings == set():
assert warnings == [], warnings
assert found_warnings == expected_warnings