using Xunit; using Moq; using Moq.Protected; using System.Net; using System.Net.Http; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Svrnty.MCP.Core; using CodexMcpServer.Tools; namespace CodexMcpServer.Tests; /// /// Unit tests for GetDocumentSectionsTool following TDD approach. /// Tests integration with CODEX API for retrieving document sections. /// public class GetDocumentSectionsToolTests { [Fact] public void GetDocumentSectionsTool_ShouldHaveCorrectName() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); // Act var name = tool.Name; // Assert Assert.Equal("get_document_sections", name); } [Fact] public void GetDocumentSectionsTool_ShouldHaveDescription() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); // Act var description = tool.Description; // Assert Assert.NotNull(description); Assert.NotEmpty(description); Assert.Contains("section", description.ToLower()); } [Fact] public void GetDocumentSectionsTool_ShouldHaveValidSchema() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); // Act var schema = tool.Schema; // Assert Assert.NotNull(schema); var root = schema.RootElement; Assert.Equal(JsonValueKind.Object, root.ValueKind); // Schema should define required "id" parameter Assert.True(root.TryGetProperty("properties", out var properties)); Assert.True(properties.TryGetProperty("id", out var idProp)); } [Fact] public async Task GetDocumentSectionsTool_ExecuteAsync_WithValidId_ShouldCallCodexApi() { // Arrange var mockResponse = new { sections = new[] { new { id = "section1", title = "Introduction", content = "Intro text" }, new { id = "section2", title = "Body", content = "Body text" } }, documentId = "doc123" }; var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler .Protected() .Setup>( "SendAsync", ItExpr.Is(req => req.Method == HttpMethod.Get && req.RequestUri.ToString().Contains("/api/documents/") && req.RequestUri.ToString().Contains("/sections") ), ItExpr.IsAny() ) .ReturnsAsync(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent(JsonSerializer.Serialize(mockResponse)) }); var httpClient = new HttpClient(mockHttpMessageHandler.Object) { BaseAddress = new System.Uri("http://localhost:5050") }; var tool = new GetDocumentSectionsTool(httpClient); var arguments = JsonDocument.Parse("""{"id": "doc123"}"""); // Act var result = await tool.ExecuteAsync(arguments); // Assert Assert.NotNull(result); var root = result.RootElement; Assert.True(root.TryGetProperty("sections", out _)); } [Fact] public async Task GetDocumentSectionsTool_ExecuteAsync_WithEmptyId_ShouldReturnError() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); var arguments = JsonDocument.Parse("""{"id": ""}"""); // Act var result = await tool.ExecuteAsync(arguments); // Assert Assert.NotNull(result); var root = result.RootElement; Assert.True(root.TryGetProperty("error", out _)); } [Fact] public async Task GetDocumentSectionsTool_ExecuteAsync_WithNullArguments_ShouldReturnError() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); // Act var result = await tool.ExecuteAsync(null); // Assert Assert.NotNull(result); var root = result.RootElement; Assert.True(root.TryGetProperty("error", out _)); } [Fact] public async Task GetDocumentSectionsTool_ExecuteAsync_WithMissingIdProperty_ShouldReturnError() { // Arrange var httpClient = new HttpClient(); var tool = new GetDocumentSectionsTool(httpClient); var arguments = JsonDocument.Parse("""{"other": "value"}"""); // Act var result = await tool.ExecuteAsync(arguments); // Assert Assert.NotNull(result); var root = result.RootElement; Assert.True(root.TryGetProperty("error", out _)); } [Fact] public void GetDocumentSectionsTool_ShouldImplementIMcpTool() { // Arrange var httpClient = new HttpClient(); // Act var tool = new GetDocumentSectionsTool(httpClient); // Assert Assert.IsAssignableFrom(tool); } [Fact] public async Task GetDocumentSectionsTool_ExecuteAsync_ShouldUseCorrectEndpoint() { // Arrange string capturedUri = null; var mockHttpMessageHandler = new Mock(); mockHttpMessageHandler .Protected() .Setup>( "SendAsync", ItExpr.IsAny(), ItExpr.IsAny() ) .ReturnsAsync((HttpRequestMessage req, CancellationToken ct) => { capturedUri = req.RequestUri?.ToString(); return new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent("""{"sections": []}""") }; }); var httpClient = new HttpClient(mockHttpMessageHandler.Object) { BaseAddress = new System.Uri("http://localhost:5050") }; var tool = new GetDocumentSectionsTool(httpClient); var arguments = JsonDocument.Parse("""{"id": "doc123"}"""); // Act await tool.ExecuteAsync(arguments); // Assert Assert.NotNull(capturedUri); Assert.Contains("/api/documents/doc123/sections", capturedUri); } }