2026-05-11 22:53:24 +02:00
|
|
|
// Copyright (c) The Geekeey Authors
|
|
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
2026-05-16 23:04:09 +02:00
|
|
|
using System.Text;
|
|
|
|
|
|
2026-05-11 22:53:24 +02:00
|
|
|
namespace Geekeey.SemVer.Tests;
|
|
|
|
|
|
|
|
|
|
internal sealed class SemanticVersionRangeTests
|
|
|
|
|
{
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("1.2.3", "1.2.3", true)]
|
|
|
|
|
[Arguments("1.2.3", "1.2.4", false)]
|
|
|
|
|
[Arguments(">1.2.3", "1.2.4", true)]
|
|
|
|
|
[Arguments(">1.2.3", "1.2.3", false)]
|
|
|
|
|
[Arguments(">=1.2.3", "1.2.3", true)]
|
|
|
|
|
[Arguments("<1.2.3", "1.2.2", true)]
|
|
|
|
|
[Arguments("<=1.2.3", "1.2.3", true)]
|
|
|
|
|
public async Task I_can_satisfy_npm_basic_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("1.2.3 - 2.3.4", "1.2.3", true)]
|
|
|
|
|
[Arguments("1.2.3 - 2.3.4", "2.3.4", true)]
|
|
|
|
|
[Arguments("1.2.3 - 2.3.4", "1.2.2", false)]
|
|
|
|
|
[Arguments("1.2.3 - 2.3.4", "2.3.5", false)]
|
|
|
|
|
public async Task I_can_satisfy_npm_hyphen_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("^1.2.3", "1.2.3", true)]
|
|
|
|
|
[Arguments("^1.2.3", "1.9.9", true)]
|
|
|
|
|
[Arguments("^1.2.3", "2.0.0", false)]
|
|
|
|
|
[Arguments("^0.2.3", "0.2.3", true)]
|
|
|
|
|
[Arguments("^0.2.3", "0.2.4", true)]
|
|
|
|
|
[Arguments("^0.2.3", "0.3.0", false)]
|
|
|
|
|
[Arguments("^0.0.3", "0.0.3", true)]
|
|
|
|
|
[Arguments("^0.0.3", "0.0.4", false)]
|
|
|
|
|
public async Task I_can_satisfy_npm_caret_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("~1.2.3", "1.2.3", true)]
|
|
|
|
|
[Arguments("~1.2.3", "1.2.9", true)]
|
|
|
|
|
[Arguments("~1.2.3", "1.3.0", false)]
|
|
|
|
|
[Arguments("~1.2", "1.2.0", true)]
|
|
|
|
|
[Arguments("~1.2", "1.2.9", true)]
|
|
|
|
|
[Arguments("~1.2", "1.3.0", false)]
|
|
|
|
|
[Arguments("~1", "1.0.0", true)]
|
|
|
|
|
[Arguments("~1", "1.9.9", true)]
|
|
|
|
|
[Arguments("~1", "2.0.0", false)]
|
|
|
|
|
public async Task I_can_satisfy_npm_tilde_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("1.2.x", "1.2.0", true)]
|
|
|
|
|
[Arguments("1.2.x", "1.2.9", true)]
|
|
|
|
|
[Arguments("1.2.x", "1.3.0", false)]
|
|
|
|
|
[Arguments("1.x", "1.0.0", true)]
|
|
|
|
|
[Arguments("1.x", "1.9.9", true)]
|
|
|
|
|
[Arguments("1.x", "2.0.0", false)]
|
|
|
|
|
[Arguments("*", "0.0.0", true)]
|
|
|
|
|
[Arguments("*", "9.9.9", true)]
|
|
|
|
|
public async Task I_can_satisfy_npm_wildcard_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments(">1.2.3 || <1.0.0", "1.2.4", true)]
|
|
|
|
|
[Arguments(">1.2.3 || <1.0.0", "0.9.9", true)]
|
|
|
|
|
[Arguments(">1.2.3 || <1.0.0", "1.1.0", false)]
|
|
|
|
|
[Arguments(">1.0.0 <=3.2.6 || >=1.0.0 <6.0.0", "2.0.0", true)]
|
|
|
|
|
[Arguments(">1.0.0 <=3.2.6 || >=1.0.0 <6.0.0", "5.0.0", true)]
|
|
|
|
|
[Arguments(">1.0.0 <=3.2.6 || >=1.0.0 <6.0.0", "7.0.0", false)]
|
|
|
|
|
public async Task I_can_satisfy_npm_or_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("^6.2.3-alpha.1", "6.2.3-alpha.1", true)]
|
|
|
|
|
[Arguments("^6.2.3-alpha.1", "6.2.3-beta", true)]
|
|
|
|
|
[Arguments("^6.2.3-alpha.1", "6.2.2", false)]
|
|
|
|
|
[Arguments("^6.2.3-alpha.1", "7.0.0", false)]
|
|
|
|
|
public async Task I_can_satisfy_complex_npm_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("[1.2.3]", "1.2.3", true)]
|
|
|
|
|
[Arguments("[1.2.3]", "1.2.4", false)]
|
|
|
|
|
[Arguments("[1.2.3, 1.4.0)", "1.2.3", true)]
|
|
|
|
|
[Arguments("[1.2.3, 1.4.0)", "1.3.9", true)]
|
|
|
|
|
[Arguments("[1.2.3, 1.4.0)", "1.4.0", false)]
|
|
|
|
|
[Arguments("(1.2.3, 1.4.0]", "1.2.3", false)]
|
|
|
|
|
[Arguments("(1.2.3, 1.4.0]", "1.4.0", true)]
|
|
|
|
|
[Arguments("[1.2.3,)", "1.2.3", true)]
|
|
|
|
|
[Arguments("[1.2.3,)", "9.9.9", true)]
|
|
|
|
|
[Arguments("(,1.4.0]", "1.4.0", true)]
|
|
|
|
|
[Arguments("(,1.4.0]", "0.0.0", true)]
|
|
|
|
|
public async Task I_can_satisfy_maven_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("[1.2,1.3],[1.5,)", "1.2.0", true)]
|
|
|
|
|
[Arguments("[1.2,1.3],[1.5,)", "1.4.0", false)]
|
|
|
|
|
[Arguments("[1.2,1.3],[1.5,)", "1.5.0", true)]
|
|
|
|
|
public async Task I_can_satisfy_maven_or_ranges(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("^1.2.3", "1.2.3-alpha", false)]
|
|
|
|
|
[Arguments("^1.2.3-alpha", "1.2.3-beta", true)]
|
|
|
|
|
[Arguments("^1.2.3-alpha", "1.2.4", true)]
|
|
|
|
|
[Arguments("^1.2.3-alpha", "1.3.0-alpha", false)]
|
|
|
|
|
public async Task I_can_satisfy_prerelease_rules(string range, string version, bool expected)
|
|
|
|
|
{
|
|
|
|
|
var r = SemanticVersionRange.Parse(range);
|
|
|
|
|
var v = SemanticVersion.Parse(version);
|
|
|
|
|
await Assert.That(r.Satisfies(v)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public async Task I_can_serialize_to_json()
|
|
|
|
|
{
|
2026-05-16 23:04:09 +02:00
|
|
|
var r = SemanticVersionRange.Parse("[1.2.3,2.0.0)");
|
2026-05-11 22:53:24 +02:00
|
|
|
var json = System.Text.Json.JsonSerializer.Serialize(r);
|
|
|
|
|
await Assert.That(json).IsEqualTo("\"^1.2.3\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public async Task I_can_deserialize_from_json()
|
|
|
|
|
{
|
|
|
|
|
var json = "\"^1.2.3\"";
|
|
|
|
|
var r = System.Text.Json.JsonSerializer.Deserialize<SemanticVersionRange>(json);
|
|
|
|
|
await Assert.That(r.ToString()).IsEqualTo("^1.2.3");
|
|
|
|
|
await Assert.That(r.Satisfies(new SemanticVersion(1, 2, 4))).IsTrue();
|
|
|
|
|
}
|
2026-05-16 23:04:09 +02:00
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public async Task I_use_npm_short_format_by_default()
|
|
|
|
|
{
|
|
|
|
|
var value = SemanticVersionRange.Parse("[1.2.3,2.0.0)");
|
|
|
|
|
await Assert.That(value.ToString()).IsEqualTo("^1.2.3");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
[Arguments("^1.2.3", "m", "[1.2.3,2.0.0)")]
|
|
|
|
|
[Arguments("~1.2.3", "m", "[1.2.3,1.3.0)")]
|
|
|
|
|
[Arguments("1.2.3", "m", "[1.2.3]")]
|
|
|
|
|
[Arguments("[1.2.3,2.0.0)", "n", ">=1.2.3 <2.0.0")]
|
|
|
|
|
[Arguments("[1.2.3,2.0.0)", "ns", "^1.2.3")]
|
|
|
|
|
[Arguments("[1.2.3,1.3.0)", "ns", "~1.2.3")]
|
|
|
|
|
[Arguments("[1.2,1.3],[1.5,)", "n", ">=1.2.0 <=1.3.0 || >=1.5.0")]
|
|
|
|
|
[Arguments("*", "m", "(,)")]
|
|
|
|
|
public async Task I_can_convert_range_formats(string range, string format, string expected)
|
|
|
|
|
{
|
|
|
|
|
var value = SemanticVersionRange.Parse(range);
|
|
|
|
|
await Assert.That(value.ToString(format, null)).IsEqualTo(expected);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public async Task I_can_format_ranges_to_chars()
|
|
|
|
|
{
|
|
|
|
|
var value = SemanticVersionRange.Parse("[1.2.3,2.0.0)");
|
|
|
|
|
var destination = new char[32];
|
|
|
|
|
var success = value.TryFormat(destination, out var charsWritten, "ns", null);
|
|
|
|
|
|
|
|
|
|
await Assert.That(success).IsTrue();
|
|
|
|
|
await Assert.That(new string(destination[..charsWritten])).IsEqualTo("^1.2.3");
|
|
|
|
|
}
|
2026-05-11 22:53:24 +02:00
|
|
|
}
|