在改动审查流水线(确定性检查前置 / 结论结构化 / 证据交叉校验)之前, 先立一张离线、确定性、秒级的回归网。 - tests/fakes.py:假 LLM + 假 MCP 基座 + 响应构造器(ok_text/ok_image/err) + make_ctx/make_evidence,绝不触网、不读密钥 - 10 个模块共 134 用例: mcp_client / llm_client / cad_tools / checklist / config / planning / evidence / review / report / annotator - pytest.ini(testpaths=tests)+ requirements-dev.txt + 根 conftest.py (sys.path + RENDER_WAIT=0 / REPORT_DIR=tmp fixture)
103 lines
3.9 KiB
Python
103 lines
3.9 KiB
Python
"""`dwg_review.cad_tools` 单元测试。"""
|
|
|
|
from dwg_review.cad_tools import CadTools, is_write_tool
|
|
from dwg_review.mcp_client import result_json
|
|
from tests.fakes import FakeMcpClient, ok_text, tool_schema
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 写类工具判定
|
|
# ---------------------------------------------------------------------------
|
|
def test_write_prefixes_detected():
|
|
for name in ("add_leader_annotation", "delete_entities", "draw_line", "set_layer"):
|
|
assert is_write_tool(name) is True
|
|
|
|
|
|
def test_write_exact_names_detected():
|
|
assert is_write_tool("set_entity_properties") is True
|
|
assert is_write_tool("highlight_entities") is True
|
|
|
|
|
|
def test_readonly_tools_are_not_write():
|
|
for name in ("query_entities", "get_text_content", "zoom_to_window", "find_zero_length"):
|
|
assert is_write_tool(name) is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 注册表
|
|
# ---------------------------------------------------------------------------
|
|
def test_registry_built_from_client():
|
|
client = FakeMcpClient()
|
|
tools = CadTools(client)
|
|
assert "query_entities" in tools.names
|
|
assert tools.has("get_viewport_screenshot") is True
|
|
assert tools.has("__nope__") is False
|
|
assert tools.names == sorted(tools.names)
|
|
|
|
|
|
def test_describe_returns_tool_dict():
|
|
client = FakeMcpClient()
|
|
tools = CadTools(client)
|
|
desc = tools.describe("query_entities")
|
|
assert desc["name"] == "query_entities"
|
|
assert "inputSchema" in desc
|
|
|
|
|
|
def test_refresh_picks_up_new_tools():
|
|
client = FakeMcpClient(tools=[tool_schema("a")])
|
|
tools = CadTools(client)
|
|
assert tools.names == ["a"]
|
|
client._tools = [tool_schema("a"), tool_schema("b")]
|
|
tools.refresh()
|
|
assert tools.names == ["a", "b"]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# openai_tools
|
|
# ---------------------------------------------------------------------------
|
|
def test_openai_tools_format():
|
|
client = FakeMcpClient(tools=[tool_schema("query_entities", "查询", {"window": {"type": "object"}})])
|
|
entry = CadTools(client).openai_tools()[0]
|
|
assert entry["type"] == "function"
|
|
assert entry["function"]["name"] == "query_entities"
|
|
assert entry["function"]["description"] == "查询"
|
|
assert entry["function"]["parameters"]["properties"] == {"window": {"type": "object"}}
|
|
|
|
|
|
def test_openai_tools_defaults_schema_when_missing():
|
|
client = FakeMcpClient(tools=[{"name": "bare", "description": ""}])
|
|
entry = CadTools(client).openai_tools()[0]
|
|
assert entry["function"]["parameters"] == {"type": "object", "properties": {}}
|
|
|
|
|
|
def test_openai_tools_names_filter():
|
|
client = FakeMcpClient()
|
|
names = CadTools(client).openai_tools(names={"query_entities", "get_layers"})
|
|
assert sorted(n["function"]["name"] for n in names) == ["get_layers", "query_entities"]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# call
|
|
# ---------------------------------------------------------------------------
|
|
def test_call_returns_normalized_response():
|
|
client = FakeMcpClient(responses={"query_entities": ok_text({"total": 7})})
|
|
tools = CadTools(client)
|
|
assert result_json(tools.call("query_entities", {"window": {}})) == {"total": 7}
|
|
assert client.calls[-1]["name"] == "query_entities"
|
|
assert client.calls[-1]["arguments"] == {"window": {}}
|
|
|
|
|
|
def test_call_marks_write_tools():
|
|
client = FakeMcpClient()
|
|
tools = CadTools(client)
|
|
tools.call("add_leader_annotation", {"text": "x"})
|
|
tools.call("query_entities", {"window": {}})
|
|
assert client.calls[0]["is_write"] is True
|
|
assert client.calls[1]["is_write"] is False
|
|
|
|
|
|
def test_call_explicit_is_write_overrides_inference():
|
|
client = FakeMcpClient()
|
|
CadTools(client).call("query_entities", {}, is_write=True)
|
|
assert client.calls[-1]["is_write"] is True
|