using StellaOps.Concelier.Models; using Xunit; using StellaOps.TestKit; namespace StellaOps.Concelier.Models.Tests; public sealed class SemVerPrimitiveTests { [Trait("Category", TestCategories.Unit)] [Theory] [InlineData("1.0.0", true, "2.0.0", false, null, false, null, null, SemVerPrimitiveStyles.Range)] [InlineData("1.0.0", true, null, false, null, false, null, null, SemVerPrimitiveStyles.GreaterThanOrEqual)] [InlineData("1.0.0", false, null, false, null, false, null, null, SemVerPrimitiveStyles.GreaterThan)] [InlineData(null, true, "2.0.0", false, null, false, null, null, SemVerPrimitiveStyles.LessThan)] [InlineData(null, true, "2.0.0", true, null, false, null, null, SemVerPrimitiveStyles.LessThanOrEqual)] [InlineData(null, true, null, false, "2.0.0", true, null, null, SemVerPrimitiveStyles.LessThanOrEqual)] [InlineData(null, true, null, false, "2.0.0", false, null, null, SemVerPrimitiveStyles.LessThan)] [InlineData(null, true, null, false, null, false, null, "1.5.0", SemVerPrimitiveStyles.Exact)] public void StyleReflectsSemantics( string? introduced, bool introducedInclusive, string? fixedVersion, bool fixedInclusive, string? lastAffected, bool lastAffectedInclusive, string? constraintExpression, string? exactValue, string expectedStyle) { var primitive = new SemVerPrimitive( introduced, introducedInclusive, fixedVersion, fixedInclusive, lastAffected, lastAffectedInclusive, constraintExpression, exactValue); Assert.Equal(expectedStyle, primitive.Style); } [Trait("Category", TestCategories.Unit)] [Fact] public void EqualityIncludesExactValue() { var baseline = new SemVerPrimitive( Introduced: null, IntroducedInclusive: true, Fixed: null, FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: null); var variant = baseline with { ExactValue = "1.2.3" }; Assert.NotEqual(baseline, variant); Assert.Equal(SemVerPrimitiveStyles.Exact, variant.Style); Assert.Equal(SemVerPrimitiveStyles.Range, baseline.Style); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_MapsRangeBounds() { var primitive = new SemVerPrimitive( Introduced: "1.0.0", IntroducedInclusive: true, Fixed: "2.0.0", FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: ">=1.0.0 <2.0.0"); var rule = primitive.ToNormalizedVersionRule(); Assert.NotNull(rule); Assert.Equal(NormalizedVersionSchemes.SemVer, rule!.Scheme); Assert.Equal(NormalizedVersionRuleTypes.Range, rule.Type); Assert.Equal("1.0.0", rule.Min); Assert.True(rule.MinInclusive); Assert.Equal("2.0.0", rule.Max); Assert.False(rule.MaxInclusive); Assert.Null(rule.Value); Assert.Equal(">=1.0.0 <2.0.0", rule.Notes); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_ExactUsesExactValue() { var primitive = new SemVerPrimitive( Introduced: null, IntroducedInclusive: true, Fixed: null, FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: null, ExactValue: "3.1.4"); var rule = primitive.ToNormalizedVersionRule("from-ghsa"); Assert.NotNull(rule); Assert.Equal(NormalizedVersionSchemes.SemVer, rule!.Scheme); Assert.Equal(NormalizedVersionRuleTypes.Exact, rule.Type); Assert.Null(rule.Min); Assert.Null(rule.Max); Assert.Equal("3.1.4", rule.Value); Assert.Equal("from-ghsa", rule.Notes); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_GreaterThanMapsMinimum() { var primitive = new SemVerPrimitive( Introduced: "1.5.0", IntroducedInclusive: false, Fixed: null, FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: null); var rule = primitive.ToNormalizedVersionRule(); Assert.NotNull(rule); Assert.Equal(NormalizedVersionSchemes.SemVer, rule!.Scheme); Assert.Equal(NormalizedVersionRuleTypes.GreaterThan, rule.Type); Assert.Equal("1.5.0", rule.Min); Assert.False(rule.MinInclusive); Assert.Null(rule.Max); Assert.Null(rule.Value); Assert.Null(rule.Notes); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_UsesConstraintExpressionAsFallbackNotes() { var primitive = new SemVerPrimitive( Introduced: "1.4.0", IntroducedInclusive: false, Fixed: null, FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: "> 1.4.0"); var rule = primitive.ToNormalizedVersionRule(); Assert.NotNull(rule); Assert.Equal("> 1.4.0", rule!.Notes); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_ExactCarriesConstraintExpressionWhenNotesMissing() { var primitive = new SemVerPrimitive( Introduced: null, IntroducedInclusive: true, Fixed: null, FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: "= 3.2.1", ExactValue: "3.2.1"); var rule = primitive.ToNormalizedVersionRule(); Assert.NotNull(rule); Assert.Equal(NormalizedVersionRuleTypes.Exact, rule!.Type); Assert.Equal("3.2.1", rule.Value); Assert.Equal("= 3.2.1", rule.Notes); } [Trait("Category", TestCategories.Unit)] [Fact] public void ToNormalizedVersionRule_ExplicitNotesOverrideConstraintExpression() { var primitive = new SemVerPrimitive( Introduced: "1.0.0", IntroducedInclusive: true, Fixed: "1.1.0", FixedInclusive: false, LastAffected: null, LastAffectedInclusive: false, ConstraintExpression: ">=1.0.0 <1.1.0"); var rule = primitive.ToNormalizedVersionRule("ghsa:range"); Assert.NotNull(rule); Assert.Equal("ghsa:range", rule!.Notes); } }