using StellaOps.Concelier.BackportProof.Models; using Xunit; namespace StellaOps.Concelier.BackportProof.Tests; /// /// Tests for PackageEcosystem enum. /// public sealed class PackageEcosystemTests { [Theory] [InlineData(PackageEcosystem.Deb)] [InlineData(PackageEcosystem.Rpm)] [InlineData(PackageEcosystem.Apk)] [InlineData(PackageEcosystem.Unknown)] public void PackageEcosystem_AllValues_AreDefined(PackageEcosystem ecosystem) { Assert.True(Enum.IsDefined(ecosystem)); } [Fact] public void PackageEcosystem_AllValues_AreCounted() { var values = Enum.GetValues(); Assert.Equal(4, values.Length); } } /// /// Tests for ProductContext record. /// public sealed class ProductContextTests { [Fact] public void ProductContext_RequiredProperties_MustBeSet() { var context = new ProductContext( Distro: "debian", Release: "bookworm", RepoScope: "main", Architecture: "amd64"); Assert.Equal("debian", context.Distro); Assert.Equal("bookworm", context.Release); Assert.Equal("main", context.RepoScope); Assert.Equal("amd64", context.Architecture); } [Fact] public void ProductContext_OptionalProperties_CanBeNull() { var context = new ProductContext( Distro: "alpine", Release: "3.19", RepoScope: null, Architecture: null); Assert.Null(context.RepoScope); Assert.Null(context.Architecture); } [Fact] public void ProductContext_RecordEquality_WorksCorrectly() { var c1 = new ProductContext("rhel", "9", "main", "x86_64"); var c2 = new ProductContext("rhel", "9", "main", "x86_64"); Assert.Equal(c1, c2); } } /// /// Tests for PackageKey record. /// public sealed class PackageKeyTests { [Fact] public void PackageKey_RequiredProperties_MustBeSet() { var key = new PackageKey( Ecosystem: PackageEcosystem.Deb, PackageName: "nginx", SourcePackageName: "nginx"); Assert.Equal(PackageEcosystem.Deb, key.Ecosystem); Assert.Equal("nginx", key.PackageName); Assert.Equal("nginx", key.SourcePackageName); } [Fact] public void PackageKey_SourcePackage_CanBeNull() { var key = new PackageKey( Ecosystem: PackageEcosystem.Rpm, PackageName: "httpd", SourcePackageName: null); Assert.Null(key.SourcePackageName); } } /// /// Tests for EvidenceTier enum. /// public sealed class EvidenceTierTests { [Theory] [InlineData(EvidenceTier.Unknown, 0)] [InlineData(EvidenceTier.NvdRange, 5)] [InlineData(EvidenceTier.UpstreamCommit, 4)] [InlineData(EvidenceTier.SourcePatch, 3)] [InlineData(EvidenceTier.Changelog, 2)] [InlineData(EvidenceTier.DistroOval, 1)] public void EvidenceTier_Values_HaveCorrectNumericValue(EvidenceTier tier, int expected) { Assert.Equal(expected, (int)tier); } [Fact] public void EvidenceTier_DistroOval_IsHighestConfidence() { // Tier 1 is highest confidence (lowest numeric value) var allTiers = Enum.GetValues().Where(t => t != EvidenceTier.Unknown); var highestConfidence = allTiers.OrderBy(t => (int)t).First(); Assert.Equal(EvidenceTier.DistroOval, highestConfidence); } [Fact] public void EvidenceTier_NvdRange_IsLowestConfidence() { // Tier 5 is lowest confidence (highest numeric value) var allTiers = Enum.GetValues().Where(t => t != EvidenceTier.Unknown); var lowestConfidence = allTiers.OrderByDescending(t => (int)t).First(); Assert.Equal(EvidenceTier.NvdRange, lowestConfidence); } } /// /// Tests for FixStatus enum. /// public sealed class FixStatusTests { [Theory] [InlineData(FixStatus.Patched)] [InlineData(FixStatus.Vulnerable)] [InlineData(FixStatus.NotAffected)] [InlineData(FixStatus.WontFix)] [InlineData(FixStatus.UnderInvestigation)] [InlineData(FixStatus.Unknown)] public void FixStatus_AllValues_AreDefined(FixStatus status) { Assert.True(Enum.IsDefined(status)); } [Fact] public void FixStatus_AllValues_AreCounted() { var values = Enum.GetValues(); Assert.Equal(6, values.Length); } } /// /// Tests for RulePriority enum. /// public sealed class RulePriorityTests { [Fact] public void RulePriority_DistroNativeOval_IsHighestPriority() { var allPriorities = Enum.GetValues(); var highest = allPriorities.Max(p => (int)p); Assert.Equal((int)RulePriority.DistroNativeOval, highest); Assert.Equal(100, highest); } [Fact] public void RulePriority_NvdRangeHeuristic_IsLowestPriority() { var allPriorities = Enum.GetValues(); var lowest = allPriorities.Min(p => (int)p); Assert.Equal((int)RulePriority.NvdRangeHeuristic, lowest); Assert.Equal(20, lowest); } [Fact] public void RulePriority_LegacyAliases_MatchNewValues() { Assert.Equal(RulePriority.DistroNativeOval, RulePriority.DistroNative); Assert.Equal(RulePriority.ChangelogExplicitCve, RulePriority.VendorCsaf); Assert.Equal(RulePriority.NvdRangeHeuristic, RulePriority.ThirdParty); } [Theory] [InlineData(RulePriority.NvdRangeHeuristic, 20)] [InlineData(RulePriority.UpstreamCommitPartialMatch, 45)] [InlineData(RulePriority.UpstreamCommitExactParity, 55)] [InlineData(RulePriority.SourcePatchFuzzyMatch, 60)] [InlineData(RulePriority.SourcePatchExactMatch, 70)] [InlineData(RulePriority.ChangelogBugIdMapped, 75)] [InlineData(RulePriority.ChangelogExplicitCve, 85)] [InlineData(RulePriority.DerivativeOvalMedium, 90)] [InlineData(RulePriority.DerivativeOvalHigh, 95)] [InlineData(RulePriority.DistroNativeOval, 100)] public void RulePriority_Values_HaveCorrectNumericValue(RulePriority priority, int expected) { Assert.Equal(expected, (int)priority); } } /// /// Tests for EvidencePointer record. /// public sealed class EvidencePointerTests { [Fact] public void EvidencePointer_RequiredProperties_MustBeSet() { var fetchedAt = DateTimeOffset.UtcNow; var pointer = new EvidencePointer( SourceType: "debian-tracker", SourceUrl: "https://security-tracker.debian.org/tracker/CVE-2024-0001", SourceDigest: "sha256:abc123", FetchedAt: fetchedAt, TierSource: EvidenceTier.DistroOval); Assert.Equal("debian-tracker", pointer.SourceType); Assert.Equal("https://security-tracker.debian.org/tracker/CVE-2024-0001", pointer.SourceUrl); Assert.Equal("sha256:abc123", pointer.SourceDigest); Assert.Equal(fetchedAt, pointer.FetchedAt); Assert.Equal(EvidenceTier.DistroOval, pointer.TierSource); } [Fact] public void EvidencePointer_TierSource_DefaultsToUnknown() { var pointer = new EvidencePointer( SourceType: "nvd", SourceUrl: "https://nvd.nist.gov/vuln/detail/CVE-2024-0001", SourceDigest: null, FetchedAt: DateTimeOffset.UtcNow); Assert.Equal(EvidenceTier.Unknown, pointer.TierSource); } } /// /// Tests for VersionRange record. /// public sealed class VersionRangeTests { [Fact] public void VersionRange_FullRange_ContainsAllBoundaries() { var range = new VersionRange( MinVersion: "1.0.0", MinInclusive: true, MaxVersion: "2.0.0", MaxInclusive: false); Assert.Equal("1.0.0", range.MinVersion); Assert.True(range.MinInclusive); Assert.Equal("2.0.0", range.MaxVersion); Assert.False(range.MaxInclusive); } [Fact] public void VersionRange_OpenEnded_AllowsNullBoundaries() { // All versions up to 2.0.0 (exclusive) var range = new VersionRange( MinVersion: null, MinInclusive: false, MaxVersion: "2.0.0", MaxInclusive: false); Assert.Null(range.MinVersion); Assert.Equal("2.0.0", range.MaxVersion); } }