Skip to main content
Glama
test_script_tools.py7.28 kB
import pytest import asyncio from .test_helpers import DummyContext class DummyMCP: def __init__(self): self.tools = {} def tool(self, *args, **kwargs): # accept decorator kwargs like description def decorator(func): self.tools[func.__name__] = func return func return decorator def setup_manage_script(): mcp = DummyMCP() # Import the tools module to trigger decorator registration import services.tools.manage_script # Get the registered tools from the registry from services.registry import get_registered_tools tools = get_registered_tools() # Add all script-related tools to our dummy MCP for tool_info in tools: tool_name = tool_info['name'] if any(keyword in tool_name for keyword in ['script', 'apply_text', 'create_script', 'delete_script', 'validate_script', 'get_sha']): mcp.tools[tool_name] = tool_info['func'] return mcp.tools def setup_manage_asset(): mcp = DummyMCP() # Import the tools module to trigger decorator registration import services.tools.manage_asset # Get the registered tools from the registry from services.registry import get_registered_tools tools = get_registered_tools() # Add all asset-related tools to our dummy MCP for tool_info in tools: tool_name = tool_info['name'] if any(keyword in tool_name for keyword in ['asset', 'manage_asset']): mcp.tools[tool_name] = tool_info['func'] return mcp.tools @pytest.mark.asyncio async def test_apply_text_edits_long_file(monkeypatch): tools = setup_manage_script() apply_edits = tools["apply_text_edits"] captured = {} async def fake_send(cmd, params, **kwargs): captured["cmd"] = cmd captured["params"] = params return {"success": True} # Patch the send_command_with_retry function at the module level where it's imported import transport.legacy.unity_connection monkeypatch.setattr( transport.legacy.unity_connection, "async_send_command_with_retry", fake_send, ) # No need to patch tools.manage_script; it now calls unity_connection.send_command_with_retry edit = {"startLine": 1005, "startCol": 0, "endLine": 1005, "endCol": 5, "newText": "Hello"} ctx = DummyContext() resp = await apply_edits(ctx, "unity://path/Assets/Scripts/LongFile.cs", [edit]) assert captured["cmd"] == "manage_script" assert captured["params"]["action"] == "apply_text_edits" assert captured["params"]["edits"][0]["startLine"] == 1005 assert resp["success"] is True @pytest.mark.asyncio async def test_sequential_edits_use_precondition(monkeypatch): tools = setup_manage_script() apply_edits = tools["apply_text_edits"] calls = [] async def fake_send(cmd, params, **kwargs): calls.append(params) return {"success": True, "sha256": f"hash{len(calls)}"} # Patch the send_command_with_retry function at the module level where it's imported import transport.legacy.unity_connection monkeypatch.setattr( transport.legacy.unity_connection, "async_send_command_with_retry", fake_send, ) # No need to patch tools.manage_script; it now calls unity_connection.send_command_with_retry edit1 = {"startLine": 1, "startCol": 0, "endLine": 1, "endCol": 0, "newText": "//header\n"} resp1 = await apply_edits(DummyContext(), "unity://path/Assets/Scripts/File.cs", [edit1]) edit2 = {"startLine": 2, "startCol": 0, "endLine": 2, "endCol": 0, "newText": "//second\n"} resp2 = await apply_edits( DummyContext(), "unity://path/Assets/Scripts/File.cs", [edit2], precondition_sha256=resp1["sha256"], ) assert calls[1]["precondition_sha256"] == resp1["sha256"] assert resp2["sha256"] == "hash2" @pytest.mark.asyncio async def test_apply_text_edits_forwards_options(monkeypatch): tools = setup_manage_script() apply_edits = tools["apply_text_edits"] captured = {} async def fake_send(cmd, params, **kwargs): captured["params"] = params return {"success": True} # Patch the send_command_with_retry function at the module level where it's imported import transport.legacy.unity_connection monkeypatch.setattr( transport.legacy.unity_connection, "async_send_command_with_retry", fake_send, ) # No need to patch tools.manage_script; it now calls unity_connection.send_command_with_retry opts = {"validate": "relaxed", "applyMode": "atomic", "refresh": "immediate"} await apply_edits( DummyContext(), "unity://path/Assets/Scripts/File.cs", [{"startLine": 1, "startCol": 1, "endLine": 1, "endCol": 1, "newText": "x"}], options=opts, ) assert captured["params"].get("options") == opts @pytest.mark.asyncio async def test_apply_text_edits_defaults_atomic_for_multi_span(monkeypatch): tools = setup_manage_script() apply_edits = tools["apply_text_edits"] captured = {} async def fake_send(cmd, params, **kwargs): captured["params"] = params return {"success": True} # Patch the send_command_with_retry function at the module level where it's imported import transport.legacy.unity_connection monkeypatch.setattr( transport.legacy.unity_connection, "async_send_command_with_retry", fake_send, ) # No need to patch tools.manage_script; it now calls unity_connection.send_command_with_retry edits = [ {"startLine": 2, "startCol": 2, "endLine": 2, "endCol": 3, "newText": "A"}, {"startLine": 3, "startCol": 2, "endLine": 3, "endCol": 2, "newText": "// tail\n"}, ] await apply_edits( DummyContext(), "unity://path/Assets/Scripts/File.cs", edits, precondition_sha256="x", ) opts = captured["params"].get("options", {}) assert opts.get("applyMode") == "atomic" @pytest.mark.asyncio async def test_manage_asset_prefab_modify_request(monkeypatch): tools = setup_manage_asset() manage_asset = tools["manage_asset"] captured = {} async def fake_async(cmd, params, loop=None): captured["cmd"] = cmd captured["params"] = params return {"success": True} # Patch the async function in the tools module import services.tools.manage_asset as tools_manage_asset # Patch both at the module and at the function closure location monkeypatch.setattr(tools_manage_asset, "async_send_command_with_retry", fake_async) # Also patch the globals of the function object (handles dynamically loaded module alias) manage_asset.__globals__["async_send_command_with_retry"] = fake_async resp = await manage_asset( DummyContext(), action="modify", path="Assets/Prefabs/Player.prefab", properties={"hp": 100}, ) assert captured["cmd"] == "manage_asset" assert captured["params"]["action"] == "modify" assert captured["params"]["path"] == "Assets/Prefabs/Player.prefab" assert captured["params"]["properties"] == {"hp": 100} assert resp["success"] is True

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CoplayDev/unity-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server