Filter completion for enum parameter against ValidateRange attributes (#17750)

This commit is contained in:
Frode Flaten
2023-05-22 14:25:00 -07:00
committed by GitHub
parent 06ab3b189d
commit c57ada217d
4 changed files with 72 additions and 9 deletions
@@ -1311,6 +1311,28 @@ namespace System.Management.Automation
return resultType;
}
/// <summary>
/// Returns only the elements that passed the attribute's validation.
/// </summary>
/// <param name="elementsToValidate">The objects to validate.</param>
internal IEnumerable GetValidatedElements(IEnumerable elementsToValidate)
{
foreach (var el in elementsToValidate)
{
try
{
ValidateElement(el);
}
catch (ValidationMetadataException)
{
// Element was not in range - drop
continue;
}
yield return el;
}
}
}
/// <summary>
@@ -1796,9 +1796,16 @@ namespace System.Management.Automation
{
RemoveLastNullCompletionResult(result);
string enumString = LanguagePrimitives.EnumSingleTypeConverter.EnumValues(parameterType);
string separator = CultureInfo.CurrentUICulture.TextInfo.ListSeparator;
string[] enumArray = enumString.Split(separator, StringSplitOptions.RemoveEmptyEntries);
IEnumerable enumValues = LanguagePrimitives.EnumSingleTypeConverter.GetEnumValues(parameterType);
// Exclude values not accepted by ValidateRange-attributes
foreach (ValidateArgumentsAttribute att in parameter.Parameter.ValidationAttributes)
{
if (att is ValidateRangeAttribute rangeAtt)
{
enumValues = rangeAtt.GetValidatedElements(enumValues);
}
}
string wordToComplete = context.WordToComplete ?? string.Empty;
string quote = HandleDoubleAndSingleQuote(ref wordToComplete);
@@ -1806,18 +1813,19 @@ namespace System.Management.Automation
var pattern = WildcardPattern.Get(wordToComplete + "*", WildcardOptions.IgnoreCase);
var enumList = new List<string>();
foreach (string value in enumArray)
foreach (Enum value in enumValues)
{
if (wordToComplete.Equals(value, StringComparison.OrdinalIgnoreCase))
string name = value.ToString();
if (wordToComplete.Equals(name, StringComparison.OrdinalIgnoreCase))
{
string completionText = quote == string.Empty ? value : quote + value + quote;
fullMatch = new CompletionResult(completionText, value, CompletionResultType.ParameterValue, value);
string completionText = quote == string.Empty ? name : quote + name + quote;
fullMatch = new CompletionResult(completionText, name, CompletionResultType.ParameterValue, name);
continue;
}
if (pattern.IsMatch(value))
if (pattern.IsMatch(name))
{
enumList.Add(value);
enumList.Add(name);
}
}
@@ -2076,6 +2076,14 @@ namespace System.Management.Automation
return string.Join(CultureInfo.CurrentUICulture.TextInfo.ListSeparator, enumHashEntry.names);
}
/// <summary>
/// Returns all values for the provided enum type.
/// </summary>
/// <param name="enumType">The enum type to retrieve values from.</param>
/// <returns>Array of enum values for the specified type.</returns>
internal static Array GetEnumValues(Type enumType)
=> EnumSingleTypeConverter.GetEnumHashEntry(enumType).values;
public override object ConvertFrom(object sourceValue, Type destinationType, IFormatProvider formatProvider, bool ignoreCase)
{
return EnumSingleTypeConverter.BaseConvertFrom(sourceValue, destinationType, formatProvider, ignoreCase, false);
@@ -1597,6 +1597,31 @@ class InheritedClassTest : System.Attribute
$res.CompletionMatches[1].CompletionText | Should -BeExactly 'Configuration'
}
It 'Tab completion for enum parameter is filtered against <Name>' -TestCases @(
@{ Name = 'ValidateRange with enum-values'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)]' }
@{ Name = 'ValidateRange with int-values'; Attribute = '[ValidateRange(9, 11)]' }
@{ Name = 'multiple ValidateRange-attributes'; Attribute = '[ValidateRange([System.ConsoleColor]::Blue, [System.ConsoleColor]::Cyan)][ValidateRange([System.ConsoleColor]::Gray, [System.ConsoleColor]::Red)]' }
) {
param($Name, $Attribute)
$functionDefinition = 'param ( {0}[consolecolor]$color )' -f $Attribute
Set-Item -Path function:baz -Value $functionDefinition
$inputStr = 'baz -color '
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
$res.CompletionMatches | Should -HaveCount 3
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Blue'
$res.CompletionMatches[1].CompletionText | Should -BeExactly 'Cyan'
$res.CompletionMatches[2].CompletionText | Should -BeExactly 'Green'
}
It 'Tab completion for enum parameter is filtered with ValidateRange using rangekind' {
$functionDefinition = 'param ( [ValidateRange([System.Management.Automation.ValidateRangeKind]::NonPositive)][consolecolor]$color )' -f $Attribute
Set-Item -Path function:baz -Value $functionDefinition
$inputStr = 'baz -color '
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length
$res.CompletionMatches | Should -HaveCount 1
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Black' # 0 = NonPositive
}
It "Test [CommandCompletion]::GetNextResult" {
$inputStr = "Get-Command -Type Alias,c"
$res = TabExpansion2 -inputScript $inputStr -cursorColumn $inputStr.Length