"""`dwg_review.cad_tools` 单元测试。""" from dwg_review.cad_tools import READ_ONLY_TOOLS, 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", "find_collisions"): assert is_write_tool(name) is False def test_find_collisions_is_whitelisted(): assert "find_collisions" in READ_ONLY_TOOLS # --------------------------------------------------------------------------- # 注册表 # --------------------------------------------------------------------------- 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