// Step 1992: Schema stub fix for text/AST sync and merge tools // Verifies that the 9 sprint 142/143/144 tools have non-empty inputSchema // and return success when called with a valid id. #include "MCPServer.h" #include #include #include // Call a named MCP tool through MCPServer. static json callTool(MCPServer& srv, const std::string& name, json params = json::object()) { json req = {{"jsonrpc", "2.0"}, {"id", 1}, {"method", "tools/call"}, {"params", {{"name", name}, {"arguments", std::move(params)}}}}; return srv.handleRequest(req); } // Return the inputSchema for a registered tool (empty object if not found). static json toolSchema(MCPServer& srv, const std::string& name) { for (const auto& t : srv.getTools()) { if (t.name == name) return t.inputSchema; } return json::object(); } // Return true if the tools/call response indicates success (isError == false). static bool isSuccess(const json& resp) { return resp.contains("result") && resp["result"].contains("isError") && resp["result"]["isError"] == false; } int main() { int passed = 0; MCPServer srv; const std::string id = "step1992-test"; // ---------------------------------------------------------------- // Test 1: Sprint 142 schemas are non-empty and contain id property // ---------------------------------------------------------------- { for (const auto& name : { "whetstone_sync_text_to_ast", "whetstone_get_sync_diagnostics", "whetstone_get_sync_identity_report"}) { json schema = toolSchema(srv, name); assert(!schema.empty() && "schema must not be empty for " + std::string(name)); assert(schema.contains("properties")); assert(schema["properties"].contains("id")); } std::cout << "Test 1 PASSED: Sprint 142 tools have full schemas\n"; ++passed; } // ---------------------------------------------------------------- // Test 2: Sprint 143 schemas are non-empty and contain id property // ---------------------------------------------------------------- { for (const auto& name : { "whetstone_regenerate_text_from_ast", "whetstone_preview_regenerated_diff", "whetstone_get_regeneration_decisions"}) { json schema = toolSchema(srv, name); assert(!schema.empty()); assert(schema.contains("properties")); assert(schema["properties"].contains("id")); } // Verify regenerate also documents the mode parameter json regenSchema = toolSchema(srv, "whetstone_regenerate_text_from_ast"); assert(regenSchema["properties"].contains("mode")); std::cout << "Test 2 PASSED: Sprint 143 tools have full schemas\n"; ++passed; } // ---------------------------------------------------------------- // Test 3: Sprint 144 schemas are non-empty and contain id property // ---------------------------------------------------------------- { for (const auto& name : { "whetstone_detect_text_ast_conflicts", "whetstone_preview_text_ast_merge", "whetstone_apply_text_ast_merge"}) { json schema = toolSchema(srv, name); assert(!schema.empty()); assert(schema.contains("properties")); assert(schema["properties"].contains("id")); } std::cout << "Test 3 PASSED: Sprint 144 tools have full schemas\n"; ++passed; } // ---------------------------------------------------------------- // Test 4: sync_text_to_ast succeeds with valid id // ---------------------------------------------------------------- { auto resp = callTool(srv, "whetstone_sync_text_to_ast", {{"id", id}, {"language", "cpp"}, {"text", "int x = 0;\n"}}); assert(isSuccess(resp)); std::cout << "Test 4 PASSED: whetstone_sync_text_to_ast returns success\n"; ++passed; } // ---------------------------------------------------------------- // Test 5: detect/preview/apply merge pipeline succeeds with valid id // ---------------------------------------------------------------- { auto detect = callTool(srv, "whetstone_detect_text_ast_conflicts", {{"id", id}, {"language", "cpp"}}); assert(isSuccess(detect)); auto preview = callTool(srv, "whetstone_preview_text_ast_merge", {{"id", id}, {"language", "cpp"}}); assert(isSuccess(preview)); auto apply = callTool(srv, "whetstone_apply_text_ast_merge", {{"id", id}, {"language", "cpp"}}); assert(isSuccess(apply)); std::cout << "Test 5 PASSED: detect/preview/apply merge pipeline works\n"; ++passed; } std::cout << "\n" << passed << "/5 passed\n"; return passed == 5 ? 0 : 1; }