pester / Pester

Pester is the ubiquitous test and mock framework for PowerShell.
https://pester.dev/
Other
3.11k stars 473 forks source link

Mock fails to process dynamic parameter called PSEdition #1274

Open renehernandez opened 5 years ago

renehernandez commented 5 years ago

1. General summary of the issue

PSEdition, which is a conflicting parameter name, is not being properly handled while mocking if it is used for a dynamic parameter

The following function and test highlight the issue:

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)"
        }
    }
}

Describe 'Usage of Alias in DynamicParams' {
    Context 'Usage of ParameterFilters in Mock' {

        It 'using conflicting PSEdition parameter name' {
            Mock Test-DynamicParam { "World" } -ParameterFilter {$PSEdition -eq 'Desktop'}

            Test-DynamicParam -Name "Hello" -PSEdition 'Desktop' | Should -Be 'World'
        }
    }

     Context 'Usage of ParameterFilters in Assert-MockCalled' {
        It 'using conflicting PSEdition parameter name' {
            Mock Test-DynamicParam { "World" }

            Test-DynamicParam -Name "Hello" -PSEdition 'Desktop' | Should -Be 'World'

            Assert-MockCalled Test-DynamicParam -ParameterFilter {$PSEdition -eq 'Desktop'}
        }
    }
}

2. Describe Your Environment

Pester version     : 4.7.3 C:\Program Files\PowerShell\Modules\Pester\4.7.3\Pester.psd1
PowerShell version : 6.1.3
OS version         : Microsoft Windows NT 10.0.17134.0

3. Expected Behavior

It should pass

4.Current Behavior

It fails

5. Possible Solution

Add corresponding implementation for dynamic parameter for what was done for regular parameters

6. Context

This is related to #1007 and #1128

renehernandez commented 5 years ago

@nohwnd Can you add this issue to the Better Mock milestone?

fflaten commented 2 years ago

Still an issue in 5.3.3 and conflict still allowed in PowerShell 7.

Note to implementer: Current behavior for static parameters is in Repair-ConflictingParameters.

Need to repeat this, converting conflictingParam to _conflictingParam with original name as alias, in Get-DynamicParamBlock (with AST-parsing) and Get-DynamicParametersForCmdlet.

nohwnd commented 2 years ago

Even though the description above seems scary, most of the work has been done before for other parameters, and in the functions named above you'd find an almost complete implementation, it just needs to be extended for PSEdition.