commit
aa72512c76
|
@ -20,6 +20,8 @@
|
|||
using System.Net;
|
||||
using Microsoft.PackageManagement.Provider.Utility;
|
||||
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
/// <summary>
|
||||
/// This class drives the Request class that is an interface exposed from the PackageManagement Platform to the provider to use.
|
||||
/// </summary>
|
||||
|
|
|
@ -11,6 +11,8 @@ namespace Microsoft.PackageManagement.NuGetProvider
|
|||
using System.Reflection;
|
||||
using System.Management.Automation;
|
||||
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
/// <summary>
|
||||
/// A Package provider to the PackageManagement Platform.
|
||||
///
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
|
|||
using Microsoft.PackageManagement.Provider.Utility;
|
||||
using Microsoft.Win32;
|
||||
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
internal static class ExePackageInstaller
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
|
|||
using Microsoft.PackageManagement.Provider.Utility;
|
||||
using ErrorCategory = PackageManagement.Internal.ErrorCategory;
|
||||
using System.Globalization;
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
internal static class NupkgInstaller {
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ using Microsoft.PackageManagement.Provider.Utility;
|
|||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
namespace Microsoft.PackageManagement.PackageSourceListProvider
|
||||
{
|
||||
internal static class JsonParser
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace Microsoft.PackageManagement.PackageSourceListProvider
|
|||
using Microsoft.PackageManagement.Implementation;
|
||||
using Microsoft.PackageManagement.Internal.Api;
|
||||
using Microsoft.PackageManagement.Provider.Utility;
|
||||
using SemanticVersion = Microsoft.PackageManagement.Provider.Utility.SemanticVersion;
|
||||
|
||||
public abstract class PackageSourceListRequest : Request {
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation.Internal;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace System.Management.Automation
|
||||
|
@ -37,6 +39,7 @@ namespace System.Management.Automation
|
|||
static Version _psV4Version = new Version(4, 0);
|
||||
static Version _psV5Version = new Version(5, 0);
|
||||
static Version _psV51Version = new Version(5, 1, NTVerpVars.PRODUCTBUILD, NTVerpVars.PRODUCTBUILD_QFE);
|
||||
static SemanticVersion _psV6Version = new SemanticVersion(6, 0, 0, "alpha");
|
||||
|
||||
/// <summary>
|
||||
/// A constant to track current PowerShell Edition
|
||||
|
@ -57,11 +60,11 @@ namespace System.Management.Automation
|
|||
{
|
||||
_psVersionTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
_psVersionTable[PSVersionInfo.PSVersionName] = _psV51Version;
|
||||
_psVersionTable[PSVersionInfo.PSVersionName] = _psV6Version;
|
||||
_psVersionTable["PSEdition"] = PSEditionValue;
|
||||
_psVersionTable["BuildVersion"] = GetBuildVersion();
|
||||
_psVersionTable["GitCommitId"] = GetCommitInfo();
|
||||
_psVersionTable["PSCompatibleVersions"] = new Version[] { _psV1Version, _psV2Version, _psV3Version, _psV4Version, _psV5Version, _psV51Version };
|
||||
_psVersionTable["PSCompatibleVersions"] = new Version[] { _psV1Version, _psV2Version, _psV3Version, _psV4Version, _psV5Version, _psV51Version, _psV6Version };
|
||||
_psVersionTable[PSVersionInfo.SerializationVersionName] = new Version(InternalSerializer.DefaultVersion);
|
||||
_psVersionTable[PSVersionInfo.PSRemotingProtocolVersionName] = RemotingConstants.ProtocolVersion;
|
||||
_psVersionTable[PSVersionInfo.WSManStackVersionName] = GetWSManStackVersion();
|
||||
|
@ -140,7 +143,7 @@ namespace System.Management.Automation
|
|||
{
|
||||
get
|
||||
{
|
||||
return (Version) GetPSVersionTable()[PSVersionInfo.PSVersionName];
|
||||
return (SemanticVersion) GetPSVersionTable()[PSVersionInfo.PSVersionName];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,6 +250,10 @@ namespace System.Management.Automation
|
|||
|
||||
static internal bool IsValidPSVersion(Version version)
|
||||
{
|
||||
if (version.Major == _psV6Version.Major)
|
||||
{
|
||||
return version.Minor == _psV6Version.Minor;
|
||||
}
|
||||
if (version.Major == _psV5Version.Major)
|
||||
{
|
||||
return (version.Minor == _psV5Version.Minor || version.Minor == _psV51Version.Minor);
|
||||
|
@ -286,7 +293,460 @@ namespace System.Management.Automation
|
|||
get { return _psV51Version; }
|
||||
}
|
||||
|
||||
static internal SemanticVersion PSV6Version
|
||||
{
|
||||
get { return _psV6Version; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of semantic versioning (http://semver.org)
|
||||
/// that can be converted to/from <see cref="System.Version"/>.
|
||||
///
|
||||
/// When converting to <see cref="Version"/>, a PSNoteProperty is
|
||||
/// added to the instance to store the semantic version label so
|
||||
/// that it can be recovered when creating a new SemanticVersion.
|
||||
/// </summary>
|
||||
public sealed class SemanticVersion : IComparable, IComparable<SemanticVersion>, IEquatable<SemanticVersion>
|
||||
{
|
||||
/// <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)
|
||||
{
|
||||
var v = SemanticVersion.Parse(version);
|
||||
|
||||
Major = v.Major;
|
||||
Minor = v.Minor;
|
||||
Patch = v.Patch;
|
||||
Label = v.Label;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SemanticVersion.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version</param>
|
||||
/// <param name="minor">The minor version</param>
|
||||
/// <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>
|
||||
public SemanticVersion(int major, int minor, int patch, string label)
|
||||
: this(major, minor, patch)
|
||||
{
|
||||
if (string.IsNullOrEmpty(label)) throw PSTraceSource.NewArgumentNullException(nameof(label));
|
||||
|
||||
Label = label;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a SemanticVersion.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version</param>
|
||||
/// <param name="minor">The minor version</param>
|
||||
/// <param name="patch">The minor version</param>
|
||||
/// <exception cref="PSArgumentException">
|
||||
/// If <paramref name="major"/>, <paramref name="minor"/>, or <paramref name="patch"/> is less than 0.
|
||||
/// </exception>
|
||||
public SemanticVersion(int major, int minor, int patch)
|
||||
{
|
||||
if (major < 0) throw PSTraceSource.NewArgumentException(nameof(major));
|
||||
if (minor < 0) throw PSTraceSource.NewArgumentException(nameof(minor));
|
||||
if (patch < 0) throw PSTraceSource.NewArgumentException(nameof(patch));
|
||||
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
Patch = patch;
|
||||
Label = null;
|
||||
}
|
||||
|
||||
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>
|
||||
public SemanticVersion(Version version)
|
||||
{
|
||||
if (version.Revision > 0 || version.Build < 0) throw PSTraceSource.NewArgumentException(nameof(version));
|
||||
|
||||
Major = version.Major;
|
||||
Minor = version.Minor;
|
||||
Patch = version.Build;
|
||||
var psobj = new PSObject(version);
|
||||
var labelNote = psobj.Properties[LabelPropertyName];
|
||||
if (labelNote != null)
|
||||
{
|
||||
Label = labelNote.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.
|
||||
/// </summary>
|
||||
/// <param name="semver"></param>
|
||||
public static implicit operator Version(SemanticVersion semver)
|
||||
{
|
||||
var result = new Version(semver.Major, semver.Minor, semver.Patch);
|
||||
|
||||
if (!string.IsNullOrEmpty(semver.Label))
|
||||
{
|
||||
var psobj = new PSObject(result);
|
||||
psobj.Properties.Add(new PSNoteProperty(LabelPropertyName, semver.Label));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The major version number, never negative.
|
||||
/// </summary>
|
||||
public int Major { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number, never negative.
|
||||
/// </summary>
|
||||
public int Minor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The patch version, -1 if not specified.
|
||||
/// </summary>
|
||||
public int Patch { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The last component in a SemanticVersion - may be null if not specified.
|
||||
/// </summary>
|
||||
public string Label { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Parse <paramref name="version"/> and return the result if it is a valid <see cref="SemanticVersion"/>, otherwise throws an exception.
|
||||
/// </summary>
|
||||
/// <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));
|
||||
|
||||
var r = new VersionResult();
|
||||
r.Init(true);
|
||||
TryParseVersion(version, ref r);
|
||||
|
||||
return r._parsedVersion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse <paramref name="version"/> and return true if it is a valid <see cref="SemanticVersion"/>, otherwise return false.
|
||||
/// No exceptions are raised.
|
||||
/// </summary>
|
||||
/// <param name="version">The string to parse</param>
|
||||
/// <param name="result">The return value when the string is a valid <see cref="SemanticVersion"/></param>
|
||||
public static bool TryParse(string version, out SemanticVersion result)
|
||||
{
|
||||
if (version != null)
|
||||
{
|
||||
var r = new VersionResult();
|
||||
r.Init(false);
|
||||
|
||||
if (TryParseVersion(version, ref r))
|
||||
{
|
||||
result = r._parsedVersion;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseVersion(string version, ref VersionResult result)
|
||||
{
|
||||
var dashIndex = version.IndexOf('-');
|
||||
|
||||
// Empty label?
|
||||
if (dashIndex == version.Length - 1)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentException);
|
||||
return false;
|
||||
}
|
||||
|
||||
var versionSansLabel = (dashIndex < 0) ? version : version.Substring(0, dashIndex);
|
||||
string[] parsedComponents = versionSansLabel.Split(Utils.Separators.Dot);
|
||||
if (parsedComponents.Length != 3)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentException);
|
||||
return false;
|
||||
}
|
||||
|
||||
int major, minor, patch;
|
||||
if (!TryParseComponent(parsedComponents[0], "major", ref result, out major))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryParseComponent(parsedComponents[1], "minor", ref result, out minor))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryParseComponent(parsedComponents[2], "patch", ref result, out patch))
|
||||
{
|
||||
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))
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.FormatException, component);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parsedComponent < 0)
|
||||
{
|
||||
result.SetFailure(ParseFailureKind.ArgumentOutOfRangeException, componentName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToString
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
if (Patch < 0)
|
||||
{
|
||||
return string.IsNullOrEmpty(Label)
|
||||
? StringUtil.Format("{0}.{1}", Major, Minor)
|
||||
: StringUtil.Format("{0}.{1}-{2}", Major, Minor, Label);
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(Label)
|
||||
? StringUtil.Format("{0}.{1}.{2}", Major, Minor, Patch)
|
||||
: StringUtil.Format("{0}.{1}.{2}-{3}", Major, Minor, Patch, Label);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement <see cref="IComparable.CompareTo"/>
|
||||
/// </summary>
|
||||
public int CompareTo(object version)
|
||||
{
|
||||
if (version == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var v = version as SemanticVersion;
|
||||
if (v == null)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentException(nameof(version));
|
||||
}
|
||||
|
||||
return CompareTo(v);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement <see cref="IComparable{T}.CompareTo"/>
|
||||
/// </summary>
|
||||
public int CompareTo(SemanticVersion value)
|
||||
{
|
||||
if ((object)value == null)
|
||||
return 1;
|
||||
|
||||
if (Major != value.Major)
|
||||
return Major > value.Major ? 1 : -1;
|
||||
|
||||
if (Minor != value.Minor)
|
||||
return Minor > value.Minor ? 1 : -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override <see cref="object.Equals(object)"/>
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as SemanticVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement <see cref="IEquatable{T}.Equals(T)"/>
|
||||
/// </summary>
|
||||
public bool Equals(SemanticVersion other)
|
||||
{
|
||||
return other != null &&
|
||||
(Major == other.Major) && (Minor == other.Minor) && (Patch == other.Patch) &&
|
||||
string.Equals(Label, other.Label, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override <see cref="object.GetHashCode()"/>
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Utils.CombineHashCodes(
|
||||
Major.GetHashCode(),
|
||||
Minor.GetHashCode(),
|
||||
Patch.GetHashCode(),
|
||||
Label == null ? 0 : Label.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded == operator
|
||||
/// </summary>
|
||||
public static bool operator ==(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
if (object.ReferenceEquals(v1, null)) {
|
||||
return object.ReferenceEquals(v2, null);
|
||||
}
|
||||
|
||||
return v1.Equals(v2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded != operator
|
||||
/// </summary>
|
||||
public static bool operator !=(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
return !(v1 == v2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded < operator
|
||||
/// </summary>
|
||||
public static bool operator <(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
if ((object) v1 == null) throw PSTraceSource.NewArgumentException(nameof(v1));
|
||||
return (v1.CompareTo(v2) < 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded <= operator
|
||||
/// </summary>
|
||||
public static bool operator <=(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
if ((object) v1 == null) throw PSTraceSource.NewArgumentException(nameof(v1));
|
||||
return (v1.CompareTo(v2) <= 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded > operator
|
||||
/// </summary>
|
||||
public static bool operator >(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
return (v2 < v1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overloaded >= operator
|
||||
/// </summary>
|
||||
public static bool operator >=(SemanticVersion v1, SemanticVersion v2)
|
||||
{
|
||||
return (v2 <= v1);
|
||||
}
|
||||
|
||||
internal enum ParseFailureKind
|
||||
{
|
||||
ArgumentException,
|
||||
ArgumentOutOfRangeException,
|
||||
FormatException
|
||||
}
|
||||
|
||||
internal struct VersionResult
|
||||
{
|
||||
internal SemanticVersion _parsedVersion;
|
||||
internal ParseFailureKind _failure;
|
||||
internal string _exceptionArgument;
|
||||
internal bool _canThrow;
|
||||
|
||||
internal void Init(bool canThrow)
|
||||
{
|
||||
_canThrow = canThrow;
|
||||
}
|
||||
|
||||
internal void SetFailure(ParseFailureKind failure)
|
||||
{
|
||||
SetFailure(failure, String.Empty);
|
||||
}
|
||||
|
||||
internal void SetFailure(ParseFailureKind failure, string argument)
|
||||
{
|
||||
_failure = failure;
|
||||
_exceptionArgument = argument;
|
||||
if (_canThrow)
|
||||
{
|
||||
throw GetVersionParseException();
|
||||
}
|
||||
}
|
||||
|
||||
internal Exception GetVersionParseException()
|
||||
{
|
||||
switch (_failure)
|
||||
{
|
||||
case ParseFailureKind.ArgumentException:
|
||||
return PSTraceSource.NewArgumentException("version");
|
||||
case ParseFailureKind.ArgumentOutOfRangeException:
|
||||
throw new ValidationMetadataException("ValidateRangeTooSmall",
|
||||
null, Metadata.ValidateRangeSmallerThanMinRangeFailure,
|
||||
_exceptionArgument, "0");
|
||||
case ParseFailureKind.FormatException:
|
||||
// Regenerate the FormatException as would be thrown by Int32.Parse()
|
||||
try
|
||||
{
|
||||
Int32.Parse(_exceptionArgument, CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
catch (OverflowException e)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return PSTraceSource.NewArgumentException("version");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
187
test/powershell/engine/SemanticVersion.Tests.ps1
Normal file
187
test/powershell/engine/SemanticVersion.Tests.ps1
Normal file
|
@ -0,0 +1,187 @@
|
|||
using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
|
||||
Describe "SemanticVersion api tests" {
|
||||
Context "constructing valid versions" {
|
||||
It "string argument constructor" {
|
||||
$v = [SemanticVersion]::new("1.2.3-alpha")
|
||||
$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 = [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.ToString() | Should Be "1.0.0"
|
||||
}
|
||||
|
||||
# After the above test, we trust the properties and rely on ToString for validation
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
It "version arg constructor" {
|
||||
$v = [SemanticVersion]::new([Version]::new(1, 2, 3))
|
||||
$v.ToString() | Should Be '1.2.3'
|
||||
}
|
||||
|
||||
It "semantic version can round trip through version" {
|
||||
$v1 = [SemanticVersion]::new(3, 2, 1, "prerelease")
|
||||
$v2 = [SemanticVersion]::new([Version]$v1)
|
||||
$v2.ToString() | Should Be "3.2.1-prerelease"
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
$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 }
|
||||
)
|
||||
It "less than" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -lt $rhs | Should Be $true
|
||||
$rhs -lt $lhs | Should Be $false
|
||||
}
|
||||
It "less than or equal" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -le $rhs | Should Be $true
|
||||
$rhs -le $lhs | Should Be $false
|
||||
$lhs -le $lhs | Should Be $true
|
||||
$rhs -le $rhs | Should Be $true
|
||||
}
|
||||
It "greater than" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -gt $rhs | Should Be $false
|
||||
$rhs -gt $lhs | Should Be $true
|
||||
}
|
||||
It "greater than or equal" -TestCases $testCases {
|
||||
param($lhs, $rhs)
|
||||
$lhs -ge $rhs | Should Be $false
|
||||
$rhs -ge $lhs | Should Be $true
|
||||
$lhs -ge $lhs | Should Be $true
|
||||
$rhs -ge $rhs | Should Be $true
|
||||
}
|
||||
|
||||
$testCases = @(
|
||||
@{ operand = $v1_0_0 }
|
||||
@{ operand = $v1_0_0_alpha }
|
||||
)
|
||||
It "Equality" -TestCases $testCases {
|
||||
param($operand)
|
||||
$operand -eq $operand | Should Be $true
|
||||
$operand -ne $operand | Should Be $false
|
||||
$null -eq $operand | Should Be $false
|
||||
$operand -eq $null | Should Be $false
|
||||
$null -ne $operand | Should Be $true
|
||||
$operand -ne $null | Should Be $true
|
||||
}
|
||||
|
||||
It "comparisons with null" {
|
||||
$v1_0_0 -lt $null | Should Be $false
|
||||
$null -lt $v1_0_0 | Should Be $true
|
||||
$v1_0_0 -le $null | Should Be $false
|
||||
$null -le $v1_0_0 | Should Be $true
|
||||
$v1_0_0 -gt $null | Should Be $true
|
||||
$null -gt $v1_0_0 | Should Be $false
|
||||
$v1_0_0 -ge $null | Should Be $true
|
||||
$null -ge $v1_0_0 | Should Be $false
|
||||
}
|
||||
}
|
||||
|
||||
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 = "-alpha" }
|
||||
@{ expectedResult = $false; version = "1.0" } # REVIEW - should this be allowed
|
||||
@{ 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" -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" -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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
# Build is required
|
||||
{ [SemanticVersion]::new([Version]::new(1, 2)) } | Should Throw # PSArgumentException
|
||||
{ [SemanticVersion]::new([Version]::new("1.2")) } | Should Throw # PSArgumentException
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue