Skip to content

Commit

Permalink
Fix handling of conflicting dynamic parameters (#2592)
Browse files Browse the repository at this point in the history
* Fix handling of conflicting dynamic parameters

* Apply suggestions from code review

---------

Co-authored-by: Jakub Jareš <[email protected]>
  • Loading branch information
benjaminfuchs and nohwnd authored Jan 16, 2025
1 parent 648f71c commit f49f842
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 13 deletions.
62 changes: 49 additions & 13 deletions src/functions/Mock.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1339,21 +1339,20 @@ function Get-ContextToDefine {
}
else {
# the parameter is not defined in the parameter set,
# it is probably dynamic, let's see if I can get away with just adding
# it to the list of stuff to define
# it is probably dynamic, try remove "_" since the conflicting names
# are already handled to properly print the debug message

$name = if ($param.Key -in $script:ConflictingParameterNames) {
if ($PesterPreference.Debug.WriteDebugMessages.Value) {
Write-PesterDebugMessage -Scope Mock -Message "! Variable `$$($param.Key) is a built-in variable, rewriting it to `$_$($param.Key). Use the version with _ in your -ParameterFilter."
if ($param.Key.StartsWith('_')) {
$originalName = $param.Key.TrimStart('_')
if ($originalName -in $script:ConflictingParameterNames) {
if ($PesterPreference.Debug.WriteDebugMessages.Value) {
Write-PesterDebugMessage -Scope Mock -Message "! Variable `$$($originalName) is a built-in variable, rewriting it to `$_$($originalName). Use the version with _ in your -ParameterFilter."
}
}
"_$($param.Key)"
}
else {
$param.Key
}

if (-not $r.ContainsKey($name)) {
$r.Add($name, $param.Value)
if (-not $r.ContainsKey($param.Key)) {
$r.Add($param.Key, $param.Value)
}
}
}
Expand Down Expand Up @@ -1457,13 +1456,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 = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$conflictingParams = Get-ConflictingParameterNames

foreach ($paramName in $DynamicParams.Keys) {
$dynamicParam = $DynamicParams[$paramName]

if ($conflictingParams -contains $paramName) {
$newName = "_$paramName"
$dynamicParam.Name = $newName

$aliasAttribute = [System.Management.Automation.AliasAttribute]::new($paramName)
$dynamicParam.Attributes.Add($aliasAttribute)

$repairedDynamicParams[$newName] = $dynamicParam
}
else {
$repairedDynamicParams[$paramName] = $dynamicParam
}
}

return $repairedDynamicParams
}

function Get-DynamicParametersForCmdlet {
Expand Down
63 changes: 63 additions & 0 deletions tst/functions/Mock.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3160,3 +3160,66 @@ 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
}
}
}

0 comments on commit f49f842

Please sign in to comment.