unity-mcp/tests/test_improved_anchor_matchi...

186 lines
4.8 KiB
Python
Raw Normal View History

"""
Test the improved anchor matching logic.
"""
import sys
import pathlib
import importlib.util
import types
# add server src to path and load modules
ROOT = pathlib.Path(__file__).resolve().parents[1]
SRC = ROOT / "MCPForUnity" / "UnityMcpServer~" / "src"
sys.path.insert(0, str(SRC))
# stub mcp.server.fastmcp
mcp_pkg = types.ModuleType("mcp")
server_pkg = types.ModuleType("mcp.server")
fastmcp_pkg = types.ModuleType("mcp.server.fastmcp")
2025-10-01 04:25:33 +08:00
class _Dummy:
pass
2025-10-01 04:25:33 +08:00
fastmcp_pkg.FastMCP = _Dummy
fastmcp_pkg.Context = _Dummy
server_pkg.fastmcp = fastmcp_pkg
mcp_pkg.server = server_pkg
sys.modules.setdefault("mcp", mcp_pkg)
sys.modules.setdefault("mcp.server", server_pkg)
sys.modules.setdefault("mcp.server.fastmcp", fastmcp_pkg)
2025-10-01 04:25:33 +08:00
def load_module(path, name):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
2025-10-01 04:25:33 +08:00
test: Consolidate pytest suite to MCPForUnity and improve test infrastructure (#332) * Update github-repo-stats.yml * pytest: make harness MCPForUnity-only; remove UnityMcpBridge paths from tests; route tools.manage_script via unity_connection for reliable monkeypatching; fix ctx usage; all tests green (39 pass, 5 skip, 7 xpass) * Add missing meta for MaterialMeshInstantiationTests.cs (Assets) * bridge/tools/manage_script: fix missing unity_connection prefix in validate_script; tests: tidy manage_script_uri unused symbols and arg names * tests: rename to script_apply_edits_module; extract DummyContext to tests/test_helpers and import; add telemetry stubs in tests to avoid pyproject I/O * tests: import cleanup and helper extraction; telemetry: prefer plain config and opt-in env override; test stubs and CWD fixes; exclude Bridge from pytest discovery * chore: remove unintended .wt-origin-main gitlink and ignore folder * tests: nit fixes (unused-arg stubs, import order, path-normalized ignore hook); telemetry: validate config endpoint; read_console: action optional * Add development dependencies to pyproject.toml - Add [project.optional-dependencies] section with dev group - Include pytest>=8.0.0 and pytest-anyio>=0.6.0 - Add Development Setup section to README-DEV.md with installation and testing instructions * Revert "Update github-repo-stats.yml" This reverts commit 8ae595d2f4f2525b0e44ece948883ea37138add4. * test: improve test clarity and modernize asyncio usage - Add explanation for 200ms timeout in backpressure test - Replace manual event loop creation with asyncio.run() - Add assertion message with actual elapsed time for easier debugging * refactor: remove duplicate DummyContext definitions across test files Replace 7 duplicate DummyContext class definitions with imports from tests.test_helpers. This follows DRY principles and ensures consistency across the test suite. * chore: remove unused _load function from test_edit_strict_and_warnings.py Dead code cleanup - function was no longer used after refactoring to dynamic tool registration. * docs: add comment explaining CWD manipulation in telemetry test Clarify why os.chdir() is necessary: telemetry.py calls get_package_version() at module load time, which reads pyproject.toml using a relative path. Acknowledges the fragility while explaining why it's currently required.
2025-10-22 01:42:55 +08:00
script_apply_edits_module = load_module(
SRC / "tools" / "script_apply_edits.py", "script_apply_edits_module")
2025-10-01 04:25:33 +08:00
def test_improved_anchor_matching():
"""Test that our improved anchor matching finds the right closing brace."""
2025-10-01 04:25:33 +08:00
test_code = '''using UnityEngine;
public class TestClass : MonoBehaviour
{
void Start()
{
Debug.Log("test");
}
void Update()
{
// Update logic
}
}'''
2025-10-01 04:25:33 +08:00
import re
2025-10-01 04:25:33 +08:00
# Test the problematic anchor pattern
anchor_pattern = r"\s*}\s*$"
flags = re.MULTILINE
2025-10-01 04:25:33 +08:00
# Test our improved function
test: Consolidate pytest suite to MCPForUnity and improve test infrastructure (#332) * Update github-repo-stats.yml * pytest: make harness MCPForUnity-only; remove UnityMcpBridge paths from tests; route tools.manage_script via unity_connection for reliable monkeypatching; fix ctx usage; all tests green (39 pass, 5 skip, 7 xpass) * Add missing meta for MaterialMeshInstantiationTests.cs (Assets) * bridge/tools/manage_script: fix missing unity_connection prefix in validate_script; tests: tidy manage_script_uri unused symbols and arg names * tests: rename to script_apply_edits_module; extract DummyContext to tests/test_helpers and import; add telemetry stubs in tests to avoid pyproject I/O * tests: import cleanup and helper extraction; telemetry: prefer plain config and opt-in env override; test stubs and CWD fixes; exclude Bridge from pytest discovery * chore: remove unintended .wt-origin-main gitlink and ignore folder * tests: nit fixes (unused-arg stubs, import order, path-normalized ignore hook); telemetry: validate config endpoint; read_console: action optional * Add development dependencies to pyproject.toml - Add [project.optional-dependencies] section with dev group - Include pytest>=8.0.0 and pytest-anyio>=0.6.0 - Add Development Setup section to README-DEV.md with installation and testing instructions * Revert "Update github-repo-stats.yml" This reverts commit 8ae595d2f4f2525b0e44ece948883ea37138add4. * test: improve test clarity and modernize asyncio usage - Add explanation for 200ms timeout in backpressure test - Replace manual event loop creation with asyncio.run() - Add assertion message with actual elapsed time for easier debugging * refactor: remove duplicate DummyContext definitions across test files Replace 7 duplicate DummyContext class definitions with imports from tests.test_helpers. This follows DRY principles and ensures consistency across the test suite. * chore: remove unused _load function from test_edit_strict_and_warnings.py Dead code cleanup - function was no longer used after refactoring to dynamic tool registration. * docs: add comment explaining CWD manipulation in telemetry test Clarify why os.chdir() is necessary: telemetry.py calls get_package_version() at module load time, which reads pyproject.toml using a relative path. Acknowledges the fragility while explaining why it's currently required.
2025-10-22 01:42:55 +08:00
best_match = script_apply_edits_module._find_best_anchor_match(
anchor_pattern, test_code, flags, prefer_last=True
)
2025-10-01 04:25:33 +08:00
assert best_match is not None, "anchor pattern not found"
match_pos = best_match.start()
line_num = test_code[:match_pos].count('\n') + 1
total_lines = test_code.count('\n') + 1
2025-10-01 04:25:33 +08:00
assert line_num >= total_lines - \
2, f"expected match near end (>= {total_lines-2}), got line {line_num}"
def test_old_vs_new_matching():
"""Compare old vs new matching behavior."""
2025-10-01 04:25:33 +08:00
test_code = '''using UnityEngine;
public class TestClass : MonoBehaviour
{
void Start()
{
Debug.Log("test");
}
void Update()
{
if (condition)
{
DoSomething();
}
}
void LateUpdate()
{
// More logic
}
}'''
2025-10-01 04:25:33 +08:00
import re
2025-10-01 04:25:33 +08:00
anchor_pattern = r"\s*}\s*$"
flags = re.MULTILINE
2025-10-01 04:25:33 +08:00
# Old behavior (first match)
old_match = re.search(anchor_pattern, test_code, flags)
2025-10-01 04:25:33 +08:00
old_line = test_code[:old_match.start()].count(
'\n') + 1 if old_match else None
# New behavior (improved matching)
test: Consolidate pytest suite to MCPForUnity and improve test infrastructure (#332) * Update github-repo-stats.yml * pytest: make harness MCPForUnity-only; remove UnityMcpBridge paths from tests; route tools.manage_script via unity_connection for reliable monkeypatching; fix ctx usage; all tests green (39 pass, 5 skip, 7 xpass) * Add missing meta for MaterialMeshInstantiationTests.cs (Assets) * bridge/tools/manage_script: fix missing unity_connection prefix in validate_script; tests: tidy manage_script_uri unused symbols and arg names * tests: rename to script_apply_edits_module; extract DummyContext to tests/test_helpers and import; add telemetry stubs in tests to avoid pyproject I/O * tests: import cleanup and helper extraction; telemetry: prefer plain config and opt-in env override; test stubs and CWD fixes; exclude Bridge from pytest discovery * chore: remove unintended .wt-origin-main gitlink and ignore folder * tests: nit fixes (unused-arg stubs, import order, path-normalized ignore hook); telemetry: validate config endpoint; read_console: action optional * Add development dependencies to pyproject.toml - Add [project.optional-dependencies] section with dev group - Include pytest>=8.0.0 and pytest-anyio>=0.6.0 - Add Development Setup section to README-DEV.md with installation and testing instructions * Revert "Update github-repo-stats.yml" This reverts commit 8ae595d2f4f2525b0e44ece948883ea37138add4. * test: improve test clarity and modernize asyncio usage - Add explanation for 200ms timeout in backpressure test - Replace manual event loop creation with asyncio.run() - Add assertion message with actual elapsed time for easier debugging * refactor: remove duplicate DummyContext definitions across test files Replace 7 duplicate DummyContext class definitions with imports from tests.test_helpers. This follows DRY principles and ensures consistency across the test suite. * chore: remove unused _load function from test_edit_strict_and_warnings.py Dead code cleanup - function was no longer used after refactoring to dynamic tool registration. * docs: add comment explaining CWD manipulation in telemetry test Clarify why os.chdir() is necessary: telemetry.py calls get_package_version() at module load time, which reads pyproject.toml using a relative path. Acknowledges the fragility while explaining why it's currently required.
2025-10-22 01:42:55 +08:00
new_match = script_apply_edits_module._find_best_anchor_match(
anchor_pattern, test_code, flags, prefer_last=True
)
2025-10-01 04:25:33 +08:00
new_line = test_code[:new_match.start()].count(
'\n') + 1 if new_match else None
assert old_line is not None and new_line is not None, "failed to locate anchors"
assert new_line > old_line, f"improved matcher should choose a later line (old={old_line}, new={new_line})"
total_lines = test_code.count('\n') + 1
2025-10-01 04:25:33 +08:00
assert new_line >= total_lines - \
2, f"expected class-end match near end (>= {total_lines-2}), got {new_line}"
def test_apply_edits_with_improved_matching():
"""Test that _apply_edits_locally uses improved matching."""
2025-10-01 04:25:33 +08:00
original_code = '''using UnityEngine;
public class TestClass : MonoBehaviour
{
public string message = "Hello World";
void Start()
{
Debug.Log(message);
}
}'''
2025-10-01 04:25:33 +08:00
# Test anchor_insert with the problematic pattern
edits = [{
"op": "anchor_insert",
"anchor": r"\s*}\s*$", # This should now find the class end
"position": "before",
"text": "\n public void NewMethod() { Debug.Log(\"Added at class end\"); }\n"
}]
2025-10-01 04:25:33 +08:00
test: Consolidate pytest suite to MCPForUnity and improve test infrastructure (#332) * Update github-repo-stats.yml * pytest: make harness MCPForUnity-only; remove UnityMcpBridge paths from tests; route tools.manage_script via unity_connection for reliable monkeypatching; fix ctx usage; all tests green (39 pass, 5 skip, 7 xpass) * Add missing meta for MaterialMeshInstantiationTests.cs (Assets) * bridge/tools/manage_script: fix missing unity_connection prefix in validate_script; tests: tidy manage_script_uri unused symbols and arg names * tests: rename to script_apply_edits_module; extract DummyContext to tests/test_helpers and import; add telemetry stubs in tests to avoid pyproject I/O * tests: import cleanup and helper extraction; telemetry: prefer plain config and opt-in env override; test stubs and CWD fixes; exclude Bridge from pytest discovery * chore: remove unintended .wt-origin-main gitlink and ignore folder * tests: nit fixes (unused-arg stubs, import order, path-normalized ignore hook); telemetry: validate config endpoint; read_console: action optional * Add development dependencies to pyproject.toml - Add [project.optional-dependencies] section with dev group - Include pytest>=8.0.0 and pytest-anyio>=0.6.0 - Add Development Setup section to README-DEV.md with installation and testing instructions * Revert "Update github-repo-stats.yml" This reverts commit 8ae595d2f4f2525b0e44ece948883ea37138add4. * test: improve test clarity and modernize asyncio usage - Add explanation for 200ms timeout in backpressure test - Replace manual event loop creation with asyncio.run() - Add assertion message with actual elapsed time for easier debugging * refactor: remove duplicate DummyContext definitions across test files Replace 7 duplicate DummyContext class definitions with imports from tests.test_helpers. This follows DRY principles and ensures consistency across the test suite. * chore: remove unused _load function from test_edit_strict_and_warnings.py Dead code cleanup - function was no longer used after refactoring to dynamic tool registration. * docs: add comment explaining CWD manipulation in telemetry test Clarify why os.chdir() is necessary: telemetry.py calls get_package_version() at module load time, which reads pyproject.toml using a relative path. Acknowledges the fragility while explaining why it's currently required.
2025-10-22 01:42:55 +08:00
result = script_apply_edits_module._apply_edits_locally(
2025-10-01 04:25:33 +08:00
original_code, edits)
lines = result.split('\n')
try:
idx = next(i for i, line in enumerate(lines) if "NewMethod" in line)
except StopIteration:
assert False, "NewMethod not found in result"
total_lines = len(lines)
2025-10-01 04:25:33 +08:00
assert idx >= total_lines - \
5, f"method inserted too early (idx={idx}, total_lines={total_lines})"
if __name__ == "__main__":
print("Testing improved anchor matching...")
print("="*60)
2025-10-01 04:25:33 +08:00
success1 = test_improved_anchor_matching()
2025-10-01 04:25:33 +08:00
print("\n" + "="*60)
print("Comparing old vs new behavior...")
success2 = test_old_vs_new_matching()
2025-10-01 04:25:33 +08:00
print("\n" + "="*60)
print("Testing _apply_edits_locally with improved matching...")
success3 = test_apply_edits_with_improved_matching()
2025-10-01 04:25:33 +08:00
print("\n" + "="*60)
if success1 and success2 and success3:
print("🎉 ALL TESTS PASSED! Improved anchor matching is working!")
else:
print("💥 Some tests failed. Need more work on anchor matching.")