test(review): 新增 pytest 离线回归网,锁定 dwg_review 既有行为
在改动审查流水线(确定性检查前置 / 结论结构化 / 证据交叉校验)之前, 先立一张离线、确定性、秒级的回归网。 - 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)
This commit is contained in:
1 parent
8c07c7cad6
commit
0656397a68
15 files changed
+1710
No files matched your search
@@ -0,0 +1,102 @@
|
||||
"""`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
|
||||
Reference in new issue
Block a user