using StellaOps.Signals.Contracts;
using Xunit;
namespace StellaOps.Signals.Contracts.Tests;
///
/// Tests for SignalEnvelope model.
///
public sealed class SignalEnvelopeTests
{
[Fact]
public void SignalEnvelope_RequiredProperties_MustBeSet()
{
var envelope = new SignalEnvelope
{
SignalKey = "pkg:npm/lodash@4.17.21:reachability",
SignalType = SignalType.Reachability,
Value = new { reachable = true, confidence = 0.95 },
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "reachability-analyzer"
};
Assert.Equal("pkg:npm/lodash@4.17.21:reachability", envelope.SignalKey);
Assert.Equal(SignalType.Reachability, envelope.SignalType);
Assert.Equal("reachability-analyzer", envelope.SourceService);
}
[Theory]
[InlineData(SignalType.Reachability)]
[InlineData(SignalType.Entropy)]
[InlineData(SignalType.Exploitability)]
[InlineData(SignalType.Trust)]
[InlineData(SignalType.UnknownSymbol)]
[InlineData(SignalType.Custom)]
public void SignalEnvelope_SignalType_AllValues_AreValid(SignalType type)
{
var envelope = new SignalEnvelope
{
SignalKey = $"test:{type.ToString().ToLowerInvariant()}",
SignalType = type,
Value = new { test = true },
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "test-service"
};
Assert.Equal(type, envelope.SignalType);
}
[Fact]
public void SignalEnvelope_DefaultSchemaVersion_IsOne()
{
var envelope = new SignalEnvelope
{
SignalKey = "test:schema",
SignalType = SignalType.Custom,
Value = new { },
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "test"
};
Assert.Equal("1.0", envelope.SchemaVersion);
}
[Fact]
public void SignalEnvelope_OptionalProperties_AreNullByDefault()
{
var envelope = new SignalEnvelope
{
SignalKey = "test:optional",
SignalType = SignalType.Reachability,
Value = new { },
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "test"
};
Assert.Null(envelope.TenantId);
Assert.Null(envelope.CorrelationId);
Assert.Null(envelope.ProvenanceDigest);
}
[Fact]
public void SignalEnvelope_WithAllOptionalProperties_ContainsValues()
{
var envelope = new SignalEnvelope
{
SignalKey = "pkg:pypi/django@4.2.0:trust",
SignalType = SignalType.Trust,
Value = new { score = 0.85 },
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "trust-engine",
TenantId = "tenant-001",
CorrelationId = "corr-abc123",
ProvenanceDigest = "sha256:xyz789",
SchemaVersion = "2.0"
};
Assert.Equal("tenant-001", envelope.TenantId);
Assert.Equal("corr-abc123", envelope.CorrelationId);
Assert.Equal("sha256:xyz789", envelope.ProvenanceDigest);
Assert.Equal("2.0", envelope.SchemaVersion);
}
[Fact]
public void SignalEnvelope_Value_CanBeAnyObject()
{
var reachabilityValue = new
{
reachable = true,
paths = new[] { "main->helper->vulnerable" },
confidence = 0.92
};
var envelope = new SignalEnvelope
{
SignalKey = "test:value",
SignalType = SignalType.Reachability,
Value = reachabilityValue,
ComputedAt = DateTimeOffset.UtcNow,
SourceService = "analyzer"
};
Assert.NotNull(envelope.Value);
}
[Fact]
public void SignalEnvelope_RecordEquality_WorksCorrectly()
{
var computedAt = DateTimeOffset.UtcNow;
var value = new { test = 123 };
var envelope1 = new SignalEnvelope
{
SignalKey = "test:eq",
SignalType = SignalType.Entropy,
Value = value,
ComputedAt = computedAt,
SourceService = "test"
};
var envelope2 = new SignalEnvelope
{
SignalKey = "test:eq",
SignalType = SignalType.Entropy,
Value = value,
ComputedAt = computedAt,
SourceService = "test"
};
Assert.Equal(envelope1, envelope2);
}
}
///
/// Tests for SignalType enum.
///
public sealed class SignalTypeTests
{
[Fact]
public void SignalType_AllDefinedValues_AreCounted()
{
var values = Enum.GetValues();
// Ensure we have expected signal types
Assert.Equal(6, values.Length);
}
[Fact]
public void SignalType_Reachability_HasValue()
{
Assert.Equal(0, (int)SignalType.Reachability);
}
[Fact]
public void SignalType_Custom_IsLast()
{
var values = Enum.GetValues();
var last = values.Max();
Assert.Equal(SignalType.Custom, last);
}
}