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();
}
}
}