Consider DBNull.Value
and NullString.Value
the same as $null
when comparing with $null
and casting to bool (#9794)
- Adds `LanguagePrimitives.IsNullLike()` method to account for `DBNull.Value` and `NullString.Value` so that they can be considered the same as a null value where sensible in PowerShell. - Updates `-ne` and `-eq` binders to treat `DBNull.Value` and `NullString.Value` as equal to null/AutomationNull. - Update code paths for comparing objects in LanguagePrimitives to ensure consistency with how the `-eq` and `-ne` binders work when calling LanguagePrimitives methods to do the comparisons. - Make `LanguagePrimitives.IsNull()` and `LanguagePrimitives.IsNullLike()` public methods. - Added tests for null behaviours in `NullRepresentatives.Tests.ps1`
This commit is contained in:
parent
f3a3922285
commit
b34e331d63
|
@ -593,9 +593,7 @@ namespace System.Management.Automation
|
|||
/// <param name="second">Object to compare first to.</param>
|
||||
/// <returns>True if first is equal to the second.</returns>
|
||||
public static new bool Equals(object first, object second)
|
||||
{
|
||||
return Equals(first, second, false, CultureInfo.InvariantCulture);
|
||||
}
|
||||
=> Equals(first, second, false, CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// Used to compare two objects for equality converting the second to the type of the first, if required.
|
||||
|
@ -606,9 +604,7 @@ namespace System.Management.Automation
|
|||
/// to specify the type of string comparison </param>
|
||||
/// <returns>True if first is equal to the second.</returns>
|
||||
public static bool Equals(object first, object second, bool ignoreCase)
|
||||
{
|
||||
return Equals(first, second, ignoreCase, CultureInfo.InvariantCulture);
|
||||
}
|
||||
=> Equals(first, second, ignoreCase, CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// Used to compare two objects for equality converting the second to the type of the first, if required.
|
||||
|
@ -646,25 +642,28 @@ namespace System.Management.Automation
|
|||
|
||||
if (first == null)
|
||||
{
|
||||
if (second == null) return true;
|
||||
return false;
|
||||
return IsNullLike(second);
|
||||
}
|
||||
|
||||
if (second == null)
|
||||
{
|
||||
return false; // first is not null
|
||||
return IsNullLike(first);
|
||||
}
|
||||
|
||||
string firstString = first as string;
|
||||
string secondString;
|
||||
if (firstString != null)
|
||||
if (first is string firstString)
|
||||
{
|
||||
secondString = second as string ?? (string)LanguagePrimitives.ConvertTo(second, typeof(string), culture);
|
||||
return (culture.CompareInfo.Compare(firstString, secondString,
|
||||
ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None) == 0);
|
||||
return culture.CompareInfo.Compare(
|
||||
firstString,
|
||||
secondString,
|
||||
ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None) == 0;
|
||||
}
|
||||
|
||||
if (first.Equals(second)) return true;
|
||||
if (first.Equals(second))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Type firstType = first.GetType();
|
||||
Type secondType = second.GetType();
|
||||
|
@ -708,24 +707,24 @@ namespace System.Management.Automation
|
|||
/// Helper method for [Try]Compare to determine object ordering with null.
|
||||
/// </summary>
|
||||
/// <param name="value">The numeric value to compare to null.</param>
|
||||
/// <param name="numberIsRightHandSide">True if the number to compare is on the right hand side if the comparison.</param>
|
||||
/// <param name="numberIsRightHandSide">True if the number to compare is on the right hand side in the comparison.</param>
|
||||
private static int CompareObjectToNull(object value, bool numberIsRightHandSide)
|
||||
{
|
||||
var i = numberIsRightHandSide ? -1 : 1;
|
||||
|
||||
// If it's a positive number, including 0, it's greater than null
|
||||
// for everything else it's less than zero...
|
||||
switch (value)
|
||||
return value switch
|
||||
{
|
||||
case Int16 i16: return Math.Sign(i16) < 0 ? -i : i;
|
||||
case Int32 i32: return Math.Sign(i32) < 0 ? -i : i;
|
||||
case Int64 i64: return Math.Sign(i64) < 0 ? -i : i;
|
||||
case sbyte sby: return Math.Sign(sby) < 0 ? -i : i;
|
||||
case float f: return Math.Sign(f) < 0 ? -i : i;
|
||||
case double d: return Math.Sign(d) < 0 ? -i : i;
|
||||
case decimal de: return Math.Sign(de) < 0 ? -i : i;
|
||||
default: return i;
|
||||
}
|
||||
Int16 i16 => Math.Sign(i16) < 0 ? -i : i,
|
||||
Int32 i32 => Math.Sign(i32) < 0 ? -i : i,
|
||||
Int64 i64 => Math.Sign(i64) < 0 ? -i : i,
|
||||
sbyte s => Math.Sign(s) < 0 ? -i : i,
|
||||
float f => Math.Sign(f) < 0 ? -i : i,
|
||||
double d => Math.Sign(d) < 0 ? -i : i,
|
||||
decimal m => Math.Sign(m) < 0 ? -i : i,
|
||||
_ => IsNullLike(value) ? 0 : i
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -741,9 +740,7 @@ namespace System.Management.Automation
|
|||
/// to the type of <paramref name="first"/>.
|
||||
/// </exception>
|
||||
public static int Compare(object first, object second)
|
||||
{
|
||||
return LanguagePrimitives.Compare(first, second, false, CultureInfo.InvariantCulture);
|
||||
}
|
||||
=> LanguagePrimitives.Compare(first, second, false, CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// Compare first and second, converting second to the
|
||||
|
@ -759,9 +756,7 @@ namespace System.Management.Automation
|
|||
/// to the type of <paramref name="first"/>.
|
||||
/// </exception>
|
||||
public static int Compare(object first, object second, bool ignoreCase)
|
||||
{
|
||||
return LanguagePrimitives.Compare(first, second, ignoreCase, CultureInfo.InvariantCulture);
|
||||
}
|
||||
=> LanguagePrimitives.Compare(first, second, ignoreCase, CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>
|
||||
/// Compare first and second, converting second to the
|
||||
|
@ -779,15 +774,12 @@ namespace System.Management.Automation
|
|||
/// </exception>
|
||||
public static int Compare(object first, object second, bool ignoreCase, IFormatProvider formatProvider)
|
||||
{
|
||||
if (formatProvider == null)
|
||||
{
|
||||
formatProvider = CultureInfo.InvariantCulture;
|
||||
}
|
||||
formatProvider ??= CultureInfo.InvariantCulture;
|
||||
|
||||
var culture = formatProvider as CultureInfo;
|
||||
if (culture == null)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentException("formatProvider");
|
||||
throw PSTraceSource.NewArgumentException(nameof(formatProvider));
|
||||
}
|
||||
|
||||
first = PSObject.Base(first);
|
||||
|
@ -795,7 +787,7 @@ namespace System.Management.Automation
|
|||
|
||||
if (first == null)
|
||||
{
|
||||
return second == null ? 0 : CompareObjectToNull(second, true);
|
||||
return CompareObjectToNull(second, true);
|
||||
}
|
||||
|
||||
if (second == null)
|
||||
|
@ -805,7 +797,7 @@ namespace System.Management.Automation
|
|||
|
||||
if (first is string firstString)
|
||||
{
|
||||
string secondString = second as string;
|
||||
var secondString = second as string;
|
||||
if (secondString == null)
|
||||
{
|
||||
try
|
||||
|
@ -814,19 +806,26 @@ namespace System.Management.Automation
|
|||
}
|
||||
catch (PSInvalidCastException e)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentException("second", ExtendedTypeSystem.ComparisonFailure,
|
||||
first.ToString(), second.ToString(), e.Message);
|
||||
throw PSTraceSource.NewArgumentException(
|
||||
nameof(second),
|
||||
ExtendedTypeSystem.ComparisonFailure,
|
||||
first.ToString(),
|
||||
second.ToString(),
|
||||
e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return culture.CompareInfo.Compare(firstString, secondString,
|
||||
ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
|
||||
return culture.CompareInfo.Compare(
|
||||
firstString,
|
||||
secondString,
|
||||
ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
|
||||
}
|
||||
|
||||
Type firstType = first.GetType();
|
||||
Type secondType = second.GetType();
|
||||
int firstIndex = LanguagePrimitives.TypeTableIndex(firstType);
|
||||
int secondIndex = LanguagePrimitives.TypeTableIndex(secondType);
|
||||
|
||||
if ((firstIndex != -1) && (secondIndex != -1))
|
||||
{
|
||||
return LanguagePrimitives.NumericCompare(first, second, firstIndex, secondIndex);
|
||||
|
@ -839,8 +838,12 @@ namespace System.Management.Automation
|
|||
}
|
||||
catch (PSInvalidCastException e)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentException("second", ExtendedTypeSystem.ComparisonFailure,
|
||||
first.ToString(), second.ToString(), e.Message);
|
||||
throw PSTraceSource.NewArgumentException(
|
||||
nameof(second),
|
||||
ExtendedTypeSystem.ComparisonFailure,
|
||||
first.ToString(),
|
||||
second.ToString(),
|
||||
e.Message);
|
||||
}
|
||||
|
||||
if (first is IComparable firstComparable)
|
||||
|
@ -855,7 +858,7 @@ namespace System.Management.Automation
|
|||
|
||||
// At this point, we know that they aren't equal but we have no way of
|
||||
// knowing which should compare greater than the other so we throw an exception.
|
||||
throw PSTraceSource.NewArgumentException("first", ExtendedTypeSystem.NotIcomparable, first.ToString());
|
||||
throw PSTraceSource.NewArgumentException(nameof(first), ExtendedTypeSystem.NotIcomparable, first.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -868,9 +871,7 @@ namespace System.Management.Automation
|
|||
/// zero if it is greater or zero if they are the same.</param>
|
||||
/// <returns>True if the comparison was successful, false otherwise.</returns>
|
||||
public static bool TryCompare(object first, object second, out int result)
|
||||
{
|
||||
return TryCompare(first, second, ignoreCase: false, CultureInfo.InvariantCulture, out result);
|
||||
}
|
||||
=> TryCompare(first, second, ignoreCase: false, CultureInfo.InvariantCulture, out result);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to compare first and second, converting second to the type of the first, if necessary.
|
||||
|
@ -882,9 +883,7 @@ namespace System.Management.Automation
|
|||
/// <param name="result">Less than zero if first is smaller than second, more than zero if it is greater or zero if they are the same.</param>
|
||||
/// <returns>True if the comparison was successful, false otherwise.</returns>
|
||||
public static bool TryCompare(object first, object second, bool ignoreCase, out int result)
|
||||
{
|
||||
return TryCompare(first, second, ignoreCase, CultureInfo.InvariantCulture, out result);
|
||||
}
|
||||
=> TryCompare(first, second, ignoreCase, CultureInfo.InvariantCulture, out result);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to compare first and second, converting second to the type of the first, if necessary.
|
||||
|
@ -900,10 +899,7 @@ namespace System.Management.Automation
|
|||
public static bool TryCompare(object first, object second, bool ignoreCase, IFormatProvider formatProvider, out int result)
|
||||
{
|
||||
result = 0;
|
||||
if (formatProvider == null)
|
||||
{
|
||||
formatProvider = CultureInfo.InvariantCulture;
|
||||
}
|
||||
formatProvider ??= CultureInfo.InvariantCulture;
|
||||
|
||||
if (!(formatProvider is CultureInfo culture))
|
||||
{
|
||||
|
@ -988,8 +984,10 @@ namespace System.Management.Automation
|
|||
public static bool IsTrue(object obj)
|
||||
{
|
||||
// null is a valid argument - it converts to false...
|
||||
if (obj == null || obj == AutomationNull.Value)
|
||||
if (IsNullLike(obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = PSObject.Base(obj);
|
||||
|
||||
|
@ -1015,8 +1013,7 @@ namespace System.Management.Automation
|
|||
if (objType == typeof(SwitchParameter))
|
||||
return ((SwitchParameter)obj).ToBool();
|
||||
|
||||
IList objectArray = obj as IList;
|
||||
if (objectArray != null)
|
||||
if (obj is IList objectArray)
|
||||
{
|
||||
return IsTrue(objectArray);
|
||||
}
|
||||
|
@ -1062,14 +1059,19 @@ namespace System.Management.Automation
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal routine that determines if an object meets any of our criteria for null.
|
||||
/// Internal routine that determines if an object meets any of our criteria for true null.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test.</param>
|
||||
/// <returns>True if the object is null.</returns>
|
||||
internal static bool IsNull(object obj)
|
||||
{
|
||||
return (obj == null || obj == AutomationNull.Value);
|
||||
}
|
||||
public static bool IsNull(object obj) => obj == null || obj == AutomationNull.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Internal routine that determines if an object meets any of our criteria for null.
|
||||
/// This method additionally checks for <see cref="NullString.Value"/> and <see cref="DBNull.Value"/>
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to test.</param>
|
||||
/// <returns>True if the object is null.</returns>
|
||||
public static bool IsNullLike(object obj) => obj == DBNull.Value || obj == NullString.Value || IsNull(obj);
|
||||
|
||||
/// <summary>
|
||||
/// Auxiliary for the cases where we want a new PSObject or null.
|
||||
|
@ -3100,15 +3102,17 @@ namespace System.Management.Automation
|
|||
return AutomationNull.Value;
|
||||
}
|
||||
|
||||
private static bool ConvertClassToBool(object valueToConvert,
|
||||
Type resultType,
|
||||
bool recursion,
|
||||
PSObject originalValueToConvert,
|
||||
IFormatProvider formatProvider,
|
||||
TypeTable backupTable)
|
||||
private static bool ConvertClassToBool(
|
||||
object valueToConvert,
|
||||
Type resultType,
|
||||
bool recursion,
|
||||
PSObject originalValueToConvert,
|
||||
IFormatProvider formatProvider,
|
||||
TypeTable backupTable)
|
||||
{
|
||||
typeConversion.WriteLine("Converting ref to boolean.");
|
||||
return valueToConvert != null;
|
||||
// Both NullString and DBNull should be treated the same as true nulls for the purposes of this conversion.
|
||||
return !IsNullLike(valueToConvert);
|
||||
}
|
||||
|
||||
private static bool ConvertValueToBool(object valueToConvert,
|
||||
|
@ -4724,10 +4728,11 @@ namespace System.Management.Automation
|
|||
{
|
||||
PSObject valueAsPsObj;
|
||||
Type originalType;
|
||||
if (valueToConvert == null || valueToConvert == AutomationNull.Value)
|
||||
|
||||
if (IsNull(valueToConvert))
|
||||
{
|
||||
valueAsPsObj = null;
|
||||
originalType = typeof(Null);
|
||||
valueAsPsObj = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3028,7 +3028,9 @@ namespace System.Management.Automation.Language
|
|||
if (target.Value == null)
|
||||
{
|
||||
return new DynamicMetaObject(
|
||||
arg.Value == null ? ExpressionCache.BoxedTrue : ExpressionCache.BoxedFalse,
|
||||
LanguagePrimitives.IsNullLike(arg.Value)
|
||||
? ExpressionCache.BoxedTrue
|
||||
: ExpressionCache.BoxedFalse,
|
||||
target.CombineRestrictions(arg));
|
||||
}
|
||||
|
||||
|
@ -3036,7 +3038,9 @@ namespace System.Management.Automation.Language
|
|||
if (enumerable == null && arg.Value == null)
|
||||
{
|
||||
return new DynamicMetaObject(
|
||||
ExpressionCache.BoxedFalse,
|
||||
LanguagePrimitives.IsNullLike(target.Value)
|
||||
? ExpressionCache.BoxedTrue
|
||||
: ExpressionCache.BoxedFalse,
|
||||
target.CombineRestrictions(arg));
|
||||
}
|
||||
|
||||
|
@ -3051,14 +3055,19 @@ namespace System.Management.Automation.Language
|
|||
if (target.Value == null)
|
||||
{
|
||||
return new DynamicMetaObject(
|
||||
arg.Value == null ? ExpressionCache.BoxedFalse : ExpressionCache.BoxedTrue,
|
||||
LanguagePrimitives.IsNullLike(arg.Value)
|
||||
? ExpressionCache.BoxedFalse
|
||||
: ExpressionCache.BoxedTrue,
|
||||
target.CombineRestrictions(arg));
|
||||
}
|
||||
|
||||
var enumerable = PSEnumerableBinder.IsEnumerable(target);
|
||||
if (enumerable == null && arg.Value == null)
|
||||
{
|
||||
return new DynamicMetaObject(ExpressionCache.BoxedTrue,
|
||||
return new DynamicMetaObject(
|
||||
LanguagePrimitives.IsNullLike(target.Value)
|
||||
? ExpressionCache.BoxedFalse
|
||||
: ExpressionCache.BoxedTrue,
|
||||
target.CombineRestrictions(arg));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
using namespace System.Management.Automation.Internal
|
||||
|
||||
Describe 'Null Representatives' -Tags 'CI' {
|
||||
|
||||
Context 'Comparisons with $null' {
|
||||
BeforeAll {
|
||||
$TestValues = @(
|
||||
@{ Value = { [AutomationNull]::Value } }
|
||||
@{ Value = { [DBNull]::Value } }
|
||||
@{ Value = { [NullString]::Value } }
|
||||
)
|
||||
}
|
||||
|
||||
It '<Value> should be equivalent to $null (RHS: $null)' -TestCases $TestValues {
|
||||
param($Value)
|
||||
|
||||
$Value.InvokeReturnAsIs() -eq $null | Should -BeTrue
|
||||
}
|
||||
|
||||
It '$null should be equivalent to <Value> (LHS: $null)' -TestCases $TestValues {
|
||||
param($Value)
|
||||
|
||||
$null -eq $Value.InvokeReturnAsIs() | Should -BeTrue
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Comparisons with other null representatives' {
|
||||
<#
|
||||
The only unequal null-representatives are NullString and DBNull.
|
||||
AutomationNull and $null are always considered equal already, so therefore NullString compares as
|
||||
true with both of them, as does DBNull.
|
||||
|
||||
However, as NullString and DBNull have different purposes, it makes more sense to consider them unequal
|
||||
when directly compared with each other.
|
||||
#>
|
||||
It 'DBNull should not be equal to NullString' {
|
||||
[DBNull]::Value -eq [NullString]::Value | Should -BeFalse
|
||||
[NullString]::Value -eq [DBNull]::Value | Should -BeFalse
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Casting Behaviour' {
|
||||
BeforeAll {
|
||||
$TestValues = @(
|
||||
@{ Value = { $null } }
|
||||
@{ Value = { [DBNull]::Value } }
|
||||
@{ Value = { [NullString]::Value } }
|
||||
@{ Value = { [AutomationNull]::Value } }
|
||||
)
|
||||
}
|
||||
|
||||
It '<Value> should cast to $false' -TestCases $TestValues {
|
||||
param($Value)
|
||||
|
||||
[bool]($Value.InvokeReturnAsIs()) | Should -BeFalse
|
||||
}
|
||||
|
||||
It '-not <Value> should be $true' -TestCases $TestValues {
|
||||
param($Value)
|
||||
|
||||
-not $Value.InvokeReturnAsIs() | Should -BeTrue
|
||||
}
|
||||
|
||||
It '<Value> should be treated as $false by Where-Object' -TestCases $TestValues {
|
||||
param($Value)
|
||||
|
||||
100 | Where-Object { $Value.InvokeReturnAsIs() } | Should -BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
Context 'Collection Comparisons' {
|
||||
BeforeAll {
|
||||
$NullArray = $null, $null, [DBNull]::Value, $null, $null, [NullString]::Value
|
||||
}
|
||||
|
||||
It '<Value> should correctly filter the array and return <ExpectedCount> results' {
|
||||
param($Value, $ExpectedCount)
|
||||
|
||||
$NullArray -eq $Value | Should -HaveCount $ExpectedCount
|
||||
} -TestCases @(
|
||||
@{ Value = $null; ExpectedCount = 6 }
|
||||
@{ Value = [DBNull]::Value; ExpectedCount = 5 }
|
||||
@{ Value = [NullString]::Value; ExpectedCount = 5 }
|
||||
)
|
||||
}
|
||||
}
|
|
@ -109,8 +109,8 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
|||
@{ 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}
|
||||
@{ lhs = $v2_1_0; rhs = "3.0" }
|
||||
@{ lhs = "1.5"; rhs = $v2_1_0 }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -176,38 +176,39 @@ Describe "SemanticVersion api tests" -Tags 'CI' {
|
|||
Context "Error handling" {
|
||||
|
||||
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" }
|
||||
@{ 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) } | Should -Throw -ErrorId $errorId
|
||||
if ($version -eq $null) {
|
||||
if ([LanguagePrimitives]::IsNull($version)) {
|
||||
# PowerShell convert $null to Empty string
|
||||
{ [SemanticVersion]::Parse($version) } | Should -Throw -ErrorId "FormatException"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
{ [SemanticVersion]::Parse($version) } | Should -Throw -ErrorId $errorId
|
||||
}
|
||||
$semVer = $null
|
||||
|
|
Loading…
Reference in a new issue