Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests from node-semver #56

Merged
merged 5 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/SemanticVersioning/Desugarer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ public static Tuple<int, Comparator[]> TildeRange(string spec)
Version maxVersion = null;

var version = new PartialVersion(match.Groups[1].Value);
if (version.Minor.HasValue)
if (!version.Major.HasValue)
{
// ~x: any versions
minVersion = version.ToZeroVersion();
}
else if (version.Minor.HasValue)
{
// Doesn't matter whether patch version is null or not,
// the logic is the same, min patch version will be zero if null.
Expand Down Expand Up @@ -62,7 +67,12 @@ public static Tuple<int, Comparator[]> CaretRange(string spec)

var version = new PartialVersion(match.Groups[1].Value);

if (version.Major.Value > 0)
if (!version.Major.HasValue)
{
// ^x: any versions
minVersion = version.ToZeroVersion();
}
else if (version.Major.Value > 0)
{
// Don't allow major version change
minVersion = version.ToZeroVersion();
Expand Down Expand Up @@ -95,7 +105,7 @@ public static Tuple<int, Comparator[]> CaretRange(string spec)

return Tuple.Create(
match.Length,
MinMaxComparators(minVersion, maxVersion, minOperator: Comparator.Operator.GreaterThanOrEqualIncludingPrereleases));
MinMaxComparators(minVersion, maxVersion));
}

public static Tuple<int, Comparator[]> HyphenRange(string spec)
Expand Down
2 changes: 1 addition & 1 deletion test/SemanticVersioning.Tests/AdvancedRanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void TestTildeRanges(string range,
public void TestCaretRanges(string range, string comparatorVersionA, string comparatorVersionB)
{
var comparatorA = new Comparator(
Comparator.Operator.GreaterThanOrEqualIncludingPrereleases, Version.Parse(comparatorVersionA));
Comparator.Operator.GreaterThanOrEqual, Version.Parse(comparatorVersionA));
var comparatorB = new Comparator(
Comparator.Operator.LessThanExcludingPrereleases, Version.Parse(comparatorVersionB));
var comparators = Desugarer.CaretRange(range).Item2;
Expand Down
252 changes: 252 additions & 0 deletions test/SemanticVersioning.Tests/NodeSemverTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
using Xunit;

namespace SemanticVersioning.Tests
{
public class NodeSemverTest
{
// test set are from node-semver
// Copyright (c) Isaac Z. Schlueter and Contributors
// Originally under The ISC License
// https://github.com/npm/node-semver/blob/09c69e23cdf6c69c51f83635482fff89ab2574e3/test/fixtures/range-include.js
[Theory]
[InlineData("1.0.0 - 2.0.0", "1.2.3")]
[InlineData("^1.2.3+build", "1.2.3")]
[InlineData("^1.2.3+build", "1.3.0")]
[InlineData("1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3")]
//[InlineData("1.2.3pre+asdf - 2.4.3-pre+asdf", "1.2.3", true)] // loose
//[InlineData("1.2.3-pre+asdf - 2.4.3pre+asdf", "1.2.3", true)] // loose
//[InlineData("1.2.3pre+asdf - 2.4.3pre+asdf", "1.2.3", true)] // loose
[InlineData("1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3-pre.2")]
[InlineData("1.2.3-pre+asdf - 2.4.3-pre+asdf", "2.4.3-alpha")]
[InlineData("1.2.3+asdf - 2.4.3+asdf", "1.2.3")]
[InlineData("1.0.0", "1.0.0")]
[InlineData(">=*", "0.2.4")]
[InlineData("", "1.0.0")]
//[InlineData("*", "1.2.3", {})] // loose
//[InlineData("*", "v1.2.3", { loose: 123 })] // loose
//[InlineData(">=1.0.0", "1.0.0", /asdf/)] // loose
//[InlineData(">=1.0.0", "1.0.1", { loose: null })] // loose
//[InlineData(">=1.0.0", "1.1.0", { loose: 0 })] // loose
//[InlineData(">1.0.0", "1.0.1", { loose: undefined })] // loose
[InlineData(">1.0.0", "1.1.0")]
[InlineData("<=2.0.0", "2.0.0")]
[InlineData("<=2.0.0", "1.9999.9999")]
[InlineData("<=2.0.0", "0.2.9")]
[InlineData("<2.0.0", "1.9999.9999")]
[InlineData("<2.0.0", "0.2.9")]
[InlineData(">= 1.0.0", "1.0.0")]
[InlineData(">= 1.0.0", "1.0.1")]
[InlineData(">= 1.0.0", "1.1.0")]
[InlineData("> 1.0.0", "1.0.1")]
[InlineData("> 1.0.0", "1.1.0")]
[InlineData("<= 2.0.0", "2.0.0")]
[InlineData("<= 2.0.0", "1.9999.9999")]
[InlineData("<= 2.0.0", "0.2.9")]
[InlineData("< 2.0.0", "1.9999.9999")]
[InlineData("<\t2.0.0", "0.2.9")]
[InlineData(">=0.1.97", "v0.1.97", true)]
[InlineData(">=0.1.97", "0.1.97")]
[InlineData("0.1.20 || 1.2.4", "1.2.4")]
[InlineData(">=0.2.3 || <0.0.1", "0.0.0")]
[InlineData(">=0.2.3 || <0.0.1", "0.2.3")]
[InlineData(">=0.2.3 || <0.0.1", "0.2.4")]
[InlineData("||", "1.3.4")]
[InlineData("2.x.x", "2.1.3")]
[InlineData("1.2.x", "1.2.3")]
[InlineData("1.2.x || 2.x", "2.1.3")]
[InlineData("1.2.x || 2.x", "1.2.3")]
[InlineData("x", "1.2.3")]
[InlineData("2.*.*", "2.1.3")]
[InlineData("1.2.*", "1.2.3")]
[InlineData("1.2.* || 2.*", "2.1.3")]
[InlineData("1.2.* || 2.*", "1.2.3")]
[InlineData("*", "1.2.3")]
[InlineData("2", "2.1.2")]
[InlineData("2.3", "2.3.1")]
[InlineData("~0.0.1", "0.0.1")]
[InlineData("~0.0.1", "0.0.2")]
[InlineData("~x", "0.0.9")] // >=2.4.0 <2.5.0
[InlineData("~2", "2.0.9")] // >=2.4.0 <2.5.0
[InlineData("~2.4", "2.4.0")] // >=2.4.0 <2.5.0
[InlineData("~2.4", "2.4.5")]
//[InlineData("~>3.2.1", "3.2.2")] // >=3.2.1 <3.3.0, // ~> is not supported
[InlineData("~1", "1.2.3")] // >=1.0.0 <2.0.0
//[InlineData("~>1", "1.2.3")] // ~> is not supported
//[InlineData("~> 1", "1.2.3")] // ~> is not supported
[InlineData("~1.0", "1.0.2")] // >=1.0.0 <1.1.0,
[InlineData("~ 1.0", "1.0.2")]
[InlineData("~ 1.0.3", "1.0.12")]
//[InlineData("~ 1.0.3alpha", "1.0.12", { loose: true })] // loose
[InlineData(">=1", "1.0.0")]
[InlineData(">= 1", "1.0.0")]
[InlineData("<1.2", "1.1.1")]
[InlineData("< 1.2", "1.1.1")]
[InlineData("~v0.5.4-pre", "0.5.5")]
[InlineData("~v0.5.4-pre", "0.5.4")]
[InlineData("=0.7.x", "0.7.2")]
[InlineData("<=0.7.x", "0.7.2")]
[InlineData(">=0.7.x", "0.7.2")]
[InlineData("<=0.7.x", "0.6.2")]
[InlineData("~1.2.1 >=1.2.3", "1.2.3")]
[InlineData("~1.2.1 =1.2.3", "1.2.3")]
[InlineData("~1.2.1 1.2.3", "1.2.3")]
[InlineData("~1.2.1 >=1.2.3 1.2.3", "1.2.3")]
[InlineData("~1.2.1 1.2.3 >=1.2.3", "1.2.3")]
[InlineData(">=1.2.1 1.2.3", "1.2.3")]
[InlineData("1.2.3 >=1.2.1", "1.2.3")]
[InlineData(">=1.2.3 >=1.2.1", "1.2.3")]
[InlineData(">=1.2.1 >=1.2.3", "1.2.3")]
[InlineData(">=1.2", "1.2.8")]
[InlineData("^1.2.3", "1.8.1")]
[InlineData("^0.1.2", "0.1.2")]
[InlineData("^0.1", "0.1.2")]
[InlineData("^0.0.1", "0.0.1")]
[InlineData("^1.2", "1.4.2")]
[InlineData("^1.2 ^1", "1.4.2")]
[InlineData("^1.2.3-alpha", "1.2.3-pre")]
[InlineData("^1.2.0-alpha", "1.2.0-pre")]
[InlineData("^0.0.1-alpha", "0.0.1-beta")]
[InlineData("^0.0.1-alpha", "0.0.1")]
[InlineData("^0.1.1-alpha", "0.1.1-beta")]
[InlineData("^x", "1.2.3")]
[InlineData("x - 1.0.0", "0.9.7")]
[InlineData("x - 1.x", "0.9.7")]
[InlineData("1.0.0 - x", "1.9.7")]
[InlineData("1.x - x", "1.9.7")]
[InlineData("<=7.x", "7.9.9")]
[InlineData("2.x", "2.0.0-pre.0", true)]
[InlineData("2.x", "2.1.0-pre.0", true)]
[InlineData("1.1.x", "1.1.0-a", true)]
[InlineData("1.1.x", "1.1.1-a", true)]
[InlineData("*", "1.0.0-rc1", true)]
[InlineData("^1.0.0-0", "1.0.1-rc1", true)]
[InlineData("^1.0.0-rc2", "1.0.1-rc1", true)]
[InlineData("^1.0.0", "1.0.1-rc1", true)]
[InlineData("^1.0.0", "1.1.0-rc1", true)]
[InlineData("1 - 2", "2.0.0-pre", true)]
[InlineData("1 - 2", "1.0.0-pre", true)]
[InlineData("1.0 - 2", "1.0.0-pre", true)]

[InlineData("=0.7.x", "0.7.0-asdf", true)]
[InlineData(">=0.7.x", "0.7.0-asdf", true)]
[InlineData("<=0.7.x", "0.7.0-asdf", true)]

[InlineData(">=1.0.0 <=1.1.0", "1.1.0-pre", true)]
public void TestPositive(string range, string version, bool includePrerelease = false)
{
Assert.True(new Range(range).IsSatisfied(new Version(version), includePrerelease));
}

// test set are from node-semver
// Copyright (c) Isaac Z. Schlueter and Contributors
// Originally under The ISC License
// https://github.com/npm/node-semver/blob/09c69e23cdf6c69c51f83635482fff89ab2574e3/test/fixtures/range-exclude.js
[Theory]
[InlineData("1.0.0 - 2.0.0", "2.2.3")]
[InlineData("1.2.3+asdf - 2.4.3+asdf", "1.2.3-pre.2")]
[InlineData("1.2.3+asdf - 2.4.3+asdf", "2.4.3-alpha")]
[InlineData("^1.2.3+build", "2.0.0")]
[InlineData("^1.2.3+build", "1.2.0")]
[InlineData("^1.2.3", "1.2.3-pre")]
[InlineData("^1.2", "1.2.0-pre")]
[InlineData(">1.2", "1.3.0-beta")]
[InlineData("<=1.2.3", "1.2.3-beta")]
[InlineData("^1.2.3", "1.2.3-beta")]
[InlineData("=0.7.x", "0.7.0-asdf")]
[InlineData(">=0.7.x", "0.7.0-asdf")]
[InlineData("<=0.7.x", "0.7.0-asdf")]
//[InlineData("1", "1.0.0beta", { loose: 420 })] // loose
//[InlineData("<1", "1.0.0beta", true)] // loose
//[InlineData("< 1", "1.0.0beta", true)] // loose
[InlineData("1.0.0", "1.0.1")]
[InlineData(">=1.0.0", "0.0.0")]
[InlineData(">=1.0.0", "0.0.1")]
[InlineData(">=1.0.0", "0.1.0")]
[InlineData(">1.0.0", "0.0.1")]
[InlineData(">1.0.0", "0.1.0")]
[InlineData("<=2.0.0", "3.0.0")]
[InlineData("<=2.0.0", "2.9999.9999")]
[InlineData("<=2.0.0", "2.2.9")]
[InlineData("<2.0.0", "2.9999.9999")]
[InlineData("<2.0.0", "2.2.9")]
//[InlineData(">=0.1.97", "v0.1.93", true)] // loose
[InlineData(">=0.1.97", "0.1.93")]
[InlineData("0.1.20 || 1.2.4", "1.2.3")]
[InlineData(">=0.2.3 || <0.0.1", "0.0.3")]
[InlineData(">=0.2.3 || <0.0.1", "0.2.2")]
//[InlineData("2.x.x", "1.1.3", { loose: NaN })] // loose
[InlineData("2.x.x", "3.1.3")]
[InlineData("1.2.x", "1.3.3")]
[InlineData("1.2.x || 2.x", "3.1.3")]
[InlineData("1.2.x || 2.x", "1.1.3")]
[InlineData("2.*.*", "1.1.3")]
[InlineData("2.*.*", "3.1.3")]
[InlineData("1.2.*", "1.3.3")]
[InlineData("1.2.* || 2.*", "3.1.3")]
[InlineData("1.2.* || 2.*", "1.1.3")]
[InlineData("2", "1.1.2")]
[InlineData("2.3", "2.4.1")]
[InlineData("~0.0.1", "0.1.0-alpha")]
[InlineData("~0.0.1", "0.1.0")]
[InlineData("~2.4", "2.5.0")] // >=2.4.0 <2.5.0
[InlineData("~2.4", "2.3.9")]
//[InlineData("~>3.2.1", "3.3.2")] // >=3.2.1 <3.3.0 // ~> is not supported
//[InlineData("~>3.2.1", "3.2.0")] // >=3.2.1 <3.3.0 // ~> is not supported
[InlineData("~1", "0.2.3")] // >=1.0.0 <2.0.0
//[InlineData("~>1", "2.2.3")] // ~> is not supported
[InlineData("~1.0", "1.1.0")] // >=1.0.0 <1.1.0
[InlineData("<1", "1.0.0")]
[InlineData(">=1.2", "1.1.1")]
//[InlineData("1", "2.0.0beta", true)] // loose
[InlineData("~v0.5.4-beta", "0.5.4-alpha")]
[InlineData("=0.7.x", "0.8.2")]
[InlineData(">=0.7.x", "0.6.2")]
[InlineData("<0.7.x", "0.7.2")]
[InlineData("<1.2.3", "1.2.3-beta")]
[InlineData("=1.2.3", "1.2.3-beta")]
[InlineData(">1.2", "1.2.8")]
[InlineData("^0.0.1", "0.0.2-alpha")]
[InlineData("^0.0.1", "0.0.2")]
[InlineData("^1.2.3", "2.0.0-alpha")]
[InlineData("^1.2.3", "1.2.2")]
[InlineData("^1.2", "1.1.9")]
//[InlineData("*", "v1.2.3-foo", true)] // loose

// invalid versions never satisfy, but shouldn"t throw
// C#: Invalid version should throw exception
//[InlineData("*", "not a version")]
//[InlineData(">=2", "glorp")]
//[InlineData(">=2", false)]

[InlineData("2.x", "3.0.0-pre.0", true)]
[InlineData("^1.0.0", "1.0.0-rc1", true)]
[InlineData("^1.0.0", "2.0.0-rc1", true)]
[InlineData("^1.2.3-rc2", "2.0.0", true)]
[InlineData("^1.0.0", "2.0.0-rc1")]

[InlineData("1 - 2", "3.0.0-pre", true)]
[InlineData("1 - 2", "2.0.0-pre")]
[InlineData("1 - 2", "1.0.0-pre")]
[InlineData("1.0 - 2", "1.0.0-pre")]

[InlineData("1.1.x", "1.0.0-a")]
[InlineData("1.1.x", "1.1.0-a")]
[InlineData("1.1.x", "1.2.0-a")]
[InlineData("1.1.x", "1.2.0-a", true)]
[InlineData("1.1.x", "1.0.0-a", true)]
[InlineData("1.x", "1.0.0-a")]
[InlineData("1.x", "1.1.0-a")]
[InlineData("1.x", "1.2.0-a")]
[InlineData("1.x", "0.0.0-a", true)]
[InlineData("1.x", "2.0.0-a", true)]

[InlineData(">=1.0.0 <1.1.0", "1.1.0")]
[InlineData(">=1.0.0 <1.1.0", "1.1.0", true)]
[InlineData(">=1.0.0 <1.1.0", "1.1.0-pre")]
[InlineData(">=1.0.0 <1.1.0-pre", "1.1.0-pre")]
public void TestNegative(string range, string version, bool includePrerelease = false)
{
Assert.False(new Range(range).IsSatisfied(new Version(version), includePrerelease));
}
}
}
2 changes: 1 addition & 1 deletion test/SemanticVersioning.Tests/PreReleaseRanges.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public void ExcludedPreRelease(string rangeString, string versionString)
[InlineData("1.2 - 1.3", "1.3.0-alpha.1")]
[InlineData("1.2.0 - 1.3.0", "1.2.0-alpha.1")]
[InlineData("1.2.0 - 1.3.0", "1.3.0-alpha.1")]
[InlineData("^0.2.3", "0.2.3-alpha")]
[InlineData("^0.2.3", "0.2.4-alpha")]
public void MatchingPreReleaseWithIncludePrereleases(string rangeString, string versionString)
{
Expand All @@ -67,6 +66,7 @@ public void MatchingPreReleaseWithIncludePrereleases(string rangeString, string
[InlineData("<1.3", "1.3.0-alpha.1")]
[InlineData("~1.2.3", "1.3.0-alpha.1")]
[InlineData("^0.2.3", "0.2.2-alpha")]
[InlineData("^0.2.3", "0.2.3-alpha")]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change is correct, and matches the reasoning in npm/node-semver#409, but node-semver (version 7.5.0) actually treats this as satisfied. It looks like this is possibly a bug in node-semver though as this behaviour is inconsistent compared to versions with a major version number:

> semver.satisfies('0.2.3-alpha', '^0.2.3', {includePrerelease: true})
true
> semver.satisfies('1.2.3-alpha', '^1.2.3', {includePrerelease: true})
false

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've raised npm/node-semver#557 for this, will hold off merging this for now and see if I get a response.

[InlineData("^0.2.3", "0.3.0-alpha")]
public void ExcludedPreReleaseWithIncludePrereleases(string rangeString, string versionString)
{
Expand Down