重构为函数式通用 Markdown 修改库

This commit is contained in:
2026-08-26 15:33:37 +08:00
parent 1abf72ccb1
commit bb0507db30
89 changed files with 1589 additions and 14850 deletions
+25 -25
View File
@@ -3,17 +3,17 @@ from __future__ import annotations
import pytest
from mdpolish import (
ComponentInfo,
DocumentSnapshot,
EditValidationError,
ModifierInfo,
ProposedChange,
TextEdit,
TextSpan,
apply_component_batch,
apply_modifier_batch,
)
COMPONENT = ComponentInfo(
component_id="test.component",
MODIFIER = ModifierInfo(
modifier_id="test.modifier",
version="1.2.3",
parameters=(),
applicability="测试精确文本编辑,只处理测试字符串,排除其他输入。",
@@ -38,22 +38,22 @@ def test_applies_insert_delete_and_replace() -> None:
delete_snapshot = DocumentSnapshot("abc")
replace_snapshot = DocumentSnapshot("abc")
inserted = apply_component_batch(
inserted = apply_modifier_batch(
insert_snapshot,
(make_proposal(insert_snapshot, make_edit(insert_snapshot, 1, 1, "X")),),
COMPONENT,
MODIFIER,
0,
)
deleted = apply_component_batch(
deleted = apply_modifier_batch(
delete_snapshot,
(make_proposal(delete_snapshot, make_edit(delete_snapshot, 1, 2, "")),),
COMPONENT,
MODIFIER,
0,
)
replaced = apply_component_batch(
replaced = apply_modifier_batch(
replace_snapshot,
(make_proposal(replace_snapshot, make_edit(replace_snapshot, 1, 2, "X")),),
COMPONENT,
MODIFIER,
0,
)
@@ -71,7 +71,7 @@ def test_multiple_edits_apply_backwards_but_report_in_source_order() -> None:
reason="normalize two locations",
)
applied = apply_component_batch(snapshot, (proposal,), COMPONENT, 3)
applied = apply_modifier_batch(snapshot, (proposal,), MODIFIER, 3)
assert applied.snapshot.markdown == "AbcdF"
assert [change.span.start for change in applied.changes] == [0, 4]
@@ -82,7 +82,7 @@ def test_multiple_edits_apply_backwards_but_report_in_source_order() -> None:
}
assert {change.reason for change in applied.changes} == {"normalize two locations"}
assert [change.edit_index for change in applied.changes] == [1, 0]
assert all(change.component_position == 3 for change in applied.changes)
assert all(change.modifier_position == 3 for change in applied.changes)
def test_adjacent_nonempty_ranges_are_allowed() -> None:
@@ -93,7 +93,7 @@ def test_adjacent_nonempty_ranges_are_allowed() -> None:
make_edit(snapshot, 2, 4, "D"),
)
applied = apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
applied = apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
assert applied.snapshot.markdown == "AD"
@@ -107,7 +107,7 @@ def test_overlapping_ranges_fail_without_changing_snapshot() -> None:
)
with pytest.raises(EditValidationError, match="conflicting"):
apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
assert snapshot.markdown == "abcdef"
assert snapshot.sha256 == DocumentSnapshot("abcdef").sha256
@@ -119,7 +119,7 @@ def test_duplicate_edits_fail_explicitly() -> None:
proposal = make_proposal(snapshot, edit, edit)
with pytest.raises(EditValidationError, match="duplicate"):
apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
def test_distinct_insert_points_are_allowed() -> None:
@@ -130,7 +130,7 @@ def test_distinct_insert_points_are_allowed() -> None:
make_edit(snapshot, 3, 3, "Y"),
)
applied = apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
applied = apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
assert applied.snapshot.markdown == "aXbcYd"
@@ -144,7 +144,7 @@ def test_same_insert_point_conflicts() -> None:
)
with pytest.raises(EditValidationError, match="conflicting"):
apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
@pytest.mark.parametrize("insert_position", [1, 2, 3])
@@ -157,7 +157,7 @@ def test_insert_at_start_inside_or_end_of_nonempty_range_conflicts(insert_positi
)
with pytest.raises(EditValidationError, match="conflicting"):
apply_component_batch(snapshot, (proposal,), COMPONENT, 0)
apply_modifier_batch(snapshot, (proposal,), MODIFIER, 0)
def test_stale_hash_out_of_range_and_expected_text_mismatch_fail() -> None:
@@ -166,34 +166,34 @@ def test_stale_hash_out_of_range_and_expected_text_mismatch_fail() -> None:
stale = make_proposal(original, make_edit(original, 0, 1, "A"))
with pytest.raises(EditValidationError, match="stale"):
apply_component_batch(current, (stale,), COMPONENT, 0)
apply_modifier_batch(current, (stale,), MODIFIER, 0)
out_of_range_edit = TextEdit(current.sha256, TextSpan(2, 5), "dxx", "D")
out_of_range = make_proposal(current, out_of_range_edit)
with pytest.raises(EditValidationError, match="outside"):
apply_component_batch(current, (out_of_range,), COMPONENT, 0)
apply_modifier_batch(current, (out_of_range,), MODIFIER, 0)
mismatch_edit = TextEdit(current.sha256, TextSpan(0, 1), "z", "A")
mismatch = make_proposal(current, mismatch_edit)
with pytest.raises(EditValidationError, match="expected_text"):
apply_component_batch(current, (mismatch,), COMPONENT, 0)
apply_modifier_batch(current, (mismatch,), MODIFIER, 0)
def test_conflict_across_proposals_rejects_whole_component_batch() -> None:
def test_conflict_across_proposals_rejects_whole_modifier_batch() -> None:
snapshot = DocumentSnapshot("abcdef")
first = make_proposal(snapshot, make_edit(snapshot, 0, 3, "X"), reason="first")
second = make_proposal(snapshot, make_edit(snapshot, 2, 4, "Y"), reason="second")
with pytest.raises(EditValidationError, match="conflicting"):
apply_component_batch(snapshot, (first, second), COMPONENT, 0)
apply_modifier_batch(snapshot, (first, second), MODIFIER, 0)
assert snapshot.markdown == "abcdef"
def test_empty_component_batch_keeps_same_snapshot_and_records_nothing() -> None:
def test_empty_modifier_batch_keeps_same_snapshot_and_records_nothing() -> None:
snapshot = DocumentSnapshot("abc")
applied = apply_component_batch(snapshot, (), COMPONENT, 0)
applied = apply_modifier_batch(snapshot, (), MODIFIER, 0)
assert applied.snapshot is snapshot
assert applied.changes == ()