From cb2b3e3430827a6c5bcdb71e7bbbad4e851c76a7 Mon Sep 17 00:00:00 2001 From: Benjamin Fuchs Date: Fri, 20 Dec 2024 10:55:35 +0100 Subject: [PATCH] Fix handling of conflicting dynamic parameters --- src/functions/Mock.ps1 | 41 +++++++++++++++++++-- tst/functions/Mock.Tests.ps1 | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/src/functions/Mock.ps1 b/src/functions/Mock.ps1 index 7f299b532..5f6f48973 100644 --- a/src/functions/Mock.ps1 +++ b/src/functions/Mock.ps1 @@ -1457,13 +1457,50 @@ function Get-MockDynamicParameter { switch ($PSCmdlet.ParameterSetName) { 'Cmdlet' { - Get-DynamicParametersForCmdlet -CmdletName $CmdletName -Parameters $Parameters + $dynamicParams = Get-DynamicParametersForCmdlet -CmdletName $CmdletName -Parameters $Parameters } 'Function' { - Get-DynamicParametersForMockedFunction -DynamicParamScriptBlock $DynamicParamScriptBlock -Parameters $Parameters -Cmdlet $Cmdlet + $dynamicParams = Get-DynamicParametersForMockedFunction -DynamicParamScriptBlock $DynamicParamScriptBlock -Parameters $Parameters -Cmdlet $Cmdlet } } + + if ($null -eq $dynamicParams) { + return + } + + Repair-ConflictingDynamicParameters -DynamicParams $dynamicParams +} + +function Repair-ConflictingDynamicParameters { + [OutputType([System.Management.Automation.RuntimeDefinedParameterDictionary])] + param ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.RuntimeDefinedParameterDictionary] + $DynamicParams + ) + + $repairedDynamicParams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary + $conflictingParams = Get-ConflictingParameterNames + + foreach ($paramName in $DynamicParams.Keys) { + $dynamicParam = $DynamicParams[$paramName] + + if ($conflictingParams -contains $paramName) { + $newName = "_$paramName" + $dynamicParam.Name = $newName + + $aliasAttribute = New-Object System.Management.Automation.AliasAttribute -ArgumentList $paramName + $dynamicParam.Attributes.Add($aliasAttribute) + + $repairedDynamicParams[$newName] = $dynamicParam + } + else { + $repairedDynamicParams[$paramName] = $dynamicParam + } + } + + return $repairedDynamicParams } function Get-DynamicParametersForCmdlet { diff --git a/tst/functions/Mock.Tests.ps1 b/tst/functions/Mock.Tests.ps1 index b3853dca6..c19f58be7 100644 --- a/tst/functions/Mock.Tests.ps1 +++ b/tst/functions/Mock.Tests.ps1 @@ -3160,3 +3160,72 @@ Describe 'Mocking with nested Pester runs' { Get-Command Get-ChildItem | Should -Not -Be 2 } } + +Describe 'Usage of Alias in DynamicParams' { + # https://github.com/pester/Pester/issues/1274 + + BeforeAll { + function New-DynamicAttr($ParamDictionary, $Name, $Alias = $null) { + $attr = New-Object -Type ` + System.Management.Automation.ParameterAttribute + $attr.Mandatory = $false + $attr.ParameterSetName = '__AllParameterSets' + $attributeCollection = New-Object ` + -Type System.Collections.ObjectModel.Collection[System.Attribute] + $attributeCollection.Add($attr) + + if ($null -ne $Alias) { + $attr = New-Object -Type ` + System.Management.Automation.AliasAttribute -ArgumentList @($Alias) + $attributeCollection.Add($attr) + } + + $dynParam1 = New-Object -Type ` + System.Management.Automation.RuntimeDefinedParameter($Name, [string], + $attributeCollection) + + $ParamDictionary.Add($Name, $dynParam1) + } + + function Test-DynamicParam { + [CmdletBinding()] + param( + [String]$Name + ) + + dynamicparam { + if ($Name.StartsWith("Hello")) { + $paramDictionary = New-Object ` + -Type System.Management.Automation.RuntimeDefinedParameterDictionary + New-DynamicAttr -ParamDictionary $paramDictionary -Name "PSEdition" + + return $paramDictionary + } + } + + process { + if ($PSBoundParameters.PSEdition) { + Write-Host "PSEdition value: $($PSBoundParameters.PSEdition)" + } + } + } + } + + Context 'Mocking with ParameterFilter' { + It 'Mocks Test-DynamicParam with PSEdition set to Desktop' { + Mock Test-DynamicParam { "World" } -ParameterFilter { $PSEdition -eq 'Desktop' } + + Test-DynamicParam -Name "Hello" -PSEdition 'Desktop' | Should -Be 'World' + } + } + + Context 'Validating Mock Invocation' { + It 'Invokes Test-DynamicParam with correct parameters' { + Mock Test-DynamicParam { "World" } + + Test-DynamicParam -Name "Hello" -PSEdition 'Desktop' | Should -Be 'World' + + Should -Invoke Test-DynamicParam -Exactly 1 -Scope It + } + } +}