- Renamed all directories: OpenHarbor.MCP.* → Svrnty.MCP.* - Updated all namespaces in 179 C# files - Renamed 20 .csproj files and 3 .sln files - Updated 193 documentation references - Updated 33 references in main CODEX codebase - Updated Codex.sln with new paths - Build verified: 0 errors Preparing for extraction to standalone repositories. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
179 lines
4.9 KiB
C#
179 lines
4.9 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Unit tests for SearchByTagTool following TDD approach.
|
|
/// Tests integration with CODEX API for tag-based search.
|
|
/// </summary>
|
|
public class SearchByTagToolTests
|
|
{
|
|
[Fact]
|
|
public void SearchByTagTool_ShouldHaveCorrectName()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(httpClient);
|
|
|
|
// Act
|
|
var name = tool.Name;
|
|
|
|
// Assert
|
|
Assert.Equal("search_by_tag", name);
|
|
}
|
|
|
|
[Fact]
|
|
public void SearchByTagTool_ShouldHaveDescription()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(httpClient);
|
|
|
|
// Act
|
|
var description = tool.Description;
|
|
|
|
// Assert
|
|
Assert.NotNull(description);
|
|
Assert.NotEmpty(description);
|
|
Assert.Contains("tag", description.ToLower());
|
|
}
|
|
|
|
[Fact]
|
|
public void SearchByTagTool_ShouldHaveValidSchema()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(httpClient);
|
|
|
|
// Act
|
|
var schema = tool.Schema;
|
|
|
|
// Assert
|
|
Assert.NotNull(schema);
|
|
var root = schema.RootElement;
|
|
Assert.Equal(JsonValueKind.Object, root.ValueKind);
|
|
|
|
// Schema should define required "tag" parameter
|
|
Assert.True(root.TryGetProperty("properties", out var properties));
|
|
Assert.True(properties.TryGetProperty("tag", out var tagProp));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SearchByTagTool_ExecuteAsync_WithValidTag_ShouldCallCodexApi()
|
|
{
|
|
// Arrange
|
|
var mockResponse = new
|
|
{
|
|
documents = new[]
|
|
{
|
|
new { id = "doc1", title = "Document 1", tags = new[] { "test" } }
|
|
},
|
|
total = 1
|
|
};
|
|
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
|
|
mockHttpMessageHandler
|
|
.Protected()
|
|
.Setup<Task<HttpResponseMessage>>(
|
|
"SendAsync",
|
|
ItExpr.Is<HttpRequestMessage>(req =>
|
|
req.Method == HttpMethod.Get &&
|
|
req.RequestUri.ToString().Contains("/api/tags/")
|
|
),
|
|
ItExpr.IsAny<CancellationToken>()
|
|
)
|
|
.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 SearchByTagTool(httpClient);
|
|
|
|
var arguments = JsonDocument.Parse("""{"tag": "test"}""");
|
|
|
|
// Act
|
|
var result = await tool.ExecuteAsync(arguments);
|
|
|
|
// Assert
|
|
Assert.NotNull(result);
|
|
var root = result.RootElement;
|
|
Assert.True(root.TryGetProperty("documents", out _));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SearchByTagTool_ExecuteAsync_WithEmptyTag_ShouldReturnError()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(httpClient);
|
|
var arguments = JsonDocument.Parse("""{"tag": ""}""");
|
|
|
|
// 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 SearchByTagTool_ExecuteAsync_WithNullArguments_ShouldReturnError()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(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 SearchByTagTool_ExecuteAsync_WithMissingTagProperty_ShouldReturnError()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
var tool = new SearchByTagTool(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 SearchByTagTool_ShouldImplementIMcpTool()
|
|
{
|
|
// Arrange
|
|
var httpClient = new HttpClient();
|
|
|
|
// Act
|
|
var tool = new SearchByTagTool(httpClient);
|
|
|
|
// Assert
|
|
Assert.IsAssignableFrom<IMcpTool>(tool);
|
|
}
|
|
}
|