using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Contracts.Resources;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using NSubstitute;
namespace ColaFlow.Modules.Mcp.Tests.Services;
///
/// Unit tests for McpResourceRegistry
///
public class McpResourceRegistryTests
{
private readonly ILogger _logger;
private readonly McpResourceRegistry _sut;
public McpResourceRegistryTests()
{
_logger = Substitute.For>();
_sut = new McpResourceRegistry(_logger);
}
[Fact]
public void RegisterResource_AddsResourceToRegistry()
{
// Arrange
var resource = CreateMockResource("colaflow://test", "Test Resource");
// Act
_sut.RegisterResource(resource);
// Assert
var resources = _sut.GetAllResources();
resources.Should().ContainSingle();
resources[0].Uri.Should().Be("colaflow://test");
}
[Fact]
public void RegisterResource_WithDuplicateUri_Overwrites()
{
// Arrange
var resource1 = CreateMockResource("colaflow://test", "Test Resource 1");
var resource2 = CreateMockResource("colaflow://test", "Test Resource 2");
// Act
_sut.RegisterResource(resource1);
_sut.RegisterResource(resource2);
// Assert
var resources = _sut.GetAllResources();
resources.Count.Should().Be(2); // Both are in the list
var foundResource = _sut.GetResourceByUri("colaflow://test");
foundResource!.Name.Should().Be("Test Resource 2"); // But only the last one is returned
}
[Fact]
public void GetResourceByUri_WithExactMatch_ReturnsResource()
{
// Arrange
var resource = CreateMockResource("colaflow://projects.list", "Projects List");
_sut.RegisterResource(resource);
// Act
var result = _sut.GetResourceByUri("colaflow://projects.list");
// Assert
result.Should().NotBeNull();
result!.Uri.Should().Be("colaflow://projects.list");
}
[Fact]
public void GetResourceByUri_WithTemplateMatch_ReturnsResource()
{
// Arrange
var resource = CreateMockResource("colaflow://projects.get/{id}", "Project Details");
_sut.RegisterResource(resource);
// Act
var result = _sut.GetResourceByUri("colaflow://projects.get/123");
// Assert
result.Should().NotBeNull();
result!.Uri.Should().Be("colaflow://projects.get/{id}");
}
[Fact]
public void GetResourceByUri_WithNonExistentUri_ReturnsNull()
{
// Act
var result = _sut.GetResourceByUri("colaflow://nonexistent");
// Assert
result.Should().BeNull();
}
[Fact]
public void GetResourceDescriptors_ReturnsAllDescriptors()
{
// Arrange
var resource1 = CreateMockResource("colaflow://test1", "Test 1");
var resource2 = CreateMockResource("colaflow://test2", "Test 2");
_sut.RegisterResource(resource1);
_sut.RegisterResource(resource2);
// Act
var descriptors = _sut.GetResourceDescriptors();
// Assert
descriptors.Should().HaveCount(2);
descriptors.Should().Contain(d => d.Uri == "colaflow://test1");
descriptors.Should().Contain(d => d.Uri == "colaflow://test2");
}
[Fact]
public void GetAllResources_ReturnsReadOnlyList()
{
// Arrange
var resource = CreateMockResource("colaflow://test", "Test");
_sut.RegisterResource(resource);
// Act
var resources = _sut.GetAllResources();
// Assert
resources.Should().BeAssignableTo>();
}
private IMcpResource CreateMockResource(string uri, string name)
{
var resource = Substitute.For();
resource.Uri.Returns(uri);
resource.Name.Returns(name);
resource.Description.Returns($"Description for {name}");
resource.MimeType.Returns("application/json");
resource.GetContentAsync(Arg.Any(), Arg.Any())
.Returns(new McpResourceContent
{
Uri = uri,
MimeType = "application/json",
Text = "{}"
});
return resource;
}
}