render() reported symbols = len(all_specs()) without rendering anything, and the plan's bytes > 10_000 threshold was calibrated for view_screenshot's 16 x 9 in figure, not the 20 x 22 in sheet, where a labels-only render is 85 KB. A builder that draws nothing passed the test. render() now reports what was drawn: symbols counts the specs whose insert left an entity with a real extent in the modelspace (blank names the rest; a spec break is one vertical line, so either axis counts), and ink is the share of PNG pixels that are not the background colour. The test renders a labels-only baseline with insert_symbol monkeypatched to draw nothing and checks that baseline reports zero symbols, is past the byte threshold, and carries less ink than the real sheet (measured 0.0234 vs 0.0273). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
"""pid_tag_parse tool, the two P&ID resources, the rewritten prompt, the contact sheet."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from fastmcp import Client
|
|
|
|
import server
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def client(monkeypatch):
|
|
monkeypatch.setenv("AUTOCAD_MCP_BACKEND", "ezdxf")
|
|
async with Client(server.mcp) as connected:
|
|
yield connected
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_tag_parse_tool(client):
|
|
out = (await client.call_tool("pid_tag_parse", {"tag": "10-FIC-101A"})).structured_content
|
|
assert out["valid"] is True and out["description"] == "Flow Indicating Controller"
|
|
out = (
|
|
await client.call_tool(
|
|
"pid_tag_parse",
|
|
{"tag": "Q-1", "kind": "equipment", "equipment_prefixes": {"Q": "quench"}},
|
|
)
|
|
).structured_content
|
|
assert out["equipment_kind"] == "quench"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_resources_serve_the_catalogue_and_the_letter_tables(client):
|
|
uris = {str(r.uri) for r in await client.list_resources()}
|
|
assert {"autocad://pid/symbols", "autocad://standards/isa51"} <= uris
|
|
symbols = json.loads((await client.read_resource("autocad://pid/symbols"))[0].text)
|
|
assert symbols["catalog_version"] == "1" and any(
|
|
s["symbol"] == "gate" for s in symbols["symbols"]
|
|
)
|
|
isa = json.loads((await client.read_resource("autocad://standards/isa51"))[0].text)
|
|
assert isa["first_letters"]["F"] == "Flow" and "rules" in isa
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_prompt_walks_the_tool_workflow(client):
|
|
prompt = await client.get_prompt(
|
|
"prompt_pid_diagram", {"project_name": "Unit 7", "revision": "B"}
|
|
)
|
|
text = "\n".join(m.content.text for m in prompt.messages)
|
|
for needle in (
|
|
"drawing_plan",
|
|
'layer_set_id="pid"',
|
|
"pid_symbol_insert",
|
|
"pid_line_draw",
|
|
"pid_graph",
|
|
"drawing_critique",
|
|
"drawing_finalize",
|
|
"pid_from_spec",
|
|
"Unit 7",
|
|
"Ø10",
|
|
):
|
|
assert needle in text, needle
|
|
assert "circle with triangle" not in text, "no hand-drawn symbols"
|
|
|
|
|
|
def test_catalog_contact_sheet_renders_every_symbol(tmp_path, monkeypatch):
|
|
pytest.importorskip("matplotlib")
|
|
import engineering.pid.insert as insert_module
|
|
from engineering.pid.symbols import all_specs
|
|
from scripts.render_pid_catalog import render
|
|
|
|
result = render(tmp_path / "sheet.png")
|
|
assert result["blank"] == [], "every catalogue symbol must leave geometry on the sheet"
|
|
assert result["symbols"] == len(all_specs()) >= 100 and result["bytes"] > 10_000
|
|
|
|
# The evidence has to come from the drawing and the picture, not from the
|
|
# catalogue's length: a builder that draws nothing yields a labels-only
|
|
# sheet whose PNG is well past the byte threshold, so the symbol count and
|
|
# the ink share are what tell the two apart.
|
|
async def draw_nothing(*_args, **_kwargs):
|
|
return {"handle": "0", "ports": {}}
|
|
|
|
monkeypatch.setattr(insert_module, "insert_symbol", draw_nothing)
|
|
labels_only = render(tmp_path / "labels_only.png")
|
|
assert labels_only["symbols"] == 0 and len(labels_only["blank"]) == len(all_specs())
|
|
assert labels_only["bytes"] > 10_000, "bytes alone would not have caught this"
|
|
assert result["ink"] > labels_only["ink"] * 1.1, (result["ink"], labels_only["ink"])
|