using FluentAssertions;
using StellaOps.Policy.Engine.DeterminismGuard;
using Xunit;
namespace StellaOps.Policy.Engine.Tests.DeterminismGuard;
///
/// Deep verification tests for determinism guards covering pattern detection gaps,
/// ValidateContext, FailOnSeverity threshold, GuardedPolicyEvaluatorBuilder,
/// floating-point/unstable-iteration warnings, socket detection, and scope lifecycle.
///
public sealed class DeterminismGuardDeepTests
{
#region Additional Pattern Detection
[Fact]
public void AnalyzeSource_DetectsDateTimeOffsetNow()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "var now = DateTimeOffset.Now;";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.ViolationType == "DateTimeOffset.Now" &&
v.Category == DeterminismViolationCategory.WallClock);
}
[Fact]
public void AnalyzeSource_DetectsDateTimeOffsetUtcNow()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "var now = DateTimeOffset.UtcNow;";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.ViolationType == "DateTimeOffset.UtcNow" &&
v.Category == DeterminismViolationCategory.WallClock);
}
[Fact]
public void AnalyzeSource_DetectsCryptoRandom()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "var bytes = RandomNumberGenerator.GetBytes(32);";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.ViolationType == "RandomNumberGenerator" &&
v.Category == DeterminismViolationCategory.RandomNumber);
}
[Fact]
public void AnalyzeSource_DetectsSocketClasses()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = """
var tcp = new TcpClient("localhost", 80);
var udp = new UdpClient(9090);
var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
""";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().HaveCount(3);
result.Violations.Should().OnlyContain(v =>
v.Category == DeterminismViolationCategory.NetworkAccess &&
v.Severity == DeterminismViolationSeverity.Critical);
}
[Fact]
public void AnalyzeSource_DetectsWebClient()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "using var client = new WebClient();";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.ViolationType == "WebClient" &&
v.Category == DeterminismViolationCategory.NetworkAccess);
}
[Fact]
public void AnalyzeSource_DetectsEnvironmentMachineName()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "var name = Environment.MachineName;";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.ViolationType == "Environment.MachineName" &&
v.Category == DeterminismViolationCategory.EnvironmentAccess &&
v.Severity == DeterminismViolationSeverity.Warning);
}
[Fact]
public void AnalyzeSource_DetectsFloatingPointComparison()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "double score == 7.5;";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.Category == DeterminismViolationCategory.FloatingPointHazard &&
v.Severity == DeterminismViolationSeverity.Warning);
}
[Fact]
public void AnalyzeSource_DetectsDictionaryIteration()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "foreach (var item in myDictionary)";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.Category == DeterminismViolationCategory.UnstableIteration);
}
[Fact]
public void AnalyzeSource_DetectsHashSetIteration()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = "foreach (var item in myHashSet)";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().ContainSingle(v =>
v.Category == DeterminismViolationCategory.UnstableIteration);
}
[Fact]
public void AnalyzeSource_MultipleViolationCategories_ReportsAll()
{
var analyzer = new ProhibitedPatternAnalyzer();
var source = """
var now = DateTime.Now;
var rng = new Random();
var id = Guid.NewGuid();
private readonly HttpClient _client = new();
""";
var result = analyzer.AnalyzeSource(source, "test.cs", DeterminismGuardOptions.Default);
result.Violations.Should().HaveCountGreaterThanOrEqualTo(4);
result.Violations.Select(v => v.Category).Distinct()
.Should().Contain(DeterminismViolationCategory.WallClock)
.And.Contain(DeterminismViolationCategory.RandomNumber)
.And.Contain(DeterminismViolationCategory.GuidGeneration)
.And.Contain(DeterminismViolationCategory.NetworkAccess);
}
#endregion
#region ValidateContext Tests
[Fact]
public void ValidateContext_NullContext_DetectsViolation()
{
var guard = new DeterminismGuardService();
var result = guard.ValidateContext