Pester icon indicating copy to clipboard operation
Pester copied to clipboard

Pester throws if a test calls New-HashSet from ListFunctions package

Open scottbilas opened this issue 3 years ago • 9 comments

General summary of the issue

Pester fails with a quite deep call stack if I have a test that uses New-HashSet from the ListFunctions package (Gallery; GitHub).

Describe your environment

Pester version : 5.3.1 C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1 PowerShell version : 7.1.3 OS version : Microsoft Windows NT 10.0.22000.0

(I also tried on the posh classic, same issue)

Pester version : 5.3.1 C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1 PowerShell version : 5.1.22000.282 OS version : Microsoft Windows NT 10.0.22000.0

Steps to reproduce

  1. Install-Module ListFunctions (requires PSGallery as a PSRepository)
  2. Copy this script into test.ps1
#Requires -Modules ListFunctions
Describe 'Demo' {
    It 'Shows the issue' { New-HashSet }
}
  1. Invoke-Pester test.ps1

Expected Behavior

Should not throw an exception. (If I run New-HashSet on its own, there's no problem.)

The code to New-HashSet is at New-HashSet.ps1. Nothing in there seems particularly weird to me, but it is apparently confusing Pester.

Current Behavior

I get a call stack like this:

 invoke-pester C:\temp\test.ps1

Starting discovery in 1 files.
Discovery found 1 tests in 1.14s.
Running tests.
System.Management.Automation.ParameterBindingArgumentTransformationException: Cannot process argument transformation on parameter 'Condition'. Cannot convert the "System.Collections.Generic.List`1[Pester.Block]" value of type "System.Collections.Generic.List`1[[Pester.Block, Pester, Version=5.3.1.0, Culture=neutral, PublicKeyToken=null]]" to type "System.Management.Automation.ScriptBlock".
 ---> System.Management.Automation.ArgumentTransformationMetadataException: Cannot convert the "System.Collections.Generic.List`1[Pester.Block]" value of type "System.Collections.Generic.List`1[[Pester.Block, Pester, Version=5.3.1.0, Culture=neutral, PublicKeyToken=null]]" to type "System.Management.Automation.ScriptBlock".
 ---> System.Management.Automation.PSInvalidCastException: Cannot convert the "System.Collections.Generic.List`1[Pester.Block]" value of type "System.Collections.Generic.List`1[[Pester.Block, Pester, Version=5.3.1.0, Culture=neutral, PublicKeyToken=null]]" to type "System.Management.Automation.ScriptBlock".
   at System.Management.Automation.LanguagePrimitives.ThrowInvalidCastException(Object valueToConvert, Type resultType)
   at System.Management.Automation.LanguagePrimitives.ConvertNoConversion(Object valueToConvert, Type resultType, Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   at System.Management.Automation.LanguagePrimitives.ConversionData`1.Invoke(Object valueToConvert, Type resultType, Boolean recurse, PSObject originalValueToConvert, IFormatProvider formatProvider, TypeTable backupTable)
   at System.Management.Automation.LanguagePrimitives.ConvertTo(Object valueToConvert, Type resultType, Boolean recursion, IFormatProvider formatProvider, TypeTable backupTypeTable)                                                                                                at System.Management.Automation.ArgumentTypeConverterAttribute.Transform(EngineIntrinsics engineIntrinsics, Object inputData, Boolean bindingParameters, Boolean bindingScriptCmdlet)                                                                                             --- End of inner exception stack trace ---
   at System.Management.Automation.ArgumentTypeConverterAttribute.Transform(EngineIntrinsics engineIntrinsics, Object inputData, Boolean bindingParameters, Boolean bindingScriptCmdlet)
   at System.Management.Automation.ParameterBinderBase.BindParameter(CommandParameterInternal parameter, CompiledCommandParameter parameterMetadata, ParameterBindingFlags flags)
   --- End of inner exception stack trace ---
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
   at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnderbar, Object inputToProcess)
   at System.Management.Automation.PSScriptCmdlet.DoProcessRecord()
   at System.Management.Automation.CommandProcessor.ProcessRecord()
at none, C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1: line 234
at PostProcess-ExecutedBlock<Process>, C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1: line 2713
at Run-Test, C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1: line 1671
at Invoke-Test, C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1: line 2465
at Invoke-Pester<End>, C:\Users\scott\Documents\PowerShell\Modules\Pester\5.3.1\Pester.psm1: line 5225
at <ScriptBlock>, <No file>: line 1

scottbilas avatar Nov 28 '21 20:11 scottbilas

I don't remember writing that function, but it sounds like function name conflict maybe.

nohwnd avatar Apr 22 '22 20:04 nohwnd

This is caused by an alias in the module that hijacks an internal Pester-function.

image

Try importing the module without aliases (or specify the once you need except 'any' with -Alias 'name','of','aliases')

BeforeAll {
    Import-Module ListFunctions -Function *
}

Describe 'Demo' {
    It 'Shows the issue' {
        New-HashSet
    }
}

fflaten avatar May 08 '22 15:05 fflaten

Time to rename all non-public functions to Verb-PesterNoun and make our so much more non-standard again?

nohwnd avatar May 10 '22 13:05 nohwnd

Or register them in SafeCommands?

fflaten avatar May 10 '22 14:05 fflaten

Yeah that is an option too.

nohwnd avatar May 10 '22 15:05 nohwnd

Yeah that is an option too.

Any preference?

We could probably limit it to some or all of these single word functions at first. Less risk of someone adding aliases for conflicting verb-noun.

function any ($InputObject) {  # Mandatory
function combineNonNull ($Array) {
function defined {  # Mandatory
function none ($InputObject) {  # Mandatory
function notDefined {  # Mandatory
function or {  # Mandatory
function sum ($InputObject, $PropertyName, $Zero) {  # Mandatory
function tryAddValue {
function tryGetProperty {
function tryGetValue {
function tryRemoveKey ($Hashtable, $Key) {
function trySetProperty {

fflaten avatar May 30 '22 17:05 fflaten

Updating all of those functions with a call via safeCommands will make the complicated code look even more complex. How about a naming convention instead? We could just suffix the name with underscore or underscore and some other char like any_-? Intellisense keeps working and we have very small likelyhood of conflicts.

nohwnd avatar Jun 30 '22 07:06 nohwnd

I agree. Suffix or "pesterAny" etc sounds good. We real only need to fix the ones above to if you want. Don't think Fold-Block etc will be stolen by an alias, but.. you never know 😁

fflaten avatar Jun 30 '22 11:06 fflaten

Ok let me suffix them with "_"

nohwnd avatar Jun 30 '22 15:06 nohwnd