Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for Register-ArgumentCompleter to -HasArgumentCompleter #1979

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 74 additions & 1 deletion src/functions/assertions/HaveParameter.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,75 @@
}
}

function Get-ArgumentCompleter {
<#
.SYNOPSIS
Get custom argument completers registered in the current session.
.DESCRIPTION
Get custom argument completers registered in the current session.

By default Get-ArgumentCompleter lists all of the completers registered in the session.
.EXAMPLE
Get-ArgumentCompleter

Get all of the argument completers for PowerShell commands in the current session.
.EXAMPLE
Get-ArgumentCompleter -CommandName Invoke-ScriptAnalyzer

Get all of the argument completers used by the Invoke-ScriptAnalyzer command.
.EXAMPLE
Get-ArgumentCompleter -Native

Get all of the argument completers for native commands in the current session.
.NOTES
Author: Chris Dent
#>

[CmdletBinding()]
param (
# Filter results by command name.
[Parameter(Mandatory = $true)]
[String]$CommandName,

# Filter results by parameter name.
[Parameter(Mandatory = $true)]
[String]$ParameterName
)

$getExecutionContextFromTLS = [PowerShell].Assembly.GetType('System.Management.Automation.Runspaces.LocalPipeline').GetMethod(
'GetExecutionContextFromTLS',
[System.Reflection.BindingFlags]'Static, NonPublic'
)
$internalExecutionContext = $getExecutionContextFromTLS.Invoke(
$null,
[System.Reflection.BindingFlags]'Static, NonPublic',
$null,
$null,
$PSCulture
)

$argumentCompletersProperty = $internalExecutionContext.GetType().GetProperty(
'CustomArgumentCompleters',
[System.Reflection.BindingFlags]'NonPublic, Instance'
)
$argumentCompleters = $argumentCompletersProperty.GetGetMethod($true).Invoke(
$internalExecutionContext,
[System.Reflection.BindingFlags]'Instance, NonPublic, GetProperty',
$null,
@(),
$PSCulture
)

$completerName = '{0}:{1}' -f $CommandName, $ParameterName
if ($argumentCompleters.ContainsKey($completerName)) {
[PSCustomObject]@{
CommandName = $CommandName
ParameterName = $ParameterName
Definition = $argumentCompleters[$completerName]
}
}
}

if ($Type -is [string]) {
# parses type that is provided as a string in brackets (such as [int])
$parsedType = ($Type -replace '^\[(.*)\]$', '$1') -as [Type]
Expand Down Expand Up @@ -155,7 +224,7 @@
# PS5> [datetime]
[type]$actualType = $ActualValue.Parameters[$ParameterName].ParameterType
$testType = ($Type -eq $actualType)
$filters += "$(if ($Negate) {"not "})of type [$($Type.FullName)]"
$filters += "$(if ($Negate) { "not " })of type [$($Type.FullName)]"

if (-not $Negate -and -not $testType) {
$buts += "it was of type [$($actualType.FullName)]"
Expand All @@ -181,6 +250,10 @@

if ($HasArgumentCompleter) {
$testArgumentCompleter = $attributes | & $SafeCommands['Where-Object'] { $_ -is [ArgumentCompleter] }

if (-not $testArgumentCompleter) {
$testArgumentCompleter = Get-ArgumentCompleter -CommandName $ActualValue.Name -ParameterName $ParameterName
}
$filters += "has ArgumentCompletion"

if (-not $Negate -and -not $testArgumentCompleter) {
Expand Down
49 changes: 43 additions & 6 deletions tst/functions/assertions/HaveParameter.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,20 @@ InPesterModuleScope {
ForEach-Object { [System.Management.Automation.CompletionResult]::new( $_.Name, $_.Name, [System.Management.Automation.CompletionResultType]::ParameterValue, $_.Name ) }
}
)]
[String]$ParamWithArgumentCompleter = "./.git"
[String]$ParamWithArgumentCompleter = "./.git",

[Parameter()]
[String]$ParamWithRegisteredArgumentCompleter = "./.git"
)
}

Register-ArgumentCompleter -CommandName Invoke-DummyFunction -ParameterName ParamWithRegisteredArgumentCompleter -ScriptBlock {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

& Get-ChildItem |
Where-Object { $_.Name -like "$wordToComplete*" } |
ForEach-Object { [System.Management.Automation.CompletionResult]::new( $_.Name, $_.Name, [System.Management.Automation.CompletionResultType]::ParameterValue, $_.Name ) }
}
}
else {
function Invoke-DummyFunction {
Expand Down Expand Up @@ -98,6 +109,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }
}
) {
param($ParameterName)
Expand All @@ -117,6 +129,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = "String" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "String" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "String" }
}
) {
param($ParameterName, $ExpectedType)
Expand All @@ -126,6 +139,7 @@ InPesterModuleScope {
if ($PSVersionTable.PSVersion.Major -ge 5) {
It "passes if the parameter <ParameterName> has an ArgumentCompleter" -TestCases @(
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }
) {
param($ParameterName)
Get-Command "Invoke-DummyFunction" | Should -HaveParameter $ParameterName -HasArgumentCompleter
Expand All @@ -138,6 +152,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedValue = "." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedValue = "./.git" }
}
) {
param($ParameterName, $ExpectedValue)
Expand All @@ -149,6 +164,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [String]; ExpectedValue = "." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "String"; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "String"; ExpectedValue = "./.git" }
}
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
Expand All @@ -162,6 +178,7 @@ InPesterModuleScope {
if ($PSVersionTable.PSVersion.Major -ge 5) {
It "passes if the parameter <ParameterName> exists, is of type <ExpectedType>, has a default value '<ExpectedValue>' and has an ArgumentCompleter" -TestCases @(
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "./.git" }
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
Get-Command "Invoke-DummyFunction" | Should -HaveParameter $ParameterName -Type $ExpectedType -DefaultValue $ExpectedValue -HasArgumentCompleter
Expand All @@ -186,6 +203,8 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }

}
@{ParameterName = "InputObject" }
) {
Expand All @@ -199,6 +218,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [DateTime] }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "DateTime" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "DateTime" }
}
@{ParameterName = "InputObject"; ExpectedType = [String] }
) {
Expand All @@ -224,6 +244,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedValue = "" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedValue = "." }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedValue = "." }
}
@{ParameterName = "InputObject"; ExpectedValue = "" }
) {
Expand All @@ -237,6 +258,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [DateTime]; ExpectedValue = "." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "String"; ExpectedValue = "" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "" }
}
@{ParameterName = "InputObject"; ExpectedType = [String]; ExpectedValue = "" }
) {
Expand All @@ -254,6 +276,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithNotNullOrEmptyValidation"; ExpectedType = [DateTime]; ExpectedValue = "." }
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [String]; ExpectedValue = "." }
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "." }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "." }
@{ParameterName = "InputObject"; ExpectedType = [String]; ExpectedValue = "." }
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
Expand Down Expand Up @@ -284,7 +307,7 @@ InPesterModuleScope {
}
}

Describe "Should -Not -HavePameter" {
Describe "Should -Not -HaveParameter" {
BeforeAll {
. $functionsBlock
}
Expand All @@ -302,6 +325,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }
}
@{ParameterName = "InputObject" }
) {
Expand All @@ -314,6 +338,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = "[TimeSpan]" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [TimeSpan] }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [Timespan] }
}
@{ParameterName = "InputObject"; ExpectedType = "[Object]" }
) {
Expand All @@ -327,6 +352,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = "[Int32]"; ExpectedValue = ".." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [TimeSpan]; ExpectedValue = "." }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [TimeSpan]; ExpectedValue = "." }
}
@{ParameterName = "InputObject"; ExpectedType = "[Object]"; ExpectedValue = "" }
) {
Expand All @@ -352,6 +378,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation" }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }
}
) {
param($ParameterName)
Expand All @@ -371,6 +398,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [String] }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "String" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "String" }
}
) {
param($ParameterName, $ExpectedType)
Expand All @@ -383,6 +411,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = "[String]"; ExpectedValue = ".." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "." }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "." }
}
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
Expand All @@ -392,6 +421,7 @@ InPesterModuleScope {
if ($PSVersionTable.PSVersion.Major -ge 5) {
It "fails if the parameter <ParameterName> has an ArgumentCompleter" -TestCases @(
@{ParameterName = "ParamWithArgumentCompleter" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter" }
) {
param($ParameterName)
{ Get-Command "Invoke-DummyFunction" | Should -Not -HaveParameter $ParameterName -HasArgumentCompleter } | Verify-AssertionFailed
Expand All @@ -404,6 +434,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedValue = "." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedValue = "./.git" }
}
) {
param($ParameterName, $ExpectedValue)
Expand All @@ -416,6 +447,7 @@ InPesterModuleScope {
@{ParameterName = "ParamWithScriptValidation"; ExpectedType = [String]; ExpectedValue = "." }
if ($PSVersionTable.PSVersion.Major -ge 5) {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "String"; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "String"; ExpectedValue = "." }
}
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
Expand All @@ -427,7 +459,9 @@ InPesterModuleScope {
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [DateTime]; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = [DateTime]; ExpectedValue = "" }

@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [String]; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [DateTime]; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = [DateTime]; ExpectedValue = "" }
) {
param($ParameterName, $ExpectedType, $ExpectedValue)
{ Get-Command "Invoke-DummyFunction" | Should -Not -HaveParameter $ParameterName -Type $ExpectedType -DefaultValue $ExpectedValue -HasArgumentCompleter } | Verify-AssertionFailed
Expand All @@ -445,9 +479,12 @@ InPesterModuleScope {
}

if ($PSVersionTable.PSVersion.Major -ge 5) {
It "returns the correct assertion message when parameter ParamWithNotNullOrEmptyValidation is not mandatory, of the wrong type, has a different default value than expected and has no ArgumentCompleter" {
$err = { Get-Command "Invoke-DummyFunction" | Should -Not -HaveParameter ParamWithArgumentCompleter -Type [String] -DefaultValue "./.git" -HasArgumentCompleter -Because 'of reasons' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected command Invoke-DummyFunction to not have a parameter ParamWithArgumentCompleter, not of type [System.String], the default value not to be './.git' and has ArgumentCompletion, because of reasons, but it was of type [System.String], the default value was './.git' and has ArgumentCompletion."
It "returns the correct assertion message when parameter ParamWithNotNullOrEmptyValidation is not mandatory, of the wrong type, has a different default value than expected and has no ArgumentCompleter" -TestCases @(
@{ParameterName = "ParamWithArgumentCompleter"; ExpectedType = "System.String"; ExpectedValue = "./.git" }
@{ParameterName = "ParamWithRegisteredArgumentCompleter"; ExpectedType = "System.String"; ExpectedValue = "./.git" }
) {
$err = { Get-Command "Invoke-DummyFunction" | Should -Not -HaveParameter $ParameterName -Type $ExpectedType -DefaultValue $ExpectedValue -HasArgumentCompleter -Because 'of reasons' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected command Invoke-DummyFunction to not have a parameter $ParameterName, not of type [$ExpectedType], the default value not to be '$ExpectedValue' and has ArgumentCompletion, because of reasons, but it was of type [$ExpectedType], the default value was '$ExpectedValue' and has ArgumentCompletion."
}
}
}
Expand Down