using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Xunit; using StellaOps.TestKit; namespace StellaOps.Cryptography.PluginLoader.Tests; public class CryptoPluginLoaderTests { [Trait("Category", TestCategories.Unit)] [Fact] public void Constructor_WithNullConfiguration_ThrowsArgumentNullException() { // Arrange & Act Action act = () => new CryptoPluginLoader(null!, NullLogger.Instance); // Assert act.Should().Throw() .WithParameterName("configuration"); } [Trait("Category", TestCategories.Unit)] [Fact] public void LoadProviders_WithEmptyEnabledList_ReturnsEmptyCollection() { // Arrange var configuration = new CryptoPluginConfiguration { ManifestPath = CreateTestManifest(), DiscoveryMode = "explicit", Enabled = new List(), RequireAtLeastOne = false }; var loader = new CryptoPluginLoader(configuration, NullLogger.Instance); // Act var providers = loader.LoadProviders(); // Assert providers.Should().BeEmpty(); } [Trait("Category", TestCategories.Unit)] [Fact] public void LoadProviders_WithMissingManifest_ThrowsFileNotFoundException() { // Arrange var configuration = new CryptoPluginConfiguration { ManifestPath = "/nonexistent/path/manifest.json", DiscoveryMode = "explicit" }; var loader = new CryptoPluginLoader(configuration, NullLogger.Instance); // Act Action act = () => loader.LoadProviders(); // Assert act.Should().Throw() .WithMessage("*manifest.json*"); } [Trait("Category", TestCategories.Unit)] [Fact] public void LoadProviders_WithRequireAtLeastOneAndNoProviders_ThrowsCryptoPluginLoadException() { // Arrange var configuration = new CryptoPluginConfiguration { ManifestPath = CreateTestManifest(), DiscoveryMode = "explicit", Enabled = new List(), RequireAtLeastOne = true }; var loader = new CryptoPluginLoader(configuration, NullLogger.Instance); // Act Action act = () => loader.LoadProviders(); // Assert act.Should().Throw() .WithMessage("*at least one provider*"); } [Trait("Category", TestCategories.Unit)] [Fact] public void LoadProviders_WithDisabledPattern_FiltersMatchingPlugins() { // Arrange var configuration = new CryptoPluginConfiguration { ManifestPath = CreateTestManifest(), DiscoveryMode = "auto", Disabled = new List { "test.*" }, RequireAtLeastOne = false }; var loader = new CryptoPluginLoader(configuration, NullLogger.Instance); // Act var providers = loader.LoadProviders(); // Assert providers.Should().NotContain(p => p.Name.StartsWith("test.", StringComparison.OrdinalIgnoreCase)); } private static string CreateTestManifest() { var tempPath = Path.Combine(Path.GetTempPath(), $"test-manifest-{Guid.NewGuid()}.json"); var manifestContent = @"{ ""version"": ""1.0"", ""plugins"": [] }"; File.WriteAllText(tempPath, manifestContent); return tempPath; } } public class CryptoPluginConfigurationTests { [Trait("Category", TestCategories.Unit)] [Fact] public void Constructor_SetsDefaultValues() { // Arrange & Act var config = new CryptoPluginConfiguration(); // Assert config.ManifestPath.Should().Be("/etc/stellaops/crypto-plugins-manifest.json"); config.DiscoveryMode.Should().Be("explicit"); config.FailOnMissingPlugin.Should().BeTrue(); config.RequireAtLeastOne.Should().BeTrue(); config.Enabled.Should().NotBeNull().And.BeEmpty(); config.Disabled.Should().NotBeNull().And.BeEmpty(); } } public class CryptoPluginManifestTests { [Trait("Category", TestCategories.Unit)] [Fact] public void CryptoPluginDescriptor_WithRequiredProperties_IsValid() { // Arrange & Act var descriptor = new CryptoPluginDescriptor { Id = "test", Name = "TestProvider", Assembly = "Test.dll", Type = "Test.TestProvider" }; // Assert descriptor.Id.Should().Be("test"); descriptor.Name.Should().Be("TestProvider"); descriptor.Assembly.Should().Be("Test.dll"); descriptor.Type.Should().Be("Test.TestProvider"); descriptor.Priority.Should().Be(50); // Default priority descriptor.EnabledByDefault.Should().BeTrue(); } }