using Xunit;
using Moq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Linq;
namespace OpenHarbor.MCP.Core.Tests;
///
/// Unit tests for ToolRegistry following TDD approach.
/// Tests dynamic tool registration and retrieval.
///
public class ToolRegistryTests
{
[Fact]
public void ToolRegistry_ShouldInitializeEmpty()
{
// Arrange & Act
var registry = new ToolRegistry();
// Assert
Assert.NotNull(registry);
Assert.Empty(registry.GetAllTools());
}
[Fact]
public void ToolRegistry_ShouldAddTool()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("test_tool", "A test tool");
// Act
registry.AddTool(mockTool.Object);
// Assert
Assert.Single(registry.GetAllTools());
}
[Fact]
public void ToolRegistry_ShouldGetToolByName()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("search_codex", "Search CODEX documents");
registry.AddTool(mockTool.Object);
// Act
var retrieved = registry.GetTool("search_codex");
// Assert
Assert.NotNull(retrieved);
Assert.Equal("search_codex", retrieved.Name);
}
[Fact]
public void ToolRegistry_GetTool_WithInvalidName_ReturnsNull()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("existing_tool", "Exists");
registry.AddTool(mockTool.Object);
// Act
var result = registry.GetTool("nonexistent_tool");
// Assert
Assert.Null(result);
}
[Fact]
public void ToolRegistry_ShouldAddMultipleTools()
{
// Arrange
var registry = new ToolRegistry();
var tool1 = CreateMockTool("tool1", "First tool");
var tool2 = CreateMockTool("tool2", "Second tool");
var tool3 = CreateMockTool("tool3", "Third tool");
// Act
registry.AddTool(tool1.Object);
registry.AddTool(tool2.Object);
registry.AddTool(tool3.Object);
// Assert
var allTools = registry.GetAllTools();
Assert.Equal(3, allTools.Count());
}
[Fact]
public void ToolRegistry_ShouldPreventDuplicateToolNames()
{
// Arrange
var registry = new ToolRegistry();
var tool1 = CreateMockTool("duplicate", "First");
var tool2 = CreateMockTool("duplicate", "Second");
registry.AddTool(tool1.Object);
// Act & Assert
var exception = Assert.Throws(() =>
registry.AddTool(tool2.Object)
);
Assert.Contains("already registered", exception.Message);
Assert.Single(registry.GetAllTools());
}
[Fact]
public void ToolRegistry_ShouldRemoveTool()
{
// Arrange
var registry = new ToolRegistry();
var mockTool = CreateMockTool("temp_tool", "Temporary");
registry.AddTool(mockTool.Object);
// Act
var removed = registry.RemoveTool("temp_tool");
// Assert
Assert.True(removed);
Assert.Empty(registry.GetAllTools());
Assert.Null(registry.GetTool("temp_tool"));
}
[Fact]
public void ToolRegistry_RemoveTool_WithInvalidName_ReturnsFalse()
{
// Arrange
var registry = new ToolRegistry();
// Act
var removed = registry.RemoveTool("nonexistent");
// Assert
Assert.False(removed);
}
[Fact]
public void ToolRegistry_ShouldListAllToolNames()
{
// Arrange
var registry = new ToolRegistry();
registry.AddTool(CreateMockTool("tool_a", "A").Object);
registry.AddTool(CreateMockTool("tool_b", "B").Object);
registry.AddTool(CreateMockTool("tool_c", "C").Object);
// Act
var names = registry.GetToolNames();
// Assert
Assert.Equal(3, names.Count());
Assert.Contains("tool_a", names);
Assert.Contains("tool_b", names);
Assert.Contains("tool_c", names);
}
[Fact]
public void ToolRegistry_ShouldHaveTool()
{
// Arrange
var registry = new ToolRegistry();
registry.AddTool(CreateMockTool("exists", "Tool").Object);
// Act & Assert
Assert.True(registry.HasTool("exists"));
Assert.False(registry.HasTool("not_exists"));
}
[Fact]
public void ToolRegistry_ShouldClearAllTools()
{
// Arrange
var registry = new ToolRegistry();
registry.AddTool(CreateMockTool("tool1", "1").Object);
registry.AddTool(CreateMockTool("tool2", "2").Object);
// Act
registry.Clear();
// Assert
Assert.Empty(registry.GetAllTools());
Assert.Empty(registry.GetToolNames());
}
[Fact]
public void ToolRegistry_GetAllTools_ShouldReturnReadOnlyCollection()
{
// Arrange
var registry = new ToolRegistry();
registry.AddTool(CreateMockTool("tool", "Tool").Object);
// Act
var tools = registry.GetAllTools();
// Assert
Assert.NotNull(tools);
// Ensure modifying returned collection doesn't affect registry
Assert.IsAssignableFrom>(tools);
}
// Helper method to create mock tools
private Mock CreateMockTool(string name, string description)
{
var mockTool = new Mock();
mockTool.Setup(t => t.Name).Returns(name);
mockTool.Setup(t => t.Description).Returns(description);
mockTool.Setup(t => t.Schema).Returns(JsonDocument.Parse("""{"type": "object"}"""));
mockTool.Setup(t => t.ExecuteAsync(It.IsAny()))
.ReturnsAsync(JsonDocument.Parse("""{"status": "ok"}"""));
return mockTool;
}
}