using FluentAssertions; using StellaOps.Policy.Engine.Adapters; using StellaOps.Policy.Exceptions.Models; using Xunit; namespace StellaOps.Policy.Engine.Tests.Adapters; /// /// Unit tests for ExceptionEffectRegistry. /// public sealed class ExceptionEffectRegistryTests { private readonly IExceptionEffectRegistry _registry; public ExceptionEffectRegistryTests() { _registry = new ExceptionEffectRegistry(); } [Theory] [InlineData(ExceptionType.Vulnerability, ExceptionReason.FalsePositive, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.AcceptedRisk, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.CompensatingControl, PolicyExceptionEffectType.RequireControl)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.TestOnly, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.VendorNotAffected, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.ScheduledFix, PolicyExceptionEffectType.Defer)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.RuntimeMitigation, PolicyExceptionEffectType.Downgrade)] [InlineData(ExceptionType.Vulnerability, ExceptionReason.NetworkIsolation, PolicyExceptionEffectType.Downgrade)] public void GetEffect_ReturnsCorrectEffect_ForVulnerabilityType( ExceptionType type, ExceptionReason reason, PolicyExceptionEffectType expectedEffect) { // Act var effect = _registry.GetEffect(type, reason); // Assert effect.Should().NotBeNull(); effect.Effect.Should().Be(expectedEffect); } [Theory] [InlineData(ExceptionType.Policy, ExceptionReason.FalsePositive, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Policy, ExceptionReason.AcceptedRisk, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Policy, ExceptionReason.CompensatingControl, PolicyExceptionEffectType.RequireControl)] [InlineData(ExceptionType.Policy, ExceptionReason.ScheduledFix, PolicyExceptionEffectType.Defer)] public void GetEffect_ReturnsCorrectEffect_ForPolicyType( ExceptionType type, ExceptionReason reason, PolicyExceptionEffectType expectedEffect) { // Act var effect = _registry.GetEffect(type, reason); // Assert effect.Should().NotBeNull(); effect.Effect.Should().Be(expectedEffect); } [Theory] [InlineData(ExceptionType.Unknown, ExceptionReason.FalsePositive, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Unknown, ExceptionReason.ScheduledFix, PolicyExceptionEffectType.Defer)] public void GetEffect_ReturnsCorrectEffect_ForUnknownType( ExceptionType type, ExceptionReason reason, PolicyExceptionEffectType expectedEffect) { // Act var effect = _registry.GetEffect(type, reason); // Assert effect.Should().NotBeNull(); effect.Effect.Should().Be(expectedEffect); } [Theory] [InlineData(ExceptionType.Component, ExceptionReason.DeprecationInProgress, PolicyExceptionEffectType.Suppress)] [InlineData(ExceptionType.Component, ExceptionReason.Other, PolicyExceptionEffectType.Suppress)] // License waiver public void GetEffect_ReturnsCorrectEffect_ForComponentType( ExceptionType type, ExceptionReason reason, PolicyExceptionEffectType expectedEffect) { // Act var effect = _registry.GetEffect(type, reason); // Assert effect.Should().NotBeNull(); effect.Effect.Should().Be(expectedEffect); } [Fact] public void GetEffect_ReturnsDefaultDeferral_ForUnmappedCombination() { // Note: All combinations are mapped, so we test a hypothetical case // by checking that the registry handles all known combinations var allTypes = Enum.GetValues(); var allReasons = Enum.GetValues(); foreach (var type in allTypes) { foreach (var reason in allReasons) { // Act var effect = _registry.GetEffect(type, reason); // Assert - should never be null effect.Should().NotBeNull(); effect.Id.Should().NotBeNullOrEmpty(); effect.Effect.Should().BeOneOf( PolicyExceptionEffectType.Suppress, PolicyExceptionEffectType.Defer, PolicyExceptionEffectType.Downgrade, PolicyExceptionEffectType.RequireControl); } } } [Fact] public void GetAllEffects_ReturnsDistinctEffects() { // Act var allEffects = _registry.GetAllEffects(); // Assert allEffects.Should().NotBeEmpty(); allEffects.Should().OnlyHaveUniqueItems(e => e.Id); } [Fact] public void GetEffectById_ReturnsEffect_WhenExists() { // Act var effect = _registry.GetEffectById("suppress"); // Assert effect.Should().NotBeNull(); effect!.Id.Should().Be("suppress"); effect.Effect.Should().Be(PolicyExceptionEffectType.Suppress); } [Fact] public void GetEffectById_ReturnsNull_WhenNotExists() { // Act var effect = _registry.GetEffectById("non-existent-effect-id"); // Assert effect.Should().BeNull(); } [Fact] public void GetEffectById_IsCaseInsensitive() { // Act var effect1 = _registry.GetEffectById("SUPPRESS"); var effect2 = _registry.GetEffectById("suppress"); var effect3 = _registry.GetEffectById("Suppress"); // Assert effect1.Should().Be(effect2); effect2.Should().Be(effect3); } [Fact] public void Effects_HaveValidProperties() { // Act var allEffects = _registry.GetAllEffects(); // Assert foreach (var effect in allEffects) { effect.Id.Should().NotBeNullOrWhiteSpace(); effect.Name.Should().NotBeNullOrWhiteSpace(); effect.Description.Should().NotBeNullOrWhiteSpace(); effect.MaxDurationDays.Should().BeGreaterThan(0); } } [Fact] public void DowngradeEffects_HaveValidSeverity() { // Act var downgradeEffects = _registry.GetAllEffects() .Where(e => e.Effect == PolicyExceptionEffectType.Downgrade); // Assert foreach (var effect in downgradeEffects) { effect.DowngradeSeverity.Should().NotBeNull(); } } [Fact] public void RequireControlEffects_HaveControlId() { // Act var requireControlEffects = _registry.GetAllEffects() .Where(e => e.Effect == PolicyExceptionEffectType.RequireControl); // Assert foreach (var effect in requireControlEffects) { effect.RequiredControlId.Should().NotBeNullOrWhiteSpace(); } } [Fact] public void SuppressEffects_DoNotRequireControl() { // Act var suppressEffects = _registry.GetAllEffects() .Where(e => e.Effect == PolicyExceptionEffectType.Suppress); // Assert foreach (var effect in suppressEffects) { // Suppress effects should not require controls effect.RequiredControlId.Should().BeNull(); } } }