300 lines · cpp
1//===-- ProtocolMCPTest.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ProtocolMCPTestUtilities.h"10#include "TestingSupport/TestUtilities.h"11#include "lldb/Protocol/MCP/Protocol.h"12#include "llvm/Testing/Support/Error.h"13#include "gtest/gtest.h"14 15using namespace lldb;16using namespace lldb_private;17using namespace lldb_protocol::mcp;18 19// Flakey, see https://github.com/llvm/llvm-project/issues/152677.20#ifndef _WIN3221 22TEST(ProtocolMCPTest, Request) {23 Request request;24 request.id = 1;25 request.method = "foo";26 request.params = llvm::json::Object{{"key", "value"}};27 28 llvm::Expected<Request> deserialized_request = roundtripJSON(request);29 ASSERT_THAT_EXPECTED(deserialized_request, llvm::Succeeded());30 31 EXPECT_EQ(request.id, deserialized_request->id);32 EXPECT_EQ(request.method, deserialized_request->method);33 EXPECT_EQ(request.params, deserialized_request->params);34}35 36TEST(ProtocolMCPTest, Response) {37 Response response;38 response.id = 1;39 response.result = llvm::json::Object{{"key", "value"}};40 41 llvm::Expected<Response> deserialized_response = roundtripJSON(response);42 ASSERT_THAT_EXPECTED(deserialized_response, llvm::Succeeded());43 44 EXPECT_EQ(response.id, deserialized_response->id);45 EXPECT_EQ(response.result, deserialized_response->result);46}47 48TEST(ProtocolMCPTest, Notification) {49 Notification notification;50 notification.method = "notifyMethod";51 notification.params = llvm::json::Object{{"key", "value"}};52 53 llvm::Expected<Notification> deserialized_notification =54 roundtripJSON(notification);55 ASSERT_THAT_EXPECTED(deserialized_notification, llvm::Succeeded());56 57 EXPECT_EQ(notification.method, deserialized_notification->method);58 EXPECT_EQ(notification.params, deserialized_notification->params);59}60 61TEST(ProtocolMCPTest, ServerCapabilities) {62 ServerCapabilities capabilities;63 capabilities.supportsToolsList = true;64 65 llvm::Expected<ServerCapabilities> deserialized_capabilities =66 roundtripJSON(capabilities);67 ASSERT_THAT_EXPECTED(deserialized_capabilities, llvm::Succeeded());68 69 EXPECT_EQ(capabilities.supportsToolsList,70 deserialized_capabilities->supportsToolsList);71}72 73TEST(ProtocolMCPTest, TextContent) {74 TextContent text_content;75 text_content.text = "Sample text";76 77 llvm::Expected<TextContent> deserialized_text_content =78 roundtripJSON(text_content);79 ASSERT_THAT_EXPECTED(deserialized_text_content, llvm::Succeeded());80 81 EXPECT_EQ(text_content.text, deserialized_text_content->text);82}83 84TEST(ProtocolMCPTest, CallToolResult) {85 TextContent text_content1;86 text_content1.text = "Text 1";87 88 TextContent text_content2;89 text_content2.text = "Text 2";90 91 CallToolResult text_result;92 text_result.content = {text_content1, text_content2};93 text_result.isError = true;94 95 llvm::Expected<CallToolResult> deserialized_text_result =96 roundtripJSON(text_result);97 ASSERT_THAT_EXPECTED(deserialized_text_result, llvm::Succeeded());98 99 EXPECT_EQ(text_result.isError, deserialized_text_result->isError);100 ASSERT_EQ(text_result.content.size(),101 deserialized_text_result->content.size());102 EXPECT_EQ(text_result.content[0].text,103 deserialized_text_result->content[0].text);104 EXPECT_EQ(text_result.content[1].text,105 deserialized_text_result->content[1].text);106}107 108TEST(ProtocolMCPTest, ToolDefinition) {109 ToolDefinition tool_definition;110 tool_definition.name = "ToolName";111 tool_definition.description = "Tool Description";112 tool_definition.inputSchema =113 llvm::json::Object{{"schemaKey", "schemaValue"}};114 115 llvm::Expected<ToolDefinition> deserialized_tool_definition =116 roundtripJSON(tool_definition);117 ASSERT_THAT_EXPECTED(deserialized_tool_definition, llvm::Succeeded());118 119 EXPECT_EQ(tool_definition.name, deserialized_tool_definition->name);120 EXPECT_EQ(tool_definition.description,121 deserialized_tool_definition->description);122 EXPECT_EQ(tool_definition.inputSchema,123 deserialized_tool_definition->inputSchema);124}125 126TEST(ProtocolMCPTest, MessageWithRequest) {127 Request request;128 request.id = 1;129 request.method = "test_method";130 request.params = llvm::json::Object{{"param", "value"}};131 132 Message message = request;133 134 llvm::Expected<Message> deserialized_message = roundtripJSON(message);135 ASSERT_THAT_EXPECTED(deserialized_message, llvm::Succeeded());136 137 ASSERT_TRUE(std::holds_alternative<Request>(*deserialized_message));138 const Request &deserialized_request =139 std::get<Request>(*deserialized_message);140 141 EXPECT_EQ(request, deserialized_request);142}143 144TEST(ProtocolMCPTest, MessageWithResponse) {145 Response response;146 response.id = 2;147 response.result = llvm::json::Object{{"result", "success"}};148 149 Message message = response;150 151 llvm::Expected<Message> deserialized_message = roundtripJSON(message);152 ASSERT_THAT_EXPECTED(deserialized_message, llvm::Succeeded());153 154 ASSERT_TRUE(std::holds_alternative<Response>(*deserialized_message));155 const Response &deserialized_response =156 std::get<Response>(*deserialized_message);157 158 EXPECT_EQ(response, deserialized_response);159}160 161TEST(ProtocolMCPTest, MessageWithNotification) {162 Notification notification;163 notification.method = "notification_method";164 notification.params = llvm::json::Object{{"notify", "data"}};165 166 Message message = notification;167 168 llvm::Expected<Message> deserialized_message = roundtripJSON(message);169 ASSERT_THAT_EXPECTED(deserialized_message, llvm::Succeeded());170 171 ASSERT_TRUE(std::holds_alternative<Notification>(*deserialized_message));172 const Notification &deserialized_notification =173 std::get<Notification>(*deserialized_message);174 175 EXPECT_EQ(notification, deserialized_notification);176}177 178TEST(ProtocolMCPTest, MessageWithErrorResponse) {179 Error error;180 error.code = -32603;181 error.message = "Internal error";182 183 Response error_response;184 error_response.id = 3;185 error_response.result = error;186 187 Message message = error_response;188 189 llvm::Expected<Message> deserialized_message = roundtripJSON(message);190 ASSERT_THAT_EXPECTED(deserialized_message, llvm::Succeeded());191 192 ASSERT_TRUE(std::holds_alternative<Response>(*deserialized_message));193 const Response &deserialized_error =194 std::get<Response>(*deserialized_message);195 196 EXPECT_EQ(error_response, deserialized_error);197}198 199TEST(ProtocolMCPTest, Resource) {200 Resource resource;201 resource.uri = "resource://example/test";202 resource.name = "Test Resource";203 resource.description = "A test resource for unit testing";204 resource.mimeType = "text/plain";205 206 llvm::Expected<Resource> deserialized_resource = roundtripJSON(resource);207 ASSERT_THAT_EXPECTED(deserialized_resource, llvm::Succeeded());208 209 EXPECT_EQ(resource.uri, deserialized_resource->uri);210 EXPECT_EQ(resource.name, deserialized_resource->name);211 EXPECT_EQ(resource.description, deserialized_resource->description);212 EXPECT_EQ(resource.mimeType, deserialized_resource->mimeType);213}214 215TEST(ProtocolMCPTest, ResourceWithoutOptionals) {216 Resource resource;217 resource.uri = "resource://example/minimal";218 resource.name = "Minimal Resource";219 220 llvm::Expected<Resource> deserialized_resource = roundtripJSON(resource);221 ASSERT_THAT_EXPECTED(deserialized_resource, llvm::Succeeded());222 223 EXPECT_EQ(resource.uri, deserialized_resource->uri);224 EXPECT_EQ(resource.name, deserialized_resource->name);225 EXPECT_TRUE(deserialized_resource->description.empty());226 EXPECT_TRUE(deserialized_resource->mimeType.empty());227}228 229TEST(ProtocolMCPTest, TextResourceContents) {230 TextResourceContents contents;231 contents.uri = "resource://example/content";232 contents.text = "This is the content of the resource";233 contents.mimeType = "text/plain";234 235 llvm::Expected<TextResourceContents> deserialized_contents =236 roundtripJSON(contents);237 ASSERT_THAT_EXPECTED(deserialized_contents, llvm::Succeeded());238 239 EXPECT_EQ(contents.uri, deserialized_contents->uri);240 EXPECT_EQ(contents.text, deserialized_contents->text);241 EXPECT_EQ(contents.mimeType, deserialized_contents->mimeType);242}243 244TEST(ProtocolMCPTest, TextResourceContentsWithoutMimeType) {245 TextResourceContents contents;246 contents.uri = "resource://example/content-no-mime";247 contents.text = "Content without mime type specified";248 249 llvm::Expected<TextResourceContents> deserialized_contents =250 roundtripJSON(contents);251 ASSERT_THAT_EXPECTED(deserialized_contents, llvm::Succeeded());252 253 EXPECT_EQ(contents.uri, deserialized_contents->uri);254 EXPECT_EQ(contents.text, deserialized_contents->text);255 EXPECT_TRUE(deserialized_contents->mimeType.empty());256}257 258TEST(ProtocolMCPTest, ReadResourceResult) {259 TextResourceContents contents1;260 contents1.uri = "resource://example/content1";261 contents1.text = "First resource content";262 contents1.mimeType = "text/plain";263 264 TextResourceContents contents2;265 contents2.uri = "resource://example/content2";266 contents2.text = "Second resource content";267 contents2.mimeType = "application/json";268 269 ReadResourceResult result;270 result.contents = {contents1, contents2};271 272 llvm::Expected<ReadResourceResult> deserialized_result =273 roundtripJSON(result);274 ASSERT_THAT_EXPECTED(deserialized_result, llvm::Succeeded());275 276 ASSERT_EQ(result.contents.size(), deserialized_result->contents.size());277 278 EXPECT_EQ(result.contents[0].uri, deserialized_result->contents[0].uri);279 EXPECT_EQ(result.contents[0].text, deserialized_result->contents[0].text);280 EXPECT_EQ(result.contents[0].mimeType,281 deserialized_result->contents[0].mimeType);282 283 EXPECT_EQ(result.contents[1].uri, deserialized_result->contents[1].uri);284 EXPECT_EQ(result.contents[1].text, deserialized_result->contents[1].text);285 EXPECT_EQ(result.contents[1].mimeType,286 deserialized_result->contents[1].mimeType);287}288 289TEST(ProtocolMCPTest, ReadResourceResultEmpty) {290 ReadResourceResult result;291 292 llvm::Expected<ReadResourceResult> deserialized_result =293 roundtripJSON(result);294 ASSERT_THAT_EXPECTED(deserialized_result, llvm::Succeeded());295 296 EXPECT_TRUE(deserialized_result->contents.empty());297}298 299#endif300