124 lines
4.8 KiB
Python
124 lines
4.8 KiB
Python
"""探索清单形状校验纯函数:顺序、身份、类型与来源绑定的确定性拒绝;离线不连库。"""
|
||
|
||
from dataclasses import replace
|
||
|
||
import pytest
|
||
|
||
from muse.上下文.接口 import 上下文错误, 探索条目, 校验清单, 记录探索
|
||
from muse.任务运行.接口 import 工具来源, 工具结果
|
||
|
||
范围 = {
|
||
"work_id": "work-a",
|
||
"as_of": 2,
|
||
"source_ids": ["doc-1", "plan-1", "fact-lin"],
|
||
"documents": [
|
||
{
|
||
"chapter_id": "ch-1",
|
||
"branch_id": "main",
|
||
"revision": 1,
|
||
"document_id": "doc-1",
|
||
"document_hash": "hash-doc-1",
|
||
"position": 1,
|
||
}
|
||
],
|
||
"directory_revision": 3,
|
||
"authorized_by": "author-a",
|
||
"run_purpose": "production",
|
||
"content_purpose": "generation",
|
||
"target_plan": {
|
||
"chapter_id": "ch-3",
|
||
"plan_id": "plan-1",
|
||
"revision": 1,
|
||
"content_hash": "hash-plan-1",
|
||
},
|
||
"facts": {"system_revision": 5},
|
||
}
|
||
|
||
读取结果 = 工具结果(
|
||
内容={"chapter_id": "ch-1", "text": "林深停在码头"},
|
||
来源=(
|
||
工具来源("doc-1", "1", "hash-doc-1", "visible-text-codepoints/v1:production:generation"),
|
||
),
|
||
)
|
||
|
||
|
||
def 条目(调用ID: str = "call-1", 工具名: str = "read_history_document", 参数: dict | None = None):
|
||
"""用真实读取结果形状构建顺序为 1 的清单条目;覆盖字段由用例自行 replace。"""
|
||
return 记录探索(
|
||
(),
|
||
调用ID,
|
||
工具名,
|
||
参数 if 参数 is not None else {"chapter_id": "ch-1", "revision": 1},
|
||
读取结果,
|
||
)[0]
|
||
|
||
|
||
def 顺序清单(*调用: tuple[str, str, dict]) -> tuple[探索条目, ...]:
|
||
"""按调用次序经记录探索构建顺序连续的合法清单。"""
|
||
清单: tuple[探索条目, ...] = ()
|
||
for 调用ID, 工具名, 参数 in 调用:
|
||
清单 = 记录探索(清单, 调用ID, 工具名, 参数, 读取结果)
|
||
return 清单
|
||
|
||
|
||
def test_顺序断裂拒绝__b7e0b1() -> None:
|
||
跳号 = (条目("call-1"), replace(条目("call-2"), 顺序=3))
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(跳号, 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
assert "顺序" in 异常.value.说明
|
||
倒序 = (replace(条目("call-1"), 顺序=2), replace(条目("call-2"), 顺序=1))
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(倒序, 范围)
|
||
assert "顺序" in 异常.value.说明
|
||
|
||
|
||
def test_重复调用ID拒绝__b7e0b2() -> None:
|
||
重复 = (条目("call-1"), replace(条目("call-1"), 顺序=2))
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(重复, 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
assert "call-1" in 异常.value.说明 and "重复" in 异常.value.说明
|
||
|
||
|
||
def test_布尔与类型混淆拒绝__b7e0b3() -> None:
|
||
# 顺序是 bool 而不是 int:True 不能冒充 1
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单((replace(条目("call-1"), 顺序=True),), 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
# 参数里的版本是 bool:JSON Schema 的 integer 不接受布尔
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单((条目("call-1", 参数={"chapter_id": "ch-1", "revision": True}),), 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
# 条目本身不是探索条目对象:字典形状不能冒充
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(({"call_id": "call-1", "tool": "read_history_document"},), 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
|
||
|
||
def test_缺来源绑定与非法消费哈希拒绝__b7e0b4() -> None:
|
||
缺绑定 = (replace(条目("call-1"), 来源引用=()),)
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(缺绑定, 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
assert "来源绑定" in 异常.value.说明
|
||
非法哈希 = (replace(条目("call-1"), 消费哈希="不是十六进制"),)
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单(非法哈希, 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|
||
assert "消费哈希" in 异常.value.说明
|
||
|
||
|
||
def test_合法清单按序通过且空清单拒绝__b7e0b5() -> None:
|
||
清单 = 顺序清单(
|
||
("call-1", "query_work_plan", {}),
|
||
("call-2", "query_facts_as_of", {}),
|
||
("call-3", "read_history_document", {"chapter_id": "ch-1", "revision": 1}),
|
||
("call-4", "read_history_document", {"chapter_id": "ch-1", "revision": 1, "end": 6}),
|
||
)
|
||
assert [项.顺序 for 项 in 清单] == [1, 2, 3, 4]
|
||
校验清单(清单, 范围) # 不抛异常即通过
|
||
with pytest.raises(上下文错误) as 异常:
|
||
校验清单((), 范围)
|
||
assert 异常.value.错误码 == "CONTEXT_INPUT_INVALID"
|