重构为函数式通用 Markdown 修改库
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import FrozenInstanceError
|
||||
from typing import cast
|
||||
|
||||
import pytest
|
||||
|
||||
from mdpolish import DocumentSnapshot, Modifier, ModifierContractError, ProposedChange
|
||||
|
||||
|
||||
def no_changes(snapshot: DocumentSnapshot) -> tuple[ProposedChange, ...]:
|
||||
return ()
|
||||
|
||||
|
||||
def test_plain_function_and_mapping_parameters_create_immutable_modifier() -> None:
|
||||
source_parameters: dict[str, object] = {
|
||||
"enabled": True,
|
||||
"nested": {"count": 2},
|
||||
"values": ["a", "b"],
|
||||
}
|
||||
|
||||
modifier = Modifier(
|
||||
modifier_id="example.rule",
|
||||
version="1.2.3",
|
||||
parameters=source_parameters,
|
||||
applicability="处理虚构测试输入;排除其他文本。",
|
||||
propose=no_changes,
|
||||
)
|
||||
source_parameters["enabled"] = False
|
||||
|
||||
assert modifier.propose is no_changes
|
||||
assert modifier.parameters == (
|
||||
("enabled", True),
|
||||
("nested", (("count", 2),)),
|
||||
("values", ("a", "b")),
|
||||
)
|
||||
with pytest.raises(FrozenInstanceError):
|
||||
modifier.version = "2.0.0" # type: ignore[misc]
|
||||
|
||||
|
||||
def test_normalized_parameters_are_sorted_and_validated() -> None:
|
||||
modifier = Modifier(
|
||||
modifier_id="example.normalized",
|
||||
version="1.0.0",
|
||||
parameters=(("z", 1), ("a", ("x", 2))),
|
||||
applicability="处理虚构测试输入。",
|
||||
propose=no_changes,
|
||||
)
|
||||
|
||||
assert modifier.parameters == (("a", ("x", 2)), ("z", 1))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("modifier_id", ["", "Upper", "has space", ".leading", "trailing."])
|
||||
def test_invalid_modifier_id_is_rejected(modifier_id: str) -> None:
|
||||
with pytest.raises(ModifierContractError, match="modifier_id"):
|
||||
Modifier(
|
||||
modifier_id=modifier_id,
|
||||
version="1.0.0",
|
||||
parameters=(),
|
||||
applicability="测试。",
|
||||
propose=no_changes,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("version", ["", "1", "1.0", "v1.0.0", "01.0.0", "1.0.0-beta"])
|
||||
def test_invalid_version_is_rejected(version: str) -> None:
|
||||
with pytest.raises(ModifierContractError, match="version"):
|
||||
Modifier(
|
||||
modifier_id="example.rule",
|
||||
version=version,
|
||||
parameters=(),
|
||||
applicability="测试。",
|
||||
propose=no_changes,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"parameters",
|
||||
[
|
||||
{"bad": {1}},
|
||||
{"bad": float("inf")},
|
||||
(("duplicate", 1), ("duplicate", 2)),
|
||||
(("bad", object()),),
|
||||
("not-a-pair",),
|
||||
],
|
||||
)
|
||||
def test_invalid_parameters_are_rejected(parameters: object) -> None:
|
||||
with pytest.raises(ModifierContractError):
|
||||
Modifier(
|
||||
modifier_id="example.rule",
|
||||
version="1.0.0",
|
||||
parameters=parameters, # type: ignore[arg-type]
|
||||
applicability="测试。",
|
||||
propose=no_changes,
|
||||
)
|
||||
|
||||
|
||||
def test_empty_applicability_and_non_callable_proposal_are_rejected() -> None:
|
||||
with pytest.raises(ModifierContractError, match="applicability"):
|
||||
Modifier(
|
||||
modifier_id="example.rule",
|
||||
version="1.0.0",
|
||||
parameters=(),
|
||||
applicability=" ",
|
||||
propose=no_changes,
|
||||
)
|
||||
with pytest.raises(ModifierContractError, match="callable"):
|
||||
Modifier(
|
||||
modifier_id="example.rule",
|
||||
version="1.0.0",
|
||||
parameters=(),
|
||||
applicability="测试。",
|
||||
propose=cast(object, None), # type: ignore[arg-type]
|
||||
)
|
||||
Reference in New Issue
Block a user