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

Mocking a function with OrderedDictionary parameter throws error with PowerShell 7, runs fine with PowerShell 5 #2370

Open
3 tasks done
MartinusVastenhouw opened this issue Jun 20, 2023 · 1 comment

Comments

@MartinusVastenhouw
Copy link

Checklist

What is the issue?

Mocking a function that has a parameter of type [System.Collections.Specialized.OrderedDictionary] throws an error when using PowerShell 7 (version 7.3.4) but runs fine when using PowerShell 5.
See test script in attached file (hehe.txt).
hehe.txt

Expected Behavior

Pester should not throw an error. If it works in PowerShell 5 it should also work in PowerShell 7.

Steps To Reproduce

Running below tests in PowerShell 7 throws an error. They run fine with PowerShell 5.

Describe 'Difference between PowerShell 7 and PowerShell 5' {
    BeforeAll {
        function Test-WithOrderedDictionary {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [System.Collections.Specialized.OrderedDictionary]
                $Context
            )

            Write-Information -MessageData "INFO -- Test-WithOrderedDictionary: $($Context.Message)" -InformationAction Continue
        }

        function Use-TestWithOrderedDictionary {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [string]
                $Message
            )

            Write-Information -MessageData "INFO -- Use-TestWithOrderedDictionary: $Message" -InformationAction Continue

            $testContext = [ordered]@{
                Message = $Message
            }

            Test-WithOrderedDictionary -Context $testContext
        }

        function Test-WithHashTable {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [hashtable]
                $Context
            )

            Write-Information -MessageData "INFO -- Test-WithHashTable: $($Context.Message)" -InformationAction Continue
        }

        function Use-TestWithHashTable {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [string]
                $Message
            )

            Write-Information -MessageData "INFO -- Use-TestWithHashTable: $Message" -InformationAction Continue

            $testContext = @{
                Message = $Message
            }

            Test-WithHashTable -Context $testContext
        }
    }

    Context 'Test-WithOrderedDictionary' {
        It 'With mock throws error with PowerShell 7, but works with PowerShell 5' {

            Mock -CommandName 'Test-WithOrderedDictionary'

            Use-TestWithOrderedDictionary -Message 'With mock throws error with PowerShell 7, but works with PowerShell 5'
        }

        It 'Without mock runs fine with PowerShell 7 and PowerShell 5' {

            Use-TestWithOrderedDictionary -Message 'Without mock runs fine with PowerShell 7 and PowerShell 5'
        }
    }

    Context 'Test-WithHashTable' {
        It 'With mock runs fine with PowerShell 7 and PowerShell 5' {

            Mock -CommandName 'Test-WithHashTable'

            Use-TestWithHashTable -Message 'With mock runs fine with PowerShell 7 and PowerShell 5'
        }

        It 'Without mock runs fine with PowerShell 7 and PowerShell 5' {

            Use-TestWithHashTable -Message 'Without mock runs fine with PowerShell 7 and PowerShell 5'
        }
    }
}

Describe your environment

Pester version : 5.4.1 C:\Program Files\PowerShell\Modules\Pester\5.4.1\Pester.psm1
PowerShell version : 7.3.4
OS version : Microsoft Windows NT 10.0.19044.0

Possible Solution?

It's not a solution but as a workaround one can use a hashtable instead of an ordered dictionary.

@fflaten
Copy link
Collaborator

fflaten commented Jun 20, 2023

Hi. Thanks for the report. This is caused by a bug in PowerShell itself.

# Define the function
function Test-WithOrderedDictionary {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.Collections.Specialized.OrderedDictionary]
        $Context
    )

    Write-Information -MessageData "INFO -- Test-WithOrderedDictionary: $($Context.Message)" -InformationAction Continue
}

# Generate proxycommand paramblock in Windows PowerShell 5.1
> [System.Management.Automation.ProxyCommand]::GetParamBlock((Get-Command Test-WithOrderedDictionary))

    [Parameter(Mandatory=$true, Position=0)]
    [System.Collections.Specialized.OrderedDictionary]
    ${Context}

# Generate proxycommand paramblock in PowerShell 7.3
> [System.Management.Automation.ProxyCommand]::GetParamBlock((Get-Command Test-WithOrderedDictionary))

    [Parameter(Mandatory=$true, Position=0)]
    [ordered]
    ${Context}

Unfortunately I'm actually the one who introduced this bug in PS 7.3 by making [ordered] a proper type accelerator in PowerShell/PowerShell#17804. It seems the proxy command generator prefers the accelerator now, but that will fail as [ordered] has a special guard to block it from being used like this. That's something the working group decided to keep as-is, though not with this scenario in mind, see PowerShell/PowerShell#10513 (comment).

I'll submit an issue in the PowerShell-repo so we hopefully can fix this in a future PowerShell-release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants