From 7efbce848f8fd91664f3f5a03d321abca7da2123 Mon Sep 17 00:00:00 2001 From: Daliys Date: Sun, 5 Jul 2026 18:17:45 +0200 Subject: [PATCH] Fix test result message parsing --- .gitignore | 2 ++ AGENTS.md | 45 ++++++++++++++++++++++++++ AGENTS.md.meta | 7 ++++ CHANGELOG.md | 2 ++ DOCUMENTATION.MD | 3 +- Editor/MCPServerMethods.TestResults.cs | 4 ++- Editor/nexus_bridge/schemas.py | 13 ++++---- Editor/tests/test_schemas.py | 11 +++++++ README.md | 4 +-- Tests~/Editor/AgentToolingTests.cs | 12 +++++++ 10 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 AGENTS.md create mode 100644 AGENTS.md.meta diff --git a/.gitignore b/.gitignore index e46a977..04c5246 100644 --- a/.gitignore +++ b/.gitignore @@ -119,7 +119,9 @@ repro/ # Local agent and analysis artifacts .agents/ .codex/ +.gemini/ .hermes/ +.serena/ .soma/ graphify-out/ graphify-out/cache/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..fa5b301 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,45 @@ +# Agent Instructions: NexusUnity + +## Repository Scope + +This directory is the canonical Nexus Unity package repository. + +Use this directory for all Nexus Unity package work: + +- Branches, commits, pushes, pull requests, and issue fixes. +- Package source, bridge source, tests, changelog, README, and documentation. +- GitHub issue/PR work for `ForkHorizon/NexusUnity`. + +The parent Unity project is only the local test harness: + +`/Users/daliys/Daliys/UnityProjects/UnityTestForNexus` + +Use the parent project to run the Unity Editor, MCP server, scenes, `unity_lint_project`, and live package validation. Do not modify parent project files unless the user explicitly asks for harness work. + +## Branching + +- Base branch: `development`. +- Verify the real branch names before creating history. +- Do not auto-push. + +## Required Package Updates + +When package behavior or public API changes, keep these aligned: + +- `CHANGELOG.md` +- `README.md` +- `DOCUMENTATION.MD` +- `API_REFERENCE.MD` when tool contracts or public API shapes change +- Relevant tests under `Tests~/` or `Editor/tests/` + +## Validation + +Fast package validation: + +```bash +PYTHONDONTWRITEBYTECODE=1 scripts/prepush-validate.sh --static-only +``` + +For Unity-facing behavior, also use the running test harness through MCP tools such as `unity_wait`, `unity_lint_project`, and `unity_editor_controller`. + +Clean generated Python caches before validation if needed; `__pycache__` or `*.pyc` files are not part of package changes. diff --git a/AGENTS.md.meta b/AGENTS.md.meta new file mode 100644 index 0000000..b51e162 --- /dev/null +++ b/AGENTS.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e981a827e1664e38ba1ef3562ce33638 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/CHANGELOG.md b/CHANGELOG.md index fc55002..547b112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ All notable public changes to Nexus Unity are documented here. - Invalid `NEXUS_UNITY_TIMEOUT_SECONDS` values now fall back to the default bridge timeout instead of crashing the Python bridge at import time. - Python bridge type helpers no longer require Python 3.11-only typing features. - Path security tests now exercise JSON-RPC traversal rejection for representative file and asset tools. +- `get_test_results` now reads messages only from scoped NUnit result nodes and falls back to the test result instead of unrelated nested messages. +- `unity_scene_manager` schema aliases now preserve action-specific required parameters. ## [1.4.2] - 2026-06-13 diff --git a/DOCUMENTATION.MD b/DOCUMENTATION.MD index ad97f9b..9c26372 100644 --- a/DOCUMENTATION.MD +++ b/DOCUMENTATION.MD @@ -99,7 +99,7 @@ Raw HTTP JSON-RPC: - Intended for diagnostics, custom integrations, and direct automation. - The complete raw catalog is returned by `list_tools`. - Runtime schemas intentionally include compatibility fields where needed; for example `update_component` accepts both `properties` and the legacy `json_data` payload, `create_scene` accepts `path` / `open_if_exists`, `create_primitive` accepts transform/material fields, and `create_material` accepts an optional explicit asset `path` plus visible color fields. -- Agent diagnostics include `get_test_results` for Unity `TestResults*.xml` summaries, `get_tool_usage_stats` / `reset_tool_usage_stats` for scoped in-memory call counters and timing, and `ui_get_window_rect` / `ui_set_window_rect` / `ui_capture_window_snapshot` for resize-based editor UI QA. +- Agent diagnostics include `get_test_results` for Unity `TestResults*.xml` summaries with scoped non-passing test messages, `get_tool_usage_stats` / `reset_tool_usage_stats` for scoped in-memory call counters and timing, and `ui_get_window_rect` / `ui_set_window_rect` / `ui_capture_window_snapshot` for resize-based editor UI QA. - `batch_execute` runs requests serially, accepts at most 50 requests, and rejects nested `batch_execute` calls. MCP bridge: @@ -120,6 +120,7 @@ The current development line preserves backward compatibility while correcting p - `unity_write_and_compile` is the supported public MCP macro for write, wait, and compiler-feedback workflows. Any old documentation wording that says `unity_apply_code_change` should be treated as stale. - `update_component` should use a `properties` object for new callers; `json_data` remains accepted for existing callers. +- `unity_scene_manager` aliases such as `create_scene`, `open_scene`, `save_scene`, and `list_scenes` preserve action-specific required parameters. - `create_scene` accepts optional `path` and `open_if_exists` for deterministic scene assets. - `create_primitive` accepts optional `name`, `parent_id`, `position`, `rotation`, `scale`, and `material_path`. - Vector3 fields accept either `{ "x": 0, "y": 1, "z": 0 }` or `[0, 1, 0]`. diff --git a/Editor/MCPServerMethods.TestResults.cs b/Editor/MCPServerMethods.TestResults.cs index c42aa42..c4911e7 100644 --- a/Editor/MCPServerMethods.TestResults.cs +++ b/Editor/MCPServerMethods.TestResults.cs @@ -39,7 +39,9 @@ private static JToken GetTestResults(JToken p) continue; string message = testCase.Element("failure")?.Element("message")?.Value - ?? testCase.Descendants("message").FirstOrDefault()?.Value; + ?? testCase.Element("reason")?.Element("message")?.Value + ?? testCase.Element("output")?.Value + ?? result; failedTests.Add(new JObject { ["name"] = Attr(testCase, "name"), diff --git a/Editor/nexus_bridge/schemas.py b/Editor/nexus_bridge/schemas.py index 764a5c5..3f2ac48 100644 --- a/Editor/nexus_bridge/schemas.py +++ b/Editor/nexus_bridge/schemas.py @@ -39,13 +39,12 @@ "description": "Unified scene management (create, open, save, list)", "inputSchema": { "type": "object", - "properties": { - "action": {"type": "string", "enum": ["create", "create_scene", "open", "open_scene", "save", "save_scene", "list", "list_scenes"]}, - "name": {"type": "string"}, - "path": {"type": "string"}, - "open_if_exists": {"type": "boolean"} - }, - "required": ["action"] + "oneOf": [ + {"properties": {"action": {"type": "string", "enum": ["create", "create_scene"]}, "name": {"type": "string"}, "path": {"type": "string"}, "open_if_exists": {"type": "boolean"}}, "required": ["action"]}, + {"properties": {"action": {"type": "string", "enum": ["open", "open_scene"]}, "path": {"type": "string"}}, "required": ["action", "path"]}, + {"properties": {"action": {"type": "string", "enum": ["save", "save_scene"]}, "path": {"type": "string"}}, "required": ["action"]}, + {"properties": {"action": {"type": "string", "enum": ["list", "list_scenes"]}}, "required": ["action"]} + ] } }, { diff --git a/Editor/tests/test_schemas.py b/Editor/tests/test_schemas.py index 8eea83e..2e6b328 100644 --- a/Editor/tests/test_schemas.py +++ b/Editor/tests/test_schemas.py @@ -26,6 +26,17 @@ def _action_values(variant: dict[str, Any]) -> set[str]: return set(action_schema["enum"]) +class SceneManagerSchemaTests(unittest.TestCase): + def test_scene_manager_keeps_action_specific_requirements(self) -> None: + scene_manager = _get_tool("unity_scene_manager") + variants = scene_manager["inputSchema"]["oneOf"] + open_variant = next(variant for variant in variants if "open_scene" in _action_values(variant)) + list_variant = next(variant for variant in variants if "list_scenes" in _action_values(variant)) + + self.assertCountEqual(["action", "path"], open_variant["required"]) + self.assertCountEqual(["action"], list_variant["required"]) + + class HierarchyManagerSchemaTests(unittest.TestCase): def test_hierarchy_manager_uses_action_specific_variants(self) -> None: hierarchy_manager = _get_tool("unity_hierarchy_manager") diff --git a/README.md b/README.md index da7e9a9..e54aa6d 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ Current development keeps the public API backward-compatible while tightening sc - Use `unity_write_and_compile` for code-edit workflows. Older references to `unity_apply_code_change` are outdated and should not be used for the public MCP bridge. - `update_component` accepts the preferred `properties` object and the legacy `json_data` string form. -- `unity_scene_manager` accepts obvious aliases such as `list_scenes`, `create_scene`, `open_scene`, and `save_scene`; invalid manager actions now report the valid action names. +- `unity_scene_manager` accepts obvious aliases such as `list_scenes`, `create_scene`, `open_scene`, and `save_scene` while preserving action-specific required parameters; invalid manager actions now report the valid action names. - `create_scene` accepts optional `path` and `open_if_exists` so agents can create or reopen a deterministic scene asset in one call. - `create_primitive` accepts optional `name`, `parent_id`, `position`, `rotation`, `scale`, and `material_path`, which lets agents build visible non-origin objects without fragile follow-up calls. - Vector3 fields accept either `{ "x": 0, "y": 1, "z": 0 }` or `[0, 1, 0]`. @@ -182,7 +182,7 @@ Current development keeps the public API backward-compatible while tightening sc - `invoke_method.arguments` is an optional positional JSON array. - `click_object_in_game` accepts a documented `instance_id` target and still supports hierarchy `path` lookup. - Unity 6.x editor identity differences are handled internally: Nexus keeps JSON `instance_id` values stable while using Unity 6.4+ `EntityId` APIs when available and Unity 6.3-compatible instance ID APIs otherwise. -- `get_test_results` reads Unity `TestResults*.xml` summaries from the project root or Unity persistent data path; `unity_editor_controller` exposes `run_tests_wait` as a bridge-side polling workflow. +- `get_test_results` reads Unity `TestResults*.xml` summaries from the project root or Unity persistent data path, using scoped failure/reason/output messages for non-passing cases; `unity_editor_controller` exposes `run_tests_wait` as a bridge-side polling workflow. - `get_tool_usage_stats` reports in-memory raw tool counts, durations, and errors since Unity domain load without storing request payloads; `reset_tool_usage_stats` clears that state for scoped diagnostics. Both are also available through `unity_editor_controller`. - `ui_get_window_rect`, `ui_set_window_rect`, and `ui_capture_window_snapshot` support automated layout checks for editor windows. diff --git a/Tests~/Editor/AgentToolingTests.cs b/Tests~/Editor/AgentToolingTests.cs index 6e1fadf..85b6211 100644 --- a/Tests~/Editor/AgentToolingTests.cs +++ b/Tests~/Editor/AgentToolingTests.cs @@ -68,6 +68,18 @@ public void GetTestResultsParsesFailingXml() Assert.AreEqual("Expected true", failure?["message"]?.ToString()); } + [Test] + public void GetTestResultsUsesOnlyScopedMessagesForNonPassingXml() + { + WriteTestResults("No assertionsWrong nested messageWrong nested message"); + + JObject result = RpcResult("get_test_results", new JObject { ["result_path"] = _resultPath }); + JArray failures = (JArray)result["failed_tests"]; + + Assert.AreEqual("No assertions", failures[0]?["message"]?.ToString()); + Assert.AreEqual("Error", failures[1]?["message"]?.ToString()); + } + [Test] public void ToolUsageStatsTrackCountsAndErrorsWithoutPayloads() {