mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Make SemanticVersion compatible with SemVer 2.0 (#5037)
Made 'SemanticVersion' compatible with SymVer 2.0 http://semver.org/ (p.10) - Fix comparisons - Refactor and add more tests
This commit is contained in:
+48
@@ -43,6 +43,14 @@ namespace System.Management.Automation.Runspaces
|
||||
"System.Version",
|
||||
ViewsOf_System_Version());
|
||||
|
||||
yield return new ExtendedTypeDefinition(
|
||||
"System.Version#IncludeLabel",
|
||||
ViewsOf_System_Version_With_Label());
|
||||
|
||||
yield return new ExtendedTypeDefinition(
|
||||
"System.Management.Automation.SemanticVersion",
|
||||
ViewsOf_Semantic_Version_With_Label());
|
||||
|
||||
yield return new ExtendedTypeDefinition(
|
||||
"System.Drawing.Printing.PrintDocument",
|
||||
ViewsOf_System_Drawing_Printing_PrintDocument());
|
||||
@@ -478,6 +486,46 @@ namespace System.Management.Automation.Runspaces
|
||||
.EndTable());
|
||||
}
|
||||
|
||||
private static IEnumerable<FormatViewDefinition> ViewsOf_System_Version_With_Label()
|
||||
{
|
||||
yield return new FormatViewDefinition("System.Version",
|
||||
TableControl.Create()
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 8)
|
||||
.AddHeader(width: 26)
|
||||
.AddHeader(width: 27)
|
||||
.StartRowDefinition()
|
||||
.AddPropertyColumn("Major")
|
||||
.AddPropertyColumn("Minor")
|
||||
.AddPropertyColumn("Build")
|
||||
.AddPropertyColumn("Revision")
|
||||
.AddPropertyColumn("PSSemVerPreReleaseLabel")
|
||||
.AddPropertyColumn("PSSemVerBuildLabel")
|
||||
.EndRowDefinition()
|
||||
.EndTable());
|
||||
}
|
||||
|
||||
private static IEnumerable<FormatViewDefinition> ViewsOf_Semantic_Version_With_Label()
|
||||
{
|
||||
yield return new FormatViewDefinition("System.Management.Automation.SemanticVersion",
|
||||
TableControl.Create()
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 6)
|
||||
.AddHeader(width: 9)
|
||||
.AddHeader(width: 11)
|
||||
.StartRowDefinition()
|
||||
.AddPropertyColumn("Major")
|
||||
.AddPropertyColumn("Minor")
|
||||
.AddPropertyColumn("Patch")
|
||||
.AddPropertyColumn("PreReleaseLabel")
|
||||
.AddPropertyColumn("BuildLabel")
|
||||
.EndRowDefinition()
|
||||
.EndTable());
|
||||
}
|
||||
|
||||
private static IEnumerable<FormatViewDefinition> ViewsOf_System_Drawing_Printing_PrintDocument()
|
||||
{
|
||||
yield return new FormatViewDefinition("System.Drawing.Printing.PrintDocument",
|
||||
|
||||
@@ -7,6 +7,8 @@ using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation.Internal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace System.Management.Automation
|
||||
@@ -384,12 +386,18 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public sealed class SemanticVersion : IComparable, IComparable<SemanticVersion>, IEquatable<SemanticVersion>
|
||||
{
|
||||
private const string VersionSansRegEx = @"^(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?$";
|
||||
private const string LabelRegEx = @"^((?<preLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?(\+(?<buildLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?$";
|
||||
private const string LabelUnitRegEx = @"^[0-9A-Za-z][0-9A-Za-z\-\.]*$";
|
||||
private const string PreLabelPropertyName = "PSSemVerPreReleaseLabel";
|
||||
private const string BuildLabelPropertyName = "PSSemVerBuildLabel";
|
||||
private const string TypeNameForVersionWithLabel = "System.Version#IncludeLabel";
|
||||
private string versionString;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SemanticVersion from a string.
|
||||
/// </summary>
|
||||
/// <param name="version">The version to parse</param>
|
||||
/// <exception cref="PSArgumentException"></exception>
|
||||
/// <exception cref="ValidationMetadataException"></exception>
|
||||
/// <exception cref="FormatException"></exception>
|
||||
/// <exception cref="OverflowException"></exception>
|
||||
public SemanticVersion(string version)
|
||||
@@ -398,8 +406,39 @@ namespace System.Management.Automation
|
||||
|
||||
Major = v.Major;
|
||||
Minor = v.Minor;
|
||||
Patch = v.Patch;
|
||||
Label = v.Label;
|
||||
Patch = v.Patch < 0 ? 0 : v.Patch;
|
||||
PreReleaseLabel = v.PreReleaseLabel;
|
||||
BuildLabel = v.BuildLabel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SemanticVersion.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version</param>
|
||||
/// <param name="minor">The minor version</param>
|
||||
/// <param name="patch">The patch version</param>
|
||||
/// <param name="preReleaseLabel">The pre-release label for the version</param>
|
||||
/// <param name="buildLabel">The build metadata for the version</param>
|
||||
/// <exception cref="FormatException">
|
||||
/// If <paramref name="preReleaseLabel"/> don't match 'LabelUnitRegEx'.
|
||||
/// If <paramref name="buildLabel"/> don't match 'LabelUnitRegEx'.
|
||||
/// </exception>
|
||||
public SemanticVersion(int major, int minor, int patch, string preReleaseLabel, string buildLabel)
|
||||
: this(major, minor, patch)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(preReleaseLabel))
|
||||
{
|
||||
if (!Regex.IsMatch(preReleaseLabel, LabelUnitRegEx)) throw new FormatException(nameof(preReleaseLabel));
|
||||
|
||||
PreReleaseLabel = preReleaseLabel;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(buildLabel))
|
||||
{
|
||||
if (!Regex.IsMatch(buildLabel, LabelUnitRegEx)) throw new FormatException(nameof(buildLabel));
|
||||
|
||||
BuildLabel = buildLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -410,17 +449,23 @@ namespace System.Management.Automation
|
||||
/// <param name="patch">The minor version</param>
|
||||
/// <param name="label">The label for the version</param>
|
||||
/// <exception cref="PSArgumentException">
|
||||
/// If <paramref name="major"/>, <paramref name="minor"/>, or <paramref name="patch"/> is less than 0.
|
||||
/// </exception>
|
||||
/// <exception cref="PSArgumentNullException">
|
||||
/// If <paramref name="label"/> is null or an empty string.
|
||||
/// <exception cref="FormatException">
|
||||
/// If <paramref name="label"/> don't match 'LabelRegEx'.
|
||||
/// </exception>
|
||||
public SemanticVersion(int major, int minor, int patch, string label)
|
||||
: this(major, minor, patch)
|
||||
{
|
||||
if (string.IsNullOrEmpty(label)) throw PSTraceSource.NewArgumentNullException(nameof(label));
|
||||
// We presume the SymVer :
|
||||
// 1) major.minor.patch-label
|
||||
// 2) 'label' starts with letter or digit.
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
var match = Regex.Match(label, LabelRegEx);
|
||||
if (!match.Success) throw new FormatException(nameof(label));
|
||||
|
||||
Label = label;
|
||||
PreReleaseLabel = match.Groups["preLabel"].Value;
|
||||
BuildLabel = match.Groups["buildLabel"].Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -441,7 +486,9 @@ namespace System.Management.Automation
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
Patch = patch;
|
||||
Label = null;
|
||||
// We presume:
|
||||
// PreReleaseLabel = null;
|
||||
// BuildLabel = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -463,43 +510,66 @@ namespace System.Management.Automation
|
||||
/// </exception>
|
||||
public SemanticVersion(int major) : this(major, 0, 0) {}
|
||||
|
||||
private const string LabelPropertyName = "PSSemanticVersionLabel";
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="SemanticVersion"/> from a <see cref="Version"/>,
|
||||
/// copying the NoteProperty storing the label if the expected property exists.
|
||||
/// </summary>
|
||||
/// <param name="version">The version.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// If <paramref name="version"/> is null.
|
||||
/// </exception>
|
||||
/// <exception cref="PSArgumentException">
|
||||
/// If <paramref name="version.Revision"/> is more than 0.
|
||||
/// </exception>
|
||||
public SemanticVersion(Version version)
|
||||
{
|
||||
if (version == null) throw PSTraceSource.NewArgumentNullException(nameof(version));
|
||||
if (version.Revision > 0) throw PSTraceSource.NewArgumentException(nameof(version));
|
||||
|
||||
Major = version.Major;
|
||||
Minor = version.Minor;
|
||||
Patch = version.Build == -1 ? 0 : version.Build;
|
||||
var psobj = new PSObject(version);
|
||||
var labelNote = psobj.Properties[LabelPropertyName];
|
||||
if (labelNote != null)
|
||||
var preLabelNote = psobj.Properties[PreLabelPropertyName];
|
||||
if (preLabelNote != null)
|
||||
{
|
||||
Label = labelNote.Value as string;
|
||||
PreReleaseLabel = preLabelNote.Value as string;
|
||||
}
|
||||
var buildLabelNote = psobj.Properties[BuildLabelPropertyName];
|
||||
if (buildLabelNote != null)
|
||||
{
|
||||
BuildLabel = buildLabelNote.Value as string;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a <see cref="SemanticVersion"/> to a <see cref="Version"/>.
|
||||
/// If there is a <see cref="Label"/>, it is added as a NoteProperty to the
|
||||
/// result so that you can round trip back to a <see cref="SemanticVersion"/>
|
||||
/// without losing the label.
|
||||
/// If there is a <see cref="PreReleaseLabel"/> or/and a <see cref="BuildLabel"/>,
|
||||
/// it is added as a NoteProperty to the result so that you can round trip
|
||||
/// back to a <see cref="SemanticVersion"/> without losing the label.
|
||||
/// </summary>
|
||||
/// <param name="semver"></param>
|
||||
public static implicit operator Version(SemanticVersion semver)
|
||||
{
|
||||
PSObject psobj;
|
||||
|
||||
var result = new Version(semver.Major, semver.Minor, semver.Patch);
|
||||
|
||||
if (!string.IsNullOrEmpty(semver.Label))
|
||||
if (!string.IsNullOrEmpty(semver.PreReleaseLabel) || !string.IsNullOrEmpty(semver.BuildLabel))
|
||||
{
|
||||
var psobj = new PSObject(result);
|
||||
psobj.Properties.Add(new PSNoteProperty(LabelPropertyName, semver.Label));
|
||||
psobj = new PSObject(result);
|
||||
|
||||
if (!string.IsNullOrEmpty(semver.PreReleaseLabel))
|
||||
{
|
||||
psobj.Properties.Add(new PSNoteProperty(PreLabelPropertyName, semver.PreReleaseLabel));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(semver.BuildLabel))
|
||||
{
|
||||
psobj.Properties.Add(new PSNoteProperty(BuildLabelPropertyName, semver.BuildLabel));
|
||||
}
|
||||
|
||||
psobj.TypeNames.Insert(0, TypeNameForVersionWithLabel);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -521,9 +591,14 @@ namespace System.Management.Automation
|
||||
public int Patch { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The last component in a SemanticVersion - may be null if not specified.
|
||||
/// PreReleaseLabel position in the SymVer string 'major.minor.patch-PreReleaseLabel+BuildLabel'.
|
||||
/// </summary>
|
||||
public string Label { get; }
|
||||
public string PreReleaseLabel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// BuildLabel position in the SymVer string 'major.minor.patch-PreReleaseLabel+BuildLabel'.
|
||||
/// </summary>
|
||||
public string BuildLabel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parse <paramref name="version"/> and return the result if it is a valid <see cref="SemanticVersion"/>, otherwise throws an exception.
|
||||
@@ -531,12 +606,12 @@ namespace System.Management.Automation
|
||||
/// <param name="version">The string to parse</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="PSArgumentException"></exception>
|
||||
/// <exception cref="ValidationMetadataException"></exception>
|
||||
/// <exception cref="FormatException"></exception>
|
||||
/// <exception cref="OverflowException"></exception>
|
||||
public static SemanticVersion Parse(string version)
|
||||
{
|
||||
if (version == null) throw PSTraceSource.NewArgumentNullException(nameof(version));
|
||||
if (version == String.Empty) throw new FormatException(nameof(version));
|
||||
|
||||
var r = new VersionResult();
|
||||
r.Init(true);
|
||||
@@ -571,77 +646,151 @@ namespace System.Management.Automation
|
||||
|
||||
private static bool TryParseVersion(string version, ref VersionResult result)
|
||||
{
|
||||
if (version.EndsWith('-') || version.EndsWith('+') || version.EndsWith('.'))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
string versionSansLabel = null;
|
||||
var major=0;
|
||||
var minor=0;
|
||||
var patch=0;
|
||||
string preLabel = null;
|
||||
string buildLabel = null;
|
||||
|
||||
// We parse the SymVer 'version' string 'major.minor.patch-PreReleaseLabel+BuildLabel'.
|
||||
var dashIndex = version.IndexOf('-');
|
||||
var plusIndex = version.IndexOf('+');
|
||||
|
||||
// Empty label?
|
||||
if (dashIndex == version.Length - 1)
|
||||
if (dashIndex > plusIndex)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentException);
|
||||
// 'PreReleaseLabel' can contains dashes.
|
||||
if (plusIndex == -1)
|
||||
{
|
||||
// No buildLabel: buildLabel == null
|
||||
// Format is 'major.minor.patch-PreReleaseLabel'
|
||||
preLabel = version.Substring(dashIndex+1);
|
||||
versionSansLabel = version.Substring(0, dashIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No PreReleaseLabel: preLabel == null
|
||||
// Format is 'major.minor.patch+BuildLabel'
|
||||
buildLabel = version.Substring(plusIndex+1);
|
||||
versionSansLabel = version.Substring(0, plusIndex);
|
||||
dashIndex = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dashIndex == -1)
|
||||
{
|
||||
// Here dashIndex == plusIndex == -1
|
||||
// No preLabel - preLabel == null;
|
||||
// No buildLabel - buildLabel == null;
|
||||
// Format is 'major.minor.patch'
|
||||
versionSansLabel = version;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Format is 'major.minor.patch-PreReleaseLabel+BuildLabel'
|
||||
preLabel = version.Substring(dashIndex+1, plusIndex-dashIndex-1);
|
||||
buildLabel = version.Substring(plusIndex+1);
|
||||
versionSansLabel = version.Substring(0, dashIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if ((dashIndex != - 1 && String.IsNullOrEmpty(preLabel)) ||
|
||||
(plusIndex != - 1 && String.IsNullOrEmpty(buildLabel)) ||
|
||||
String.IsNullOrEmpty(versionSansLabel))
|
||||
{
|
||||
// We have dash and no preReleaseLabel or
|
||||
// we have plus and no buildLabel or
|
||||
// we have no main version part (versionSansLabel==null)
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
var versionSansLabel = (dashIndex < 0) ? version : version.Substring(0, dashIndex);
|
||||
string[] parsedComponents = versionSansLabel.Split(Utils.Separators.Dot);
|
||||
if (parsedComponents.Length > 3)
|
||||
var match = Regex.Match(versionSansLabel, VersionSansRegEx);
|
||||
if (!match.Success)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentException);
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0, patch = 0;
|
||||
if (!TryParseComponent(parsedComponents[0], "major", ref result, out major))
|
||||
if (!int.TryParse(match.Groups["major"].Value, out major))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedComponents.Length >= 2 && !TryParseComponent(parsedComponents[1], "minor", ref result, out minor))
|
||||
if (match.Groups["minor"].Success && !int.TryParse(match.Groups["minor"].Value, out minor))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedComponents.Length == 3 && !TryParseComponent(parsedComponents[2], "patch", ref result, out patch))
|
||||
if (match.Groups["patch"].Success && !int.TryParse(match.Groups["patch"].Value, out patch))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
result._parsedVersion = dashIndex < 0
|
||||
? new SemanticVersion(major, minor, patch)
|
||||
: new SemanticVersion(major, minor, patch, version.Substring(dashIndex + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryParseComponent(string component, string componentName, ref VersionResult result, out int parsedComponent)
|
||||
{
|
||||
if (!Int32.TryParse(component, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsedComponent))
|
||||
if (preLabel != null && !Regex.IsMatch(preLabel, LabelUnitRegEx) ||
|
||||
(buildLabel != null && !Regex.IsMatch(buildLabel, LabelUnitRegEx)))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException, component);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedComponent < 0)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentOutOfRangeException, componentName);
|
||||
result.SetFailure(ParseFailureKind.FormatException);
|
||||
return false;
|
||||
}
|
||||
|
||||
result._parsedVersion = new SemanticVersion(major, minor, patch, preLabel, buildLabel);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToString
|
||||
/// Implement ToString()
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
if (Patch < 0)
|
||||
if (versionString == null)
|
||||
{
|
||||
return string.IsNullOrEmpty(Label)
|
||||
? StringUtil.Format("{0}.{1}", Major, Minor)
|
||||
: StringUtil.Format("{0}.{1}-{2}", Major, Minor, Label);
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.Append(Major).Append(Utils.Separators.Dot).Append(Minor).Append(Utils.Separators.Dot).Append(Patch);
|
||||
|
||||
if (!string.IsNullOrEmpty(PreReleaseLabel))
|
||||
{
|
||||
result.Append("-").Append(PreReleaseLabel);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(BuildLabel))
|
||||
{
|
||||
result.Append("+").Append(BuildLabel);
|
||||
}
|
||||
|
||||
versionString = result.ToString();
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(Label)
|
||||
? StringUtil.Format("{0}.{1}.{2}", Major, Minor, Patch)
|
||||
: StringUtil.Format("{0}.{1}.{2}-{3}", Major, Minor, Patch, Label);
|
||||
return versionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement Compare.
|
||||
/// </summary>
|
||||
public static int Compare(SemanticVersion versionA, SemanticVersion versionB)
|
||||
{
|
||||
if (versionA != null)
|
||||
{
|
||||
return versionA.CompareTo(versionB);
|
||||
}
|
||||
|
||||
if (versionB != null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -664,7 +813,8 @@ namespace System.Management.Automation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement <see cref="IComparable{T}.CompareTo"/>
|
||||
/// Implement <see cref="IComparable{T}.CompareTo"/>.
|
||||
/// Meets SymVer 2.0 p.11 http://semver.org/
|
||||
/// </summary>
|
||||
public int CompareTo(SemanticVersion value)
|
||||
{
|
||||
@@ -680,16 +830,8 @@ namespace System.Management.Automation
|
||||
if (Patch != value.Patch)
|
||||
return Patch > value.Patch ? 1 : -1;
|
||||
|
||||
if (Label == null)
|
||||
return value.Label == null ? 0 : 1;
|
||||
|
||||
if (value.Label == null)
|
||||
return -1;
|
||||
|
||||
if (!string.Equals(Label, value.Label, StringComparison.Ordinal))
|
||||
return string.Compare(Label, value.Label, StringComparison.Ordinal);
|
||||
|
||||
return 0;
|
||||
// SymVer 2.0 standard requires to ignore 'BuildLabel' (Build metadata).
|
||||
return ComparePreLabel(this.PreReleaseLabel, value.PreReleaseLabel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -705,9 +847,10 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public bool Equals(SemanticVersion other)
|
||||
{
|
||||
// SymVer 2.0 standard requires to ignore 'BuildLabel' (Build metadata).
|
||||
return other != null &&
|
||||
(Major == other.Major) && (Minor == other.Minor) && (Patch == other.Patch) &&
|
||||
string.Equals(Label, other.Label, StringComparison.Ordinal);
|
||||
string.Equals(PreReleaseLabel, other.PreReleaseLabel, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -715,11 +858,7 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Utils.CombineHashCodes(
|
||||
Major.GetHashCode(),
|
||||
Minor.GetHashCode(),
|
||||
Patch.GetHashCode(),
|
||||
Label == null ? 0 : Label.GetHashCode());
|
||||
return this.ToString().GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -748,8 +887,7 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public static bool operator <(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
if ((object)v1 == null) throw PSTraceSource.NewArgumentException(nameof(v1));
|
||||
return (v1.CompareTo(v2) < 0);
|
||||
return (Compare(v1, v2) < 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -757,8 +895,7 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
if ((object)v1 == null) throw PSTraceSource.NewArgumentException(nameof(v1));
|
||||
return (v1.CompareTo(v2) <= 0);
|
||||
return (Compare(v1, v2) <= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -766,7 +903,7 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public static bool operator >(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
return (v2 < v1);
|
||||
return (Compare(v1, v2) > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -774,7 +911,51 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
return (v2 <= v1);
|
||||
return (Compare(v1, v2) >= 0);
|
||||
}
|
||||
|
||||
private static int ComparePreLabel(string preLabel1, string preLabel2)
|
||||
{
|
||||
// Symver 2.0 standard p.9
|
||||
// Pre-release versions have a lower precedence than the associated normal version.
|
||||
// Comparing each dot separated identifier from left to right
|
||||
// until a difference is found as follows:
|
||||
// identifiers consisting of only digits are compared numerically
|
||||
// and identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||
// Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
// A larger set of pre-release fields has a higher precedence than a smaller set,
|
||||
// if all of the preceding identifiers are equal.
|
||||
if (String.IsNullOrEmpty(preLabel1)) { return String.IsNullOrEmpty(preLabel2) ? 0 : 1; }
|
||||
if (String.IsNullOrEmpty(preLabel2)) { return -1; }
|
||||
|
||||
var units1 = preLabel1.Split('.');
|
||||
var units2 = preLabel2.Split('.');
|
||||
|
||||
var minLength = units1.Length < units2.Length ? units1.Length : units2.Length;
|
||||
|
||||
for (int i = 0; i < minLength; i++)
|
||||
{
|
||||
var ac = units1[i];
|
||||
var bc = units2[i];
|
||||
int number1, number2;
|
||||
var isNumber1 = Int32.TryParse(ac, out number1);
|
||||
var isNumber2 = Int32.TryParse(bc, out number2);
|
||||
|
||||
if (isNumber1 && isNumber2)
|
||||
{
|
||||
if (number1 != number2) { return number1 < number2 ? -1 : 1; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isNumber1) { return -1; }
|
||||
if (isNumber2) { return 1; }
|
||||
|
||||
int result = String.CompareOrdinal(ac, bc);
|
||||
if (result != 0) { return result; }
|
||||
}
|
||||
}
|
||||
|
||||
return units1.Length.CompareTo(units2.Length);
|
||||
}
|
||||
|
||||
internal enum ParseFailureKind
|
||||
|
||||
@@ -1982,6 +1982,22 @@ namespace System.Management.Automation.Runspaces
|
||||
var td251 = new TypeData(@"Deserialized.System.Management.Automation.DebuggerCommandResults", true);
|
||||
td251.TargetTypeForDeserialization = typeof(Microsoft.PowerShell.DeserializingTypeConverter);
|
||||
yield return td251;
|
||||
|
||||
var td252 = new TypeData(@"System.Version#IncludeLabel", true);
|
||||
td252.Members.Add("ToString",
|
||||
new ScriptMethodData(@"ToString", GetScriptBlock(@"
|
||||
$suffix = """"
|
||||
if (![String]::IsNullOrEmpty($this.PSSemVerPreReleaseLabel))
|
||||
{
|
||||
$suffix = ""-""+$this.PSSemVerPreReleaseLabel
|
||||
}
|
||||
if (![String]::IsNullOrEmpty($this.PSSemVerBuildLabel))
|
||||
{
|
||||
$suffix += ""+""+$this.PSSemVerBuildLabel
|
||||
}
|
||||
""$($this.Major).$($this.Minor).$($this.Build)""+$suffix
|
||||
")));
|
||||
yield return td252;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,46 +2,56 @@ using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
|
||||
Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
Context "constructing valid versions" {
|
||||
It "string argument constructor" {
|
||||
$v = [SemanticVersion]::new("1.2.3-alpha")
|
||||
Context "Constructing valid versions" {
|
||||
It "String argument constructor" {
|
||||
$v = [SemanticVersion]::new("1.2.3-Alpha-super.3+BLD.a1-xxx.03")
|
||||
$v.Major | Should Be 1
|
||||
$v.Minor | Should Be 2
|
||||
$v.Patch | Should Be 3
|
||||
$v.Label | Should Be "alpha"
|
||||
$v.ToString() | Should Be "1.2.3-alpha"
|
||||
$v.PreReleaseLabel | Should Be "Alpha-super.3"
|
||||
$v.BuildLabel | Should Be "BLD.a1-xxx.03"
|
||||
$v.ToString() | Should Be "1.2.3-Alpha-super.3+BLD.a1-xxx.03"
|
||||
|
||||
$v = [SemanticVersion]::new("1.0.0")
|
||||
$v.Major | Should Be 1
|
||||
$v.Minor | Should Be 0
|
||||
$v.Patch | Should Be 0
|
||||
$v.Label | Should BeNullOrEmpty
|
||||
$v.PreReleaseLabel | Should BeNullOrEmpty
|
||||
$v.BuildLabel | Should BeNullOrEmpty
|
||||
$v.ToString() | Should Be "1.0.0"
|
||||
|
||||
$v = [SemanticVersion]::new("3.0")
|
||||
$v.Major | Should Be 3
|
||||
$v.Minor | Should Be 0
|
||||
$v.Patch | Should Be 0
|
||||
$v.Label | Should BeNullOrEmpty
|
||||
$v.PreReleaseLabel | Should BeNullOrEmpty
|
||||
$v.BuildLabel | Should BeNullOrEmpty
|
||||
$v.ToString() | Should Be "3.0.0"
|
||||
|
||||
$v = [SemanticVersion]::new("2")
|
||||
$v.Major | Should Be 2
|
||||
$v.Minor | Should Be 0
|
||||
$v.Patch | Should Be 0
|
||||
$v.Label | Should BeNullOrEmpty
|
||||
$v.PreReleaseLabel | Should BeNullOrEmpty
|
||||
$v.BuildLabel | Should BeNullOrEmpty
|
||||
$v.ToString() | Should Be "2.0.0"
|
||||
}
|
||||
|
||||
# After the above test, we trust the properties and rely on ToString for validation
|
||||
# After the above test, we trust the properties and rely on ToString for validation
|
||||
|
||||
It "int args constructor" {
|
||||
It "Int args constructor" {
|
||||
$v = [SemanticVersion]::new(1, 0, 0)
|
||||
$v.ToString() | Should Be "1.0.0"
|
||||
|
||||
$v = [SemanticVersion]::new(3, 2, 0, "beta.1")
|
||||
$v.ToString() | Should Be "3.2.0-beta.1"
|
||||
|
||||
$v = [SemanticVersion]::new(3, 2, 0, "beta.1+meta")
|
||||
$v.ToString() | Should Be "3.2.0-beta.1+meta"
|
||||
|
||||
$v = [SemanticVersion]::new(3, 2, 0, "beta.1", "meta")
|
||||
$v.ToString() | Should Be "3.2.0-beta.1+meta"
|
||||
|
||||
$v = [SemanticVersion]::new(3, 1)
|
||||
$v.ToString() | Should Be "3.1.0"
|
||||
|
||||
@@ -49,7 +59,7 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
$v.ToString() | Should Be "3.0.0"
|
||||
}
|
||||
|
||||
It "version arg constructor" {
|
||||
It "Version arg constructor" {
|
||||
$v = [SemanticVersion]::new([Version]::new(1, 2))
|
||||
$v.ToString() | Should Be '1.2.0'
|
||||
|
||||
@@ -57,37 +67,63 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
$v.ToString() | Should Be '1.2.3'
|
||||
}
|
||||
|
||||
It "semantic version can round trip through version" {
|
||||
$v1 = [SemanticVersion]::new(3, 2, 1, "prerelease")
|
||||
It "Can covert to 'Version' type" {
|
||||
$v1 = [SemanticVersion]::new(3, 2, 1, "prerelease", "meta")
|
||||
$v2 = [Version]$v1
|
||||
$v2.GetType() | Should Be "Version"
|
||||
$v2.PSobject.TypeNames[0] | Should Be "System.Version#IncludeLabel"
|
||||
$v2.Major | Should Be 3
|
||||
$v2.Minor | Should Be 2
|
||||
$v2.Build | Should Be 1
|
||||
$v2.PSSemVerPreReleaseLabel | Should Be "prerelease"
|
||||
$v2.PSSemVerBuildLabel | Should Be "meta"
|
||||
$v2.ToString() | Should Be "3.2.1-prerelease+meta"
|
||||
}
|
||||
|
||||
It "Semantic version can round trip through version" {
|
||||
$v1 = [SemanticVersion]::new(3, 2, 1, "prerelease", "meta")
|
||||
$v2 = [SemanticVersion]::new([Version]$v1)
|
||||
$v2.ToString() | Should Be "3.2.1-prerelease"
|
||||
$v2.ToString() | Should Be "3.2.1-prerelease+meta"
|
||||
}
|
||||
}
|
||||
|
||||
Context "Comparisons" {
|
||||
$v1_0_0 = [SemanticVersion]::new(1, 0, 0)
|
||||
$v1_1_0 = [SemanticVersion]::new(1, 1, 0)
|
||||
$v1_1_1 = [SemanticVersion]::new(1, 1, 1)
|
||||
$v2_1_0 = [SemanticVersion]::new(2, 1, 0)
|
||||
$v1_0_0_alpha = [SemanticVersion]::new(1, 0, 0, "alpha")
|
||||
$v1_0_0_beta = [SemanticVersion]::new(1, 0, 0, "beta")
|
||||
BeforeAll {
|
||||
$v1_0_0 = [SemanticVersion]::new(1, 0, 0)
|
||||
$v1_1_0 = [SemanticVersion]::new(1, 1, 0)
|
||||
$v1_1_1 = [SemanticVersion]::new(1, 1, 1)
|
||||
$v2_1_0 = [SemanticVersion]::new(2, 1, 0)
|
||||
$v1_0_0_alpha = [SemanticVersion]::new(1, 0, 0, "alpha.1.1")
|
||||
$v1_0_0_alpha2 = [SemanticVersion]::new(1, 0, 0, "alpha.1.2")
|
||||
$v1_0_0_beta = [SemanticVersion]::new(1, 0, 0, "beta")
|
||||
$v1_0_0_betaBuild = [SemanticVersion]::new(1, 0, 0, "beta", "BUILD")
|
||||
|
||||
$testCases = @(
|
||||
@{ lhs = $v1_0_0; rhs = $v1_1_0 }
|
||||
@{ lhs = $v1_0_0; rhs = $v1_1_1 }
|
||||
@{ lhs = $v1_1_0; rhs = $v1_1_1 }
|
||||
@{ lhs = $v1_0_0; rhs = $v2_1_0 }
|
||||
@{ lhs = $v1_0_0_alpha; rhs = $v1_0_0_beta }
|
||||
@{ lhs = $v1_0_0_alpha; rhs = $v1_0_0_alpha2 }
|
||||
@{ lhs = $v1_0_0_alpha; rhs = $v1_0_0 }
|
||||
@{ lhs = $v1_0_0_beta; rhs = $v1_0_0 }
|
||||
@{ lhs = $v2_1_0; rhs = "3.0"}
|
||||
@{ lhs = "1.5"; rhs = $v2_1_0}
|
||||
)
|
||||
}
|
||||
|
||||
It "Build meta should be ignored" {
|
||||
$v1_0_0_beta -eq $v1_0_0_betaBuild | Should Be $true
|
||||
$v1_0_0_betaBuild -lt $v1_0_0_beta | Should Be $false
|
||||
$v1_0_0_beta -lt $v1_0_0_betaBuild | Should Be $false
|
||||
}
|
||||
|
||||
$testCases = @(
|
||||
@{ lhs = $v1_0_0; rhs = $v1_1_0 }
|
||||
@{ lhs = $v1_0_0; rhs = $v1_1_1 }
|
||||
@{ lhs = $v1_1_0; rhs = $v1_1_1 }
|
||||
@{ lhs = $v1_0_0; rhs = $v2_1_0 }
|
||||
@{ lhs = $v1_0_0_alpha; rhs = $v1_0_0_beta }
|
||||
@{ lhs = $v1_0_0_alpha; rhs = $v1_0_0 }
|
||||
@{ lhs = $v1_0_0_beta; rhs = $v1_0_0 }
|
||||
@{ lhs = $v2_1_0; rhs = "3.0"}
|
||||
@{ lhs = "1.5"; rhs = $v2_1_0}
|
||||
)
|
||||
It "<lhs> less than <rhs>" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -lt $rhs | Should Be $true
|
||||
$rhs -lt $lhs | Should Be $false
|
||||
}
|
||||
|
||||
It "<lhs> less than or equal <rhs>" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -le $rhs | Should Be $true
|
||||
@@ -95,11 +131,13 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
$lhs -le $lhs | Should Be $true
|
||||
$rhs -le $rhs | Should Be $true
|
||||
}
|
||||
|
||||
It "<lhs> greater than <rhs>" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -gt $rhs | Should Be $false
|
||||
$rhs -gt $lhs | Should Be $true
|
||||
}
|
||||
|
||||
It "<lhs> greater than or equal <rhs>" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -ge $rhs | Should Be $false
|
||||
@@ -108,11 +146,10 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
$rhs -ge $rhs | Should Be $true
|
||||
}
|
||||
|
||||
$testCases = @(
|
||||
It "Equality <operand>" -TestCases @(
|
||||
@{ operand = $v1_0_0 }
|
||||
@{ operand = $v1_0_0_alpha }
|
||||
)
|
||||
It "Equality <operand>" -TestCases $testCases {
|
||||
) {
|
||||
param($operand)
|
||||
$operand -eq $operand | Should Be $true
|
||||
$operand -ne $operand | Should Be $false
|
||||
@@ -134,84 +171,67 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
||||
}
|
||||
}
|
||||
|
||||
Context "error handling" {
|
||||
Context "Error handling" {
|
||||
|
||||
# The specific errors aren't too useful here, but noted in comments
|
||||
# so when we pick up a version of Pester that will let us check FullyQualifiedErrorId,
|
||||
# it's easier to tweak the tests
|
||||
|
||||
$testCases = @(
|
||||
@{ expectedResult = $false; version = $null }
|
||||
@{ expectedResult = $false; version = [NullString]::Value }
|
||||
@{ expectedResult = $false; version = "" }
|
||||
@{ expectedResult = $false; version = "1.0.0-" }
|
||||
@{ expectedResult = $false; version = "-" }
|
||||
@{ expectedResult = $false; version = "." }
|
||||
@{ expectedResult = $false; version = "-alpha" }
|
||||
@{ expectedResult = $false; version = "1..0" }
|
||||
@{ expectedResult = $false; version = "1.0.-alpha" }
|
||||
@{ expectedResult = $false; version = "1.0." }
|
||||
@{ expectedResult = $false; version = ".0.0" }
|
||||
)
|
||||
|
||||
It "parts of version missing" -TestCases $testCases {
|
||||
param($version, $expectedResult)
|
||||
{ [SemanticVersion]::new($version) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException
|
||||
$semVer = $null
|
||||
[SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult
|
||||
$semVer | Should Be $null
|
||||
}
|
||||
|
||||
$testCases = @(
|
||||
@{ expectedResult = $false; version = "-1.0.0" }
|
||||
@{ expectedResult = $false; version = "1.-1.0" }
|
||||
@{ expectedResult = $false; version = "1.0.-1" }
|
||||
)
|
||||
|
||||
It "range check of versions: <version>" -TestCases $testCases {
|
||||
param($version, $expectedResult)
|
||||
{ [SemanticVersion]::new($version) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException
|
||||
$semVer = $null
|
||||
[SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult
|
||||
$semVer | Should Be $null
|
||||
}
|
||||
|
||||
$testCases = @(
|
||||
@{ expectedResult = $false; version = "aa.0.0" }
|
||||
@{ expectedResult = $false; version = "1.bb.0" }
|
||||
@{ expectedResult = $false; version = "1.0.cc" }
|
||||
)
|
||||
|
||||
It "format errors: <version>" -TestCases $testCases {
|
||||
param($version, $expectedResult)
|
||||
{ [SemanticVersion]::new($version) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::Parse($version) } | Should Throw # PSArgumentException
|
||||
It "<name>: '<version>'" -TestCases @(
|
||||
@{ name = "Missing parts: 'null'"; errorId = "PSArgumentNullException";expectedResult = $false; version = $null }
|
||||
@{ name = "Missing parts: 'NullString'"; errorId = "PSArgumentNullException";expectedResult = $false; version = [NullString]::Value }
|
||||
@{ name = "Missing parts: 'EmptyString'";errorId = "FormatException"; expectedResult = $false; version = "" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "-" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "." }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "+" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "-alpha" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1..0" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.-alpha" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.+alpha" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0-alpha+" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0-+" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0+-" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0+" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0-" }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.0." }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0." }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = "1.0.." }
|
||||
@{ name = "Missing parts"; errorId = "FormatException"; expectedResult = $false; version = ".0.0" }
|
||||
@{ name = "Range check of versions"; errorId = "FormatException"; expectedResult = $false; version = "-1.0.0" }
|
||||
@{ name = "Range check of versions"; errorId = "FormatException"; expectedResult = $false; version = "1.-1.0" }
|
||||
@{ name = "Range check of versions"; errorId = "FormatException"; expectedResult = $false; version = "1.0.-1" }
|
||||
@{ name = "Format errors"; errorId = "FormatException"; expectedResult = $false; version = "aa.0.0" }
|
||||
@{ name = "Format errors"; errorId = "FormatException"; expectedResult = $false; version = "1.bb.0" }
|
||||
@{ name = "Format errors"; errorId = "FormatException"; expectedResult = $false; version = "1.0.cc" }
|
||||
) {
|
||||
param($version, $expectedResult, $errorId)
|
||||
{ [SemanticVersion]::new($version) } | ShouldBeErrorId $errorId
|
||||
if ($version -eq $null) {
|
||||
# PowerShell convert $null to Empty string
|
||||
{ [SemanticVersion]::Parse($version) } | ShouldBeErrorId "FormatException"
|
||||
} else {
|
||||
{ [SemanticVersion]::Parse($version) } | ShouldBeErrorId $errorId
|
||||
}
|
||||
$semVer = $null
|
||||
[SemanticVersion]::TryParse($_, [ref]$semVer) | Should Be $expectedResult
|
||||
$semVer | Should Be $null
|
||||
}
|
||||
|
||||
It "Negative version arguments" {
|
||||
{ [SemanticVersion]::new(-1, 0) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new(1, -1) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new(1, 1, -1) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new(-1, 0) } | ShouldBeErrorId "PSArgumentException"
|
||||
{ [SemanticVersion]::new(1, -1) } | ShouldBeErrorId "PSArgumentException"
|
||||
{ [SemanticVersion]::new(1, 1, -1) } | ShouldBeErrorId "PSArgumentException"
|
||||
}
|
||||
|
||||
It "Incompatible version throws" {
|
||||
It "Incompatible 'Version' throws" {
|
||||
# Revision isn't supported
|
||||
{ [SemanticVersion]::new([Version]::new(0, 0, 0, 4)) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new([Version]::new("1.2.3.4")) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new([Version]::new(0, 0, 0, 4)) } | ShouldBeErrorId "PSArgumentException"
|
||||
{ [SemanticVersion]::new([Version]::new("1.2.3.4")) } | ShouldBeErrorId "PSArgumentException"
|
||||
}
|
||||
}
|
||||
|
||||
Context "Serialization" {
|
||||
$testCases = @(
|
||||
@{ expectedResult = "1.0.0"; semver = [SemanticVersion]::new(1, 0, 0) }
|
||||
@{ expectedResult = "1.0.1"; semver = [SemanticVersion]::new(1, 0, 1) }
|
||||
@{ expectedResult = "1.0.0-alpha"; semver = [SemanticVersion]::new(1, 0, 0, "alpha") }
|
||||
@{ expectedResult = "1.0.0-beta"; semver = [SemanticVersion]::new(1, 0, 0, "beta") }
|
||||
@{ errorId = "PSArgumentException"; expectedResult = "1.0.0"; semver = [SemanticVersion]::new(1, 0, 0) }
|
||||
@{ errorId = "PSArgumentException"; expectedResult = "1.0.1"; semver = [SemanticVersion]::new(1, 0, 1) }
|
||||
@{ errorId = "PSArgumentException"; expectedResult = "1.0.0-alpha"; semver = [SemanticVersion]::new(1, 0, 0, "alpha") }
|
||||
@{ errorId = "PSArgumentException"; expectedResult = "1.0.0-Alpha-super.3+BLD.a1-xxx.03"; semver = [SemanticVersion]::new(1, 0, 0, "Alpha-super.3+BLD.a1-xxx.03") }
|
||||
)
|
||||
It "Can round trip: <semver>" -TestCases $testCases {
|
||||
param($semver, $expectedResult)
|
||||
|
||||
Reference in New Issue
Block a user