From e6aaccd3a2b3fb037b22a8d54c8723fe30e43414 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 14 Sep 2017 15:03:52 +0300 Subject: [PATCH 01/13] Replace tabs with spaces --- .../Get-Date.Tests.ps1 | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 index fade58e6ece..0195673f8fa 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 @@ -82,33 +82,32 @@ Describe "Get-Date DRT Unit Tests" -Tags "CI" { Describe "Get-Date" -Tags "CI" { It "Should have colons when ToString method is used" { - (Get-Date).ToString().Contains(":") | Should be $true - (Get-Date -DisplayHint Time).ToString().Contains(":") | Should be $true - (Get-Date -DisplayHint Date).ToString().Contains(":") | Should be $true + (Get-Date).ToString().Contains(":") | Should be $true + (Get-Date -DisplayHint Time).ToString().Contains(":") | Should be $true + (Get-Date -DisplayHint Date).ToString().Contains(":") | Should be $true } It "Should be able to use the format flag" { - # You would think that one could use simple loops here, but apparently powershell in Windows returns different values in loops - - (Get-Date -Format d).Contains("/") | Should be $true - (Get-Date -Format D).Contains(",") | Should be $true - (Get-Date -Format f).Contains(",") -and (Get-Date -Format f).Contains(":") | Should be $true - (Get-Date -Format F).Contains(",") -and (Get-Date -Format F).Contains(":") | Should be $true - (Get-Date -Format g).Contains("/") -and (Get-Date -Format g).Contains(":") | Should be $true - (Get-Date -Format G).Contains("/") -and (Get-Date -Format G).Contains(":") | Should be $true - (Get-Date -Format m).Contains(",") -or ` - (Get-Date -Format m).Contains(":") -or ` - (Get-Date -Format m).Contains("/") | Should be $false + # You would think that one could use simple loops here, but apparently powershell in Windows returns different values in loops + + (Get-Date -Format d).Contains("/") | Should be $true + (Get-Date -Format D).Contains(",") | Should be $true + (Get-Date -Format f).Contains(",") -and (Get-Date -Format f).Contains(":") | Should be $true + (Get-Date -Format F).Contains(",") -and (Get-Date -Format F).Contains(":") | Should be $true + (Get-Date -Format g).Contains("/") -and (Get-Date -Format g).Contains(":") | Should be $true + (Get-Date -Format G).Contains("/") -and (Get-Date -Format G).Contains(":") | Should be $true + (Get-Date -Format m).Contains(",") -or ` + (Get-Date -Format m).Contains(":") -or ` + (Get-Date -Format m).Contains("/") | Should be $false } It "Should check that Get-Date can return the correct datetime from the system time" { - $timeDifference = $(Get-Date).Subtract([System.DateTime]::Now) + $timeDifference = $(Get-Date).Subtract([System.DateTime]::Now) - $timeDifference.Days | Should Be 0 - $timeDifference.Hours | Should Be 0 - $timeDifference.Minutes | Should Be 0 - $timeDifference.Milliseconds | Should BeLessThan 1 - $timeDifference.Ticks | Should BeLessThan 10000 + $timeDifference.Days | Should Be 0 + $timeDifference.Hours | Should Be 0 + $timeDifference.Minutes | Should Be 0 + $timeDifference.Milliseconds | Should BeLessThan 1 + $timeDifference.Ticks | Should BeLessThan 10000 } - } From 69363fd035807765b062f4ecff072d45bae6d3b1 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 14 Sep 2017 14:48:57 +0300 Subject: [PATCH 02/13] Add 'AllowAll' named parameter in ValidateSet attribute If AllowAll==true 'ValidateElement' always pass all elements. Useful if we need enable IntelliSense (TabComplete) but effectively disable validation when a parameter can accept not only the listed values but also arbitrary. Ex.: Get-Date -Format --- .../engine/Attributes.cs | 13 +++++++++++++ .../engine/parser/Compiler.cs | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index 730d945305c..b46e3899874 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -1563,6 +1563,14 @@ public sealed class ValidateSetAttribute : ValidateEnumeratedArgumentsAttribute // The valid values generator cache works across 'ValidateSetAttribute' instances. private static ConcurrentDictionary s_ValidValuesGeneratorCache = new ConcurrentDictionary(); + /// + /// If AllowAll==true 'ValidateElement' always pass all elements. + /// Useful if we need enable IntelliSense (TabComplete) but effectively disable validation + /// when a parameter can accept not only the listed values but also arbitrary. + /// Ex.: Get-Date -Format + /// + public bool AllowAll { get; set; } = false; + /// /// Gets or sets the custom error message that is displayed to the user /// @@ -1625,6 +1633,11 @@ protected override void ValidateElement(object element) Metadata.ValidateNotNullFailure); } + if (AllowAll == true) + { + return; + } + string objString = element.ToString(); foreach (string setString in ValidValues) { diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index 62462ad53af..a4237cb1d26 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -1336,6 +1336,10 @@ private static Attribute NewValidateSetAttribute(AttributeAst ast) { result.IgnoreCase = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue); } + else if (argumentName.Equals("AllowAll", StringComparison.OrdinalIgnoreCase)) + { + result.AllowAll = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue); + } else if (argumentName.Equals("ErrorMessage", StringComparison.OrdinalIgnoreCase)) { result.ErrorMessage = argValue.ToString(); From e142d4991e7b80688e831017353ded13c8884bd4 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 14 Sep 2017 13:24:10 +0300 Subject: [PATCH 03/13] Enable tab complete for '-Format' parameter of Get-Date Add ValidateSet attribute to '-Format' parameter of Get-Date to enable IntelliSense (tab complete). --- .../commands/utility/GetDateCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs index 5533721b5f6..670c97cf1be 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs @@ -206,6 +206,7 @@ public int Millisecond /// Unix format string /// [Parameter(ParameterSetName = "net")] + [ValidateSetAttribute("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal", AllowAll=true)] public string Format { get; set; } #endregion From e7ea5529fa85f2c563393225b3ae61f1f2e2d2f0 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 14 Sep 2017 15:19:11 +0300 Subject: [PATCH 04/13] Add tests for Get-Date -Format named values --- .../Get-Date.Tests.ps1 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 index 0195673f8fa..f10ffadf41e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-Date.Tests.ps1 @@ -81,6 +81,22 @@ Describe "Get-Date DRT Unit Tests" -Tags "CI" { Describe "Get-Date" -Tags "CI" { + It "-Format FileDate works" { + Get-date -Date 0030-01-01T01:02:03.0004 -Format FileDate | Should Be "00300101" + } + + It "-Format FileDateTime works" { + Get-date -Date 0030-01-01T01:02:03.0004 -Format FileDateTime | Should Be "00300101T0102030004" + } + + It "-Format FileDateTimeUniversal works" { + Get-date -Date 0030-01-01T01:02:03.0004z -Format FileDateTimeUniversal | Should Be "00300101T0102030004Z" + } + + It "-Format FileDateTimeUniversal works" { + Get-date -Date 0030-01-01T01:02:03.0004z -Format FileDateUniversal | Should Be "00300101Z" + } + It "Should have colons when ToString method is used" { (Get-Date).ToString().Contains(":") | Should be $true (Get-Date -DisplayHint Time).ToString().Contains(":") | Should be $true From ab00723030e491e0de71b7f6ddfb6faa0dc0ba66 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Fri, 15 Sep 2017 15:37:52 +0300 Subject: [PATCH 05/13] Enhance ArgumentCompleter to support custom string array Introduce new ArgumentCompleter constructor. Invoke the constructor in NativeCommandArgumentCompletion() --- .../CommandCompletion/CompletionCompleters.cs | 11 +++++ .../CommandCompletion/ExtensibleCompletion.cs | 45 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 844a3588de9..a7448354fee 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -1987,6 +1987,17 @@ private static void NativeCommandArgumentCompletion( } } } + else if (argumentCompleterAttribute.CompleteStrings != null) + { + var customResults = argumentCompleterAttribute.CompleteStrings.CompleteArgument(commandName, parameterName, + context.WordToComplete, commandAst, GetBoundArgumentsAsHashtable(context)); + if (customResults != null) + { + result.AddRange(customResults); + result.Add(CompletionResult.Null); + return; + } + } else { if (InvokeScriptArgumentCompleter( diff --git a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs index 7b001d14463..b9b94b21864 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs @@ -30,6 +30,8 @@ public class ArgumentCompleterAttribute : Attribute /// public ScriptBlock ScriptBlock { get; private set; } + internal StringArrayArgumentCompleter CompleteStrings { get; private set; } = null; + /// The type must implement and have a default constructor. public ArgumentCompleterAttribute(Type type) { @@ -54,6 +56,27 @@ public ArgumentCompleterAttribute(ScriptBlock scriptBlock) ScriptBlock = scriptBlock; } + + /// + /// Initializes a new instance of the ArgumentCompleterAttribute class + /// + /// list of complete values + /// for null arguments + /// for invalid arguments + public ArgumentCompleterAttribute(params string[] completeStrings) + { + if (completeStrings == null) + { + throw PSTraceSource.NewArgumentNullException("completeStrings"); + } + + if (completeStrings.Length == 0) + { + throw PSTraceSource.NewArgumentOutOfRangeException("completeStrings", completeStrings); + } + + CompleteStrings = new StringArrayArgumentCompleter(completeStrings); + } } /// @@ -158,4 +181,26 @@ protected override void EndProcessing() } } } + + internal class StringArrayArgumentCompleter : IArgumentCompleter + { + private string[] _completeStrings; + + public StringArrayArgumentCompleter(params string[] completeStrings) + { + _completeStrings = completeStrings; + } + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + var wordToCompletePattern = WildcardPattern.Get(string.IsNullOrWhiteSpace(wordToComplete) ? "*" : wordToComplete + "*", WildcardOptions.IgnoreCase); + + foreach (var str in _completeStrings) + { + if (wordToCompletePattern.IsMatch(str)) + { + yield return new CompletionResult(str, str, CompletionResultType.Text, str); + } + } + } + } } From 52d27995dcd845a0280eeaa45cb515778d8dd712 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Fri, 15 Sep 2017 15:39:09 +0300 Subject: [PATCH 06/13] Use new ArgumentCompleterAttribute in Get-Date cmdlet --- .../commands/utility/GetDateCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs index 670c97cf1be..0a079d1b17c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs @@ -206,7 +206,7 @@ public int Millisecond /// Unix format string /// [Parameter(ParameterSetName = "net")] - [ValidateSetAttribute("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal", AllowAll=true)] + [ArgumentCompleter("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")] public string Format { get; set; } #endregion From ceb9385ca6539055002a4f3687f5468c2ab315ef Mon Sep 17 00:00:00 2001 From: iSazonov Date: Mon, 18 Sep 2017 15:26:22 +0300 Subject: [PATCH 07/13] Add ArgumentCompletionsAttribute This attribute is used to specify an argument completions for a parameter of a cmdlet or function without force throw unlike ValidateSetAttribute. --- .../commands/utility/GetDateCommand.cs | 2 +- .../CommandCompletion/CompletionCompleters.cs | 31 +++++---- .../CommandCompletion/ExtensibleCompletion.cs | 63 ++++++++++--------- .../engine/parser/TypeResolver.cs | 1 + .../Language/Parser/TypeAccelerator.Tests.ps1 | 2 +- 5 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs index 0a079d1b17c..d3205ba5e46 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetDateCommand.cs @@ -206,7 +206,7 @@ public int Millisecond /// Unix format string /// [Parameter(ParameterSetName = "net")] - [ArgumentCompleter("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")] + [ArgumentCompletions("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")] public string Format { get; set; } #endregion diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index a7448354fee..06964351af6 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -1987,17 +1987,6 @@ private static void NativeCommandArgumentCompletion( } } } - else if (argumentCompleterAttribute.CompleteStrings != null) - { - var customResults = argumentCompleterAttribute.CompleteStrings.CompleteArgument(commandName, parameterName, - context.WordToComplete, commandAst, GetBoundArgumentsAsHashtable(context)); - if (customResults != null) - { - result.AddRange(customResults); - result.Add(CompletionResult.Null); - return; - } - } else { if (InvokeScriptArgumentCompleter( @@ -2013,6 +2002,26 @@ private static void NativeCommandArgumentCompletion( { } } + + var argumentCompletionsAttribute = parameter.CompiledAttributes.OfType().FirstOrDefault(); + if (argumentCompletionsAttribute != null) + { + try + { + var customResults = argumentCompletionsAttribute.CompleteArgument(commandName, parameterName, + context.WordToComplete, commandAst, GetBoundArgumentsAsHashtable(context)); + if (customResults != null) + { + result.AddRange(customResults); + result.Add(CompletionResult.Null); + return; + } + } + catch (Exception) + { + } + } + switch (commandName) { case "Get-Command": diff --git a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs index b9b94b21864..7426ed8ea1b 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs @@ -30,8 +30,6 @@ public class ArgumentCompleterAttribute : Attribute /// public ScriptBlock ScriptBlock { get; private set; } - internal StringArrayArgumentCompleter CompleteStrings { get; private set; } = null; - /// The type must implement and have a default constructor. public ArgumentCompleterAttribute(Type type) { @@ -56,27 +54,6 @@ public ArgumentCompleterAttribute(ScriptBlock scriptBlock) ScriptBlock = scriptBlock; } - - /// - /// Initializes a new instance of the ArgumentCompleterAttribute class - /// - /// list of complete values - /// for null arguments - /// for invalid arguments - public ArgumentCompleterAttribute(params string[] completeStrings) - { - if (completeStrings == null) - { - throw PSTraceSource.NewArgumentNullException("completeStrings"); - } - - if (completeStrings.Length == 0) - { - throw PSTraceSource.NewArgumentOutOfRangeException("completeStrings", completeStrings); - } - - CompleteStrings = new StringArrayArgumentCompleter(completeStrings); - } } /// @@ -182,19 +159,49 @@ protected override void EndProcessing() } } - internal class StringArrayArgumentCompleter : IArgumentCompleter + /// + /// This attribute is used to specify an argument completions for a parameter of a cmdlet or function + /// based on string array. + /// + /// [Parameter()] + /// [ArgumentCompletions("Option1","Option2","Option3")] + /// public string Noun { get; set; } + /// + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ArgumentCompletionsAttribute : Attribute { - private string[] _completeStrings; + private string[] _completions; - public StringArrayArgumentCompleter(params string[] completeStrings) + /// + /// Initializes a new instance of the ArgumentCompleterAttribute class + /// + /// list of complete values + /// for null arguments + /// for invalid arguments + public ArgumentCompletionsAttribute(params string[] completions) { - _completeStrings = completeStrings; + if (completions == null) + { + throw PSTraceSource.NewArgumentNullException("completions"); + } + + if (completions.Length == 0) + { + throw PSTraceSource.NewArgumentOutOfRangeException("completions", completions); + } + + _completions = completions; } + + /// + /// The function returns completions for arguments. + /// public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) { var wordToCompletePattern = WildcardPattern.Get(string.IsNullOrWhiteSpace(wordToComplete) ? "*" : wordToComplete + "*", WildcardOptions.IgnoreCase); - foreach (var str in _completeStrings) + foreach (var str in _completions) { if (wordToCompletePattern.IsMatch(str)) { diff --git a/src/System.Management.Automation/engine/parser/TypeResolver.cs b/src/System.Management.Automation/engine/parser/TypeResolver.cs index 0117d767e3f..006dbf084e5 100644 --- a/src/System.Management.Automation/engine/parser/TypeResolver.cs +++ b/src/System.Management.Automation/engine/parser/TypeResolver.cs @@ -736,6 +736,7 @@ internal static class CoreTypes { typeof(AllowEmptyStringAttribute), new[] { "AllowEmptyString" } }, { typeof(AllowNullAttribute), new[] { "AllowNull" } }, { typeof(ArgumentCompleterAttribute), new[] { "ArgumentCompleter" } }, + { typeof(ArgumentCompletionsAttribute), new[] { "ArgumentCompletions" } }, { typeof(Array), new[] { "array" } }, { typeof(bool), new[] { "bool" } }, { typeof(byte), new[] { "byte" } }, diff --git a/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 b/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 index 479e7b4cec9..51b1e3c51d6 100644 --- a/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 +++ b/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 @@ -368,7 +368,7 @@ Describe "Type accelerators" -Tags "CI" { if ( $IsCoreCLR ) { - $totalAccelerators = 89 + $totalAccelerators = 90 } else { From d414f9b2c2287664a079f83145aaebf6de0d442c Mon Sep 17 00:00:00 2001 From: iSazonov Date: Tue, 19 Sep 2017 06:08:48 +0300 Subject: [PATCH 08/13] Remove try and change type --- .../CommandCompletion/CompletionCompleters.cs | 18 ++++++------------ .../CommandCompletion/ExtensibleCompletion.cs | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 06964351af6..4ce76a9a88d 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -2006,19 +2006,13 @@ private static void NativeCommandArgumentCompletion( var argumentCompletionsAttribute = parameter.CompiledAttributes.OfType().FirstOrDefault(); if (argumentCompletionsAttribute != null) { - try - { - var customResults = argumentCompletionsAttribute.CompleteArgument(commandName, parameterName, - context.WordToComplete, commandAst, GetBoundArgumentsAsHashtable(context)); - if (customResults != null) - { - result.AddRange(customResults); - result.Add(CompletionResult.Null); - return; - } - } - catch (Exception) + var customResults = argumentCompletionsAttribute.CompleteArgument(commandName, parameterName, + context.WordToComplete, commandAst, GetBoundArgumentsAsHashtable(context)); + if (customResults != null) { + result.AddRange(customResults); + result.Add(CompletionResult.Null); + return; } } diff --git a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs index 7426ed8ea1b..2a0d2459b8e 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs @@ -205,7 +205,7 @@ public IEnumerable CompleteArgument(string commandName, string { if (wordToCompletePattern.IsMatch(str)) { - yield return new CompletionResult(str, str, CompletionResultType.Text, str); + yield return new CompletionResult(str, str, CompletionResultType.ParameterValue, str); } } } From 48e5ec5f11b678f7d2bc4c5fb1e1044c3b31c24b Mon Sep 17 00:00:00 2001 From: iSazonov Date: Tue, 19 Sep 2017 06:09:45 +0300 Subject: [PATCH 09/13] Revert "Add 'AllowAll' named parameter in ValidateSet attribute" This reverts commit 69363fd035807765b062f4ecff072d45bae6d3b1. --- .../engine/Attributes.cs | 13 ------------- .../engine/parser/Compiler.cs | 4 ---- 2 files changed, 17 deletions(-) diff --git a/src/System.Management.Automation/engine/Attributes.cs b/src/System.Management.Automation/engine/Attributes.cs index b46e3899874..730d945305c 100644 --- a/src/System.Management.Automation/engine/Attributes.cs +++ b/src/System.Management.Automation/engine/Attributes.cs @@ -1563,14 +1563,6 @@ public sealed class ValidateSetAttribute : ValidateEnumeratedArgumentsAttribute // The valid values generator cache works across 'ValidateSetAttribute' instances. private static ConcurrentDictionary s_ValidValuesGeneratorCache = new ConcurrentDictionary(); - /// - /// If AllowAll==true 'ValidateElement' always pass all elements. - /// Useful if we need enable IntelliSense (TabComplete) but effectively disable validation - /// when a parameter can accept not only the listed values but also arbitrary. - /// Ex.: Get-Date -Format - /// - public bool AllowAll { get; set; } = false; - /// /// Gets or sets the custom error message that is displayed to the user /// @@ -1633,11 +1625,6 @@ protected override void ValidateElement(object element) Metadata.ValidateNotNullFailure); } - if (AllowAll == true) - { - return; - } - string objString = element.ToString(); foreach (string setString in ValidValues) { diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index a4237cb1d26..62462ad53af 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -1336,10 +1336,6 @@ private static Attribute NewValidateSetAttribute(AttributeAst ast) { result.IgnoreCase = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue); } - else if (argumentName.Equals("AllowAll", StringComparison.OrdinalIgnoreCase)) - { - result.AllowAll = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue); - } else if (argumentName.Equals("ErrorMessage", StringComparison.OrdinalIgnoreCase)) { result.ErrorMessage = argValue.ToString(); From 87b26b47d1425f2a0c93d2371be320ee8febab73 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Tue, 19 Sep 2017 06:13:07 +0300 Subject: [PATCH 10/13] Fix typo in comment. --- .../engine/CommandCompletion/ExtensibleCompletion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs index 2a0d2459b8e..18dce545a42 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/ExtensibleCompletion.cs @@ -174,7 +174,7 @@ public class ArgumentCompletionsAttribute : Attribute private string[] _completions; /// - /// Initializes a new instance of the ArgumentCompleterAttribute class + /// Initializes a new instance of the ArgumentCompletionsAttribute class /// /// list of complete values /// for null arguments From 306fdc687b0d3ce9fc942973da108fece545f030 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Wed, 20 Sep 2017 18:22:55 +0300 Subject: [PATCH 11/13] Add tests --- .../Parser/ExtensibleCompletion.Tests.ps1 | 60 +++++++++++++++++++ .../Language/Parser/TypeAccelerator.Tests.ps1 | 4 ++ 2 files changed, 64 insertions(+) diff --git a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 index 7082f91f352..10bf8dbd732 100644 --- a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 +++ b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 @@ -355,3 +355,63 @@ Describe "Additional type name completion tests" -Tags "CI" { TestInput = 'Get-Command -ParameterType System.Collections.Generic.Dic' } | Get-CompletionTestCaseData | Test-Completions } + +Describe "ArgumentCompletionsAttribute tests" -Tags "CI" { + + BeforeAll { + function TestArgumentCompletionsAttribute + { + param( + [ArgumentCompletions("value1", "value2", "value3")] + $Alpha, + [ArgumentCompleter()] + $Beta + ) + } + + $cmdletSrc=@' + using System; + using System.Management.Automation; + using System.Collections.Generic; + + namespace Test.ArgumentCompletionsAttribute { + + [Cmdlet(VerbsCommon.Get, "ArgumentCompletions")] + public class TestArgumentCompletionsAttributeCommand0 : PSCmdlet + { + [Parameter] + [ArgumentCompletions("value1", "value2", "value3")] + public string Param1; + + protected override void EndProcessing() + { + WriteObject(Param1); + } + } + } +'@ + + $cls = Add-Type -TypeDefinition $cmdletSrc -PassThru | Select-Object -First 1 + $testModule = Import-Module $cls.Assembly -PassThru + } + + AfterAll { + Remove-Module -ModuleInfo $testModule + } + + It "ArgumentCompletionsAttribute works in script" { + $line = "TestArgumentCompletionsAttribute -Alpha val" + $res = TaBexpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches.Count | Should Be 3 + $res.CompletionMatches.CompletionText -join " " | Should Be "value1 value2 value3" + { TestArgumentCompletionsAttribute -Alpha unExpectedValue } | Should Not Throw + } + + It "ArgumentCompletionsAttribute works in c#" { + $line = "Get-ArgumentCompletions -Param1 val" + $res = TaBexpansion2 -inputScript $line -cursorColumn $line.Length + $res.CompletionMatches.Count | Should Be 3 + $res.CompletionMatches.CompletionText -join " " | Should Be "value1 value2 value3" + { TestArgumentCompletionsAttribute -Param1 unExpectedValue } | Should Not Throw + } +} diff --git a/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 b/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 index 51b1e3c51d6..152650135dd 100644 --- a/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 +++ b/test/powershell/Language/Parser/TypeAccelerator.Tests.ps1 @@ -28,6 +28,10 @@ Describe "Type accelerators" -Tags "CI" { Accelerator = 'ArgumentCompleter' Type = [System.Management.Automation.ArgumentCompleterAttribute] } + @{ + Accelerator = 'ArgumentCompletions' + Type = [System.Management.Automation.ArgumentCompletionsAttribute] + } @{ Accelerator = 'array' Type = [System.Array] From 1e6286e81fc538ef2cc01c487d634cf538d647a3 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 21 Sep 2017 08:18:25 +0300 Subject: [PATCH 12/13] Correct tests --- .../Parser/ExtensibleCompletion.Tests.ps1 | 54 +++++++++++++++---- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 index 10bf8dbd732..57e25f2ca05 100644 --- a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 +++ b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 @@ -364,7 +364,15 @@ Describe "ArgumentCompletionsAttribute tests" -Tags "CI" { param( [ArgumentCompletions("value1", "value2", "value3")] $Alpha, - [ArgumentCompleter()] + $Beta + ) + } + + function TestArgumentCompletionsAttribute1 + { + param( + [ArgumentCompletionsAttribute("value1", "value2", "value3")] + $Alpha, $Beta ) } @@ -374,10 +382,10 @@ Describe "ArgumentCompletionsAttribute tests" -Tags "CI" { using System.Management.Automation; using System.Collections.Generic; - namespace Test.ArgumentCompletionsAttribute { + namespace Test.A { [Cmdlet(VerbsCommon.Get, "ArgumentCompletions")] - public class TestArgumentCompletionsAttributeCommand0 : PSCmdlet + public class TestArgumentCompletionsAttributeCommand : PSCmdlet { [Parameter] [ArgumentCompletions("value1", "value2", "value3")] @@ -388,27 +396,53 @@ Describe "ArgumentCompletionsAttribute tests" -Tags "CI" { WriteObject(Param1); } } + + [Cmdlet(VerbsCommon.Get, "ArgumentCompletions1")] + public class TestArgumentCompletionsAttributeCommand1 : PSCmdlet + { + [Parameter] + [ArgumentCompletionsAttribute("value1", "value2", "value3")] + public string Param1; + + protected override void EndProcessing() + { + WriteObject(Param1); + } + } } '@ + $cls = Add-Type -TypeDefinition $cmdletSrc -PassThru | Select-Object -First 1 + $testModule = Import-Module $cls.Assembly -PassThru - $cls = Add-Type -TypeDefinition $cmdletSrc -PassThru | Select-Object -First 1 - $testModule = Import-Module $cls.Assembly -PassThru + $testCasesScript = @( + @{ attributeName = "ArgumentCompletions" ; cmdletName = "TestArgumentCompletionsAttribute" }, + @{ attributeName = "ArgumentCompletionsAttribute"; cmdletName = "TestArgumentCompletionsAttribute1" } + ) + + $testCasesCSharp = @( + @{ attributeName = "ArgumentCompletions" ; cmdletName = "Get-ArgumentCompletions" }, + @{ attributeName = "ArgumentCompletionsAttribute"; cmdletName = "Get-ArgumentCompletions1" } + ) } AfterAll { - Remove-Module -ModuleInfo $testModule + #Remove-Module -ModuleInfo $testModule } - It "ArgumentCompletionsAttribute works in script" { - $line = "TestArgumentCompletionsAttribute -Alpha val" + It " works in script" -TestCases $testCasesScript { + param($attributeName, $cmdletName) + + $line = "$cmdletName -Alpha val" $res = TaBexpansion2 -inputScript $line -cursorColumn $line.Length $res.CompletionMatches.Count | Should Be 3 $res.CompletionMatches.CompletionText -join " " | Should Be "value1 value2 value3" { TestArgumentCompletionsAttribute -Alpha unExpectedValue } | Should Not Throw } - It "ArgumentCompletionsAttribute works in c#" { - $line = "Get-ArgumentCompletions -Param1 val" + It " works in C#" -TestCases $testCasesCSharp { + param($attributeName, $cmdletName) + + $line = "$cmdletName -Param1 val" $res = TaBexpansion2 -inputScript $line -cursorColumn $line.Length $res.CompletionMatches.Count | Should Be 3 $res.CompletionMatches.CompletionText -join " " | Should Be "value1 value2 value3" From b69678cee586ddf94f70deab689a08263e4b5455 Mon Sep 17 00:00:00 2001 From: iSazonov Date: Thu, 21 Sep 2017 09:33:32 +0300 Subject: [PATCH 13/13] Uncomment Remove-Module --- test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 index 57e25f2ca05..61fc32b5201 100644 --- a/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 +++ b/test/powershell/Language/Parser/ExtensibleCompletion.Tests.ps1 @@ -426,7 +426,7 @@ Describe "ArgumentCompletionsAttribute tests" -Tags "CI" { } AfterAll { - #Remove-Module -ModuleInfo $testModule + Remove-Module -ModuleInfo $testModule } It " works in script" -TestCases $testCasesScript {