mcltspice/tests/test_resources.py
Ryan Malloy ca6e15e751 Extract library_tools + resources; fix 3 dead resources
ltspice://symbols, ltspice://examples, ltspice://status raised TypeError on
read -- they called list_symbols/list_examples/check_installation, which are
@mcp.tool() FunctionTool objects (not callable). Split those three into plain
*_impl functions + thin tool wrappers, and point the resources at the impls.
The other library tools move verbatim.

Adds test_resources.py to read every resource (regression guard). Library tool
outputs verified byte-identical old-vs-new. server.py: 2168 -> 1876 lines.
2026-06-21 20:50:27 -06:00

60 lines
1.9 KiB
Python

"""Resource-read regression tests.
ltspice://symbols, ltspice://examples, and ltspice://status previously raised
TypeError on read because the resource functions called @mcp.tool()-decorated
names (FunctionTool objects are not callable). These tests read every resource
to guard against that regressing.
"""
import inspect
import json
from mcltspice.library_tools import (
check_installation_impl,
list_examples_impl,
list_symbols_impl,
)
from mcltspice.server import mcp # importing registers all resources
async def _read(uri: str) -> str:
resources = await mcp.get_resources()
assert uri in resources, f"{uri} not registered"
out = resources[uri].fn()
if inspect.isawaitable(out):
out = await out
return out
class TestResourceReadsWithoutError:
async def test_symbols_resource_reads(self):
out = await _read("ltspice://symbols")
json.loads(out) # valid JSON, no TypeError
async def test_examples_resource_reads(self):
out = await _read("ltspice://examples")
json.loads(out)
async def test_status_resource_reads(self):
out = await _read("ltspice://status")
data = json.loads(out)
assert "valid" in data
async def test_templates_resource_reads(self):
out = await _read("ltspice://templates")
data = json.loads(out)
assert "netlist_templates" in data and "schematic_templates" in data
class TestLibraryImplsAreCallable:
"""The fix: the *_impl functions must be plain callables (not FunctionTool)."""
def test_impls_are_callable(self):
assert callable(list_symbols_impl)
assert callable(list_examples_impl)
assert callable(check_installation_impl)
def test_check_installation_impl_shape(self):
result = check_installation_impl()
assert set(result) >= {"valid", "message", "paths", "lib_exists"}