Should does NOT assert correctly for certain calls when calling it in different ways
TofuBug opened this issue · comments
Checklist
- Issue has a meaningful title
- I have searched the existing issues. See all issues
- I have tested using the latest version of Pester. See Installation and update guide.
What is the issue?
Preface
PowerShell has the ability to preload Cmdlet parameters in Hashtables used to Splat the eventual Cmdlet Call
Pester is made up of Cmdlet so this tenant should hold true
So for instance
'10 | Should -Be 10
Could be splatted like
$Should =
@{
ActualValue =
10
ExpectedValue =
10
Be =
$true
}
Should @Should
And this example works just fine
However something like in the steps to reproduce does not
Expected Behavior
Yes Splatting might not be the traditional way to call Pester but a lot of places have coding style guides that heavily prioritize splatting and Pester's style flies in the face of that
I'm not here to argue the merrits of one coding style over another simply that
Regardless of the means to call the Cmdlet the result should be the same
The fact the error states it expected X and got X is a bit humorous to me
Steps To Reproduce
$Should =
@{
ActualValue =
@(1,2,3)
ExpectedValue =
@(1,2,3)
Be =
$true
}
Works with
$Should.ActualValue | Should -Be $Should.ExpectedValue
but NOT
Should -ActualValue $Should.ActualValue -Be -ExpectedValue $Should.ExpectedValue
or
Should @should
The last two both happily report
Expected @(1, 2, 3), but got @(1, 2, 3).
At C:\Program Files (x86)\WindowsPowerShell\Modules\Pester\5.4.0\Pester.psm1:8130 char:13
+ throw $errorRecord
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidResult: (System.Collecti...,System.Object]:Dictionary`2) [], Exceptio
n
+ FullyQualifiedErrorId : PesterAssertionFailed
Describe your environment
Windows 10.
Windows PowerShell, and PowerShell
Possible Solution?
For the above example with any complicated object the solution is to have a Compare-Object call as the ActualValue and BeNullOrEmpty as the assertion so
$CompareObject =
@{
ReferenceObject =
@(1,2,3)
DifferenceObject =
@(1,2,3)
}
$Should =
@{
ActualValue =
Compare-Object @CompareObject
BeNullOrEmpty =
$true
}
Should @Should
Will work and you can add Property to the hashtable for complicated object comparisions
Hi. Thanks for the report! This really boils down to:
It 'works' {
@(1,2,3) | Should -Be -ExpectedValue @(1,2,3)
}
It 'fails' {
Should -ActualValue @(1,2,3) -Be -ExpectedValue @(1,2,3)
}
The issue is that when using the pipeline, PowerShell unrolls the array. To enable array-comparisons we overcome this by adding $ActualValue
to a new array, but when providing an array using -ActualValue
it actually becomes @(@(1,2,3))
at the moment. As a workaround, you could wrap your expected value in a similar outer array using the comma operator:
It 'workaround' {
Should -ActualValue @(1,2,3) -Be -ExpectedValue (,@(1,2,3))
}
It 'workaround splatting' {
$ShouldParams =
@{
ActualValue =
@(1,2,3)
ExpectedValue =
,@(1,2,3) # notice the , to create a nested array
Be =
$true
}
Should @ShouldParams
}
The issue is that when using the pipeline, PowerShell unrolls the array. To enable array-comparisons we overcome this by adding
$ActualValue
to a new array, but when providing an array using-ActualValue
it actually becomes@(@(1,2,3))
at the moment. As a workaround, you could wrap your expected value in a similar outer array using the comma operator:
I get the explanation but why do we have to remember a different way of putting our expected value in when you should be able to check if ActualValue came from the pipeline and ONLY wrap it in an array in that case
So instead of
begin {
$inputArray = [System.Collections.Generic.List[PSObject]]@()
}
process {
$inputArray.Add($ActualValue)
}
have
begin {
$inputArray = $ActualValue
if ($PSCmdlet.MyInvocation.ExpectingInput) {
$inputArray = [System.Collections.Generic.List[PSObject]]@()
}
}
process {
if ($PSCmdlet.MyInvocation.ExpectingInput) {
$inputArray.Add($ActualValue)
}
}
You might not have noticed that I called it a workaround, didn't close the issue and linked a related PR (possible breaking change so no promises yet).
You might not have noticed that I called it a workaround, didn't close the issue and linked a related PR (possible breaking change so no promises yet).
🙂
I saw after I responded LOL
Seems you were going down the same general thought process I was.
I appreciate the attempt at a merge