8000 Added Addtional Validation Attributes by dchristian3188 · Pull Request #4084 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content
193 changes: 165 additions & 28 deletions src/System.Management.Automation/engine/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -896,6 +896,31 @@ public ValidateLengthAttribute(int minLength, int maxLength) : base()
}
}

/// <Summary>
/// Predefined range kind to use with ValidateRangeAttribute.
/// </Summary>
public enum ValidateRangeKind
{
/// <Summary>
/// Range is greater than 0.
/// </Summary>
Positive,

/// <Summary>
/// Range is greater than or equal to 0.
/// </Summary>
NonNegative,

/// <Summary>
/// Range is less than 0.
/// </Summary>
Negative,

/// <Summary>
/// Range is less than or equal to 0.
/// </Summary>
NonPositive
}
/// <summary>
/// Validates that each parameter argument falls in the range
/// specified by MinRange and MaxRange
Expand Down Expand Up @@ -923,6 +948,8 @@ public sealed class ValidateRangeAttribute : ValidateEnumeratedArgumentsAttribut
/// </summary>
private Type _promotedType;

ValidateRangeKind? _rangeKind;

/// <summary>
/// Validates that each parameter argument falls in the range
/// specified by MinRange and MaxRange
Expand All @@ -948,37 +975,14 @@ protected override void ValidateElement(object element)
{
element = o.BaseObject;
}

// minRange and maxRange have the same type, so we just need
// to compare to one of them
if (element.GetType() != _promotedType)

if (_rangeKind.HasValue)
{
object resultValue;
if (LanguagePrimitives.TryConvertTo(element, _promotedType, out resultValue))
{
element = resultValue;
}
else
{
throw new ValidationMetadataException("ValidationRangeElementType",
null, Metadata.ValidateRangeElementType,
element.GetType().Name, MinRange.GetType().Name);
}
ValidateRange(element, (ValidateRangeKind)_rangeKind);
}

// They are the same type and are all IComparable, so this should not throw
if (_minComparable.CompareTo(element) > 0)
{
throw new ValidationMetadataException("ValidateRangeTooSmall",
null, Metadata.ValidateRangeSmallerThanMinRangeFailure,
element.ToString(), MinRange.ToString());
}

if (_maxComparable.CompareTo(element) < 0)
else
{
throw new ValidationMetadataException("ValidateRangeTooBig",
null, Metadata.ValidateRangeGreaterThanMaxRangeFailure,
element.ToString(), MaxRange.ToString());
ValidateRange(element);
}
}

Expand Down Expand Up @@ -1055,6 +1059,139 @@ public ValidateRangeAttribute(object minRange, object maxRange) : base()
MaxRange = maxRange;
}

/// <summary>
/// Initializes a new instance of the ValidateRangeAttribute class
/// this constructor uses a predefined ranged
/// </summary>
public ValidateRangeAttribute(ValidateRangeKind kind) : base()
{
_rangeKind = kind;
}

private void ValidateRange(object element, ValidateRangeKind rangeKind)
{
Type commonType = GetCommonType(typeof(int),element.GetType());
if (commonType == null)
{
throw new ValidationMetadataException(
"ValidationRangeElementType",
null,
Metadata.ValidateRangeElementType,
element.GetType().Name,
typeof(int).Name);
}

object resultValue;
IComparable dynamicZero = 0;

if (LanguagePrimitives.TryConvertTo(element, commonType, out resultValue))
{
element = resultValue;

if (LanguagePrimitives.TryConvertTo(0, commonType, out resultValue))
{
dynamicZero = (IComparable)resultValue;
}
}
else
{
throw new ValidationMetadataException(
"ValidationRangeElementType",
null,
Metadata.ValidateRangeElementType,
element.GetType().Name,
commonType.Name);
}

switch (rangeKind)
{
case ValidateRangeKind.Positive:
if (dynamicZero.CompareTo(element) >= 0)
{
throw new ValidationMetadataException(
"ValidateRangePositiveFailure",
null,
Metadata.ValidateRangePositiveFailure,
element.ToString());
}
break;
case ValidateRangeKind.NonNegative:
if (dynamicZero.CompareTo(element) > 0)
{
throw new ValidationMetadataException(
"ValidateRangeNonNegativeFailure",
null,
Metadata.ValidateRangeNonNegativeFailure,
element.ToString());
}
break;
case ValidateRangeKind.Negative:
if (dynamicZero.CompareTo(element) <= 0)
{
throw new ValidationMetadataException(
"ValidateRangeNegativeFailure",
null,
Metadata.ValidateRangeNegativeFailure,
element.ToString());
}
break;
case ValidateRangeKind.NonPositive:
if (dynamicZero.CompareTo(element) < 0)
{
throw new ValidationMetadataException(
"ValidateRangeNonPositiveFailure",
null,
Metadata.ValidateRangeNonPositiveFailure,
element.ToString());
}
break;
}
}

private void ValidateRange(object element)
{
// MinRange and maxRange have the same type, so we just need
// to compare to one of them.
if (element.GetType() != _promotedType)
{
object resultValue;
if (LanguagePrimitives.TryConvertTo(element, _promotedType, out resultValue))
{
element = resultValue;
}
else
{
throw new ValidationMetadataException(
"ValidationRangeElementType",
null,
Metadata.ValidateRangeElementType,
element.GetType().Name,
MinRange.GetType().Name);
}
}

// They are the same type and are all IComparable, so this should not throw
if (_minComparable.CompareTo(element) > 0)
{
throw new ValidationMetadataException(
"ValidateRangeTooSmall",
null,
Metadata.ValidateRangeSmallerThanMinRangeFailure,
element.ToString(),
MinRange.ToString());
}

if (_maxComparable.CompareTo(element) < 0)
{
throw new ValidationMetadataException(
"ValidateRangeTooBig",
null,
Metadata.ValidateRangeGreaterThanMaxRangeFailure,
element.ToString(),
MaxRange.ToString());
}
}

private static Type GetCommonType(Type minType, Type maxType)
{
Type resultType = null;
Expand Down
12 changes: 12 additions & 0 deletions src/System.Management.Automation/resources/Metadata.resx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@
<data name="ValidateRangeElementType" xml:space="preserve">
<value>The argument cannot be validated because its type "{0}" is not the same type ({1}) as the maximum and minimum limits of the parameter. Make sure the argument is of type {1} and then try the command again.</value>
</data>
<data name="ValidateRangePositiveFailure" xml:space="preserve">
<value>The argument "{0}" cannot be validated because its value is not greater than zero.</value>
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can "validate" but cannot "accept". Maybe better change this. Below too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, this does make more sense. It also follows the same verbiage as existing Validate Range

</data>
<data name="ValidateRangeNonNegativeFailure" xml:space="preserve">
<value>The argument "{0}" cannot be validated because its value is not greater than or equal to zero.</value>
</data>
<data name="ValidateRangeNegativeFailure" xml:space="preserve">
<value>The argument "{0}" cannot be validated because its value is not less than zero.</value>
</data>
<data name="ValidateRangeNonPositiveFailure" xml:space="preserve">
<value>The argument "{0}" cannot be validated because its value is not less than or equal to zero.</value>
</data>
<data name="ValidateRangeMinRangeMaxRangeType" xml:space="preserve">
<value>The specified minimum range ({0}) cannot be accepted because it is not the same type as the specified maximum range ({1}). Update the ValidateRange attribute for the parameter.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ internal MetadataException(string errorId, Exception innerException, string reso
public class ValidationMetadataException : MetadataException
{
internal const string ValidateRangeElementType = "ValidateRangeElementType";
internal const string ValidateRangePositiveFailure = "ValidateRangePositiveFailure";
internal const string ValidateRangeNonNegativeFailure = "ValidateRangeNonNegativeFailure";
internal const string ValidateRangeNegativeFailure = "ValidateRangeNegativeFailure";
internal const string ValidateRangeNonPositiveFailure = "ValidateRangeNonPositiveFailure";
internal const string ValidateRangeMinRangeMaxRangeType = "ValidateRangeMinRangeMaxRangeType";
internal const string ValidateRangeNotIComparable = "ValidateRangeNotIComparable";
internal const string ValidateRangeMaxRangeSmallerThanMinRange = "ValidateRangeMaxRangeSmallerThanMinRange";
Expand Down
Loading
0