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

Fix Should-BeCollection #2506

Merged
merged 4 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/Format2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,7 @@ function Format-Type2 ([Type]$Value) {
$typeFormatted = $type `
-replace "^System\." `
-replace "^Management\.Automation\.PSCustomObject$", "PSObject" `
-replace "^PSCustomObject$", "PSObject" `
-replace "^Object\[\]$", "collection" `
-replace "^PSCustomObject$", "PSObject"

"[$($typeFormatted)]"
}
Expand Down
60 changes: 52 additions & 8 deletions src/functions/assert/Collection/Should-BeCollection.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,68 @@
$Actual = $collectedInput.Actual

if (-not (Is-Collection -Value $Expected)) {
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> '<expected>' is not a collection."
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> <expected> is not a collection."
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}

if (-not (Is-Collection -Value $Actual)) {
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Actual <actualType> '<actual>' is not a collection."
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Actual <actualType> <actual> is not a collection."
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}

if (-not (Is-CollectionSize -Expected $Expected -Actual $Actual)) {
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> '<expected>' to be equal to collection <actualType> '<actual>' but they don't have the same number of items."
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> <expected> to be present in <actualType> <actual>, but they don't have the same number of items."
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}

if ($Actual) {
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> '<expected>' to be present in collection '<actual>', but it was not there."
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}
if (-Not $InOrder) {

$actualCopy = [System.Collections.Generic.List[Object]]::new($Actual)
$expectedCopy = [System.Collections.Generic.List[Object]]::new($Expected)

$actualLength = $actualCopy.Count
$expectedLength = $expectedCopy.Count

# If the arrays below have both size 0 we won't go over them,
# but they are not different. If one of them has size 0 and the other does not
# we already failed the assertion above.
#
# This marks the items that were the same in both arrays, so user can put anything
# in the array, including $null, and we don't have a conflict, because they can never get
# reference to the object in $same.
$same = [Object]::new()
# go over each item in the array and when found overwrite it in the array
for ($a = 0; $a -lt $actualLength; $a++) {
if ($same -eq $actualCopy[$a]) {
continue
}
for ($e = 0; $e -lt $expectedLength; $e++) {
if ($same -eq $expectedCopy[$e]) {
continue
}
if ($actualCopy[$a] -eq $expectedCopy[$e]) {
$expectedCopy[$e] = $same
$actualCopy[$a] = $same
}
}
}

$Actual
$different = $false
for ($a = 0; $a -lt $actualLength; $a++) {
if ($same -ne $actualCopy[$a]) {
$different = $true
break
}
}

if ($different) {
$actualDifference = $(for ($a = 0; $a -lt $actualLength; $a++) { if ($same -ne $actualCopy[$a]) { "$(Format-Nicely2 $actualCopy[$a]) (index $a)" } }) -join ", "
$expectedDifference = $(for ($e = 0; $e -lt $actualLength; $e++) { if ($same -ne $expectedCopy[$e]) { "$(Format-Nicely2 $expectedCopy[$e]) (index $e)" } }) -join ", "

$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -Data @{ expectedDifference = $expectedDifference; actualDifference = $actualDifference } -DefaultMessage "Expected <expectedType> <expected> to be present in <actualType> <actual> in any order, but some values were not.`nMissing in actual: <expectedDifference>`nExtra in actual: <actualDifference>"
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}

$Actual
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
$collectedInput = Collect-Input -ParameterInput $Actual -PipelineInput $local:Input -IsPipelineInput $MyInvocation.ExpectingInput
$Actual = $collectedInput.Actual
if ($Actual -notcontains $Expected) {
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> <expected> to be present in collection <actual>, but it was not there."
$Message = Get-AssertionMessage -Expected $Expected -Actual $Actual -Because $Because -DefaultMessage "Expected <expectedType> <expected> to be present in <actualType> <actual>, but it was not there."
throw [Pester.Factory]::CreateShouldErrorRecord($Message, $MyInvocation.ScriptName, $MyInvocation.ScriptLineNumber, $MyInvocation.Line.TrimEnd([System.Environment]::NewLine), $true)
}

Expand Down
6 changes: 2 additions & 4 deletions tst/Format2.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ InPesterModuleScope {
@{ Value = [double]; Expected = '[double]' },
@{ Value = [string]; Expected = '[string]' },
@{ Value = $null; Expected = '[null]' },
@{ Value = [Management.Automation.PSObject]; Expected = '[PSObject]' },
@{ Value = [Object[]]; Expected = '[collection]' }
@{ Value = [Management.Automation.PSObject]; Expected = '[PSObject]' }
) {
param($Value, $Expected)
Format-Type2 -Value $Value | Verify-Equal $Expected
Expand All @@ -199,8 +198,7 @@ InPesterModuleScope {
@{ Value = 1.1; Expected = '[double]' },
@{ Value = 'a' ; Expected = '[string]' },
@{ Value = $null ; Expected = '[null]' },
@{ Value = [PSCustomObject]@{Name = 'Jakub' } ; Expected = '[PSObject]' },
@{ Value = [Object[]]1, 2, 3 ; Expected = '[collection]' }
@{ Value = [PSCustomObject]@{Name = 'Jakub' } ; Expected = '[PSObject]' }
) {
param($Value, $Expected)
Get-ShortType2 -Value $Value | Verify-Equal $Expected
Expand Down
2 changes: 1 addition & 1 deletion tst/functions/assert/Collection/Should-All.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Expected [int] 2, but got [int] 1." -replace "`r`n", "`n")

It "Fails when no items are passed" -TestCases @(
@{ Actual = $null; Expected = "Expected all items in collection @(`$null) to pass filter { `$_ -eq 1 }, but 1 of them `$null did not pass the filter." }
@{ Actual = @(); Expected = "Expected all items in collection to pass filter { `$_ -eq 1 }, but [collection] @() contains no items to compare." }
@{ Actual = @(); Expected = "Expected all items in collection to pass filter { `$_ -eq 1 }, but [Object[]] @() contains no items to compare." }
) {
$err = { $Actual | Should-All -FilterScript { $_ -eq 1 } } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal $Expected
Expand Down
2 changes: 1 addition & 1 deletion tst/functions/assert/Collection/Should-Any.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Expected [int] 2, but got [int] 1." -replace "`r`n", "`n")

It "Fails when no items are passed" -TestCases @(
@{ Actual = $null; Expected = 'Expected at least one item in collection @($null) to pass filter { $_ -eq 1 }, but none of the items passed the filter.' }
@{ Actual = @(); Expected = 'Expected at least one item in collection to pass filter { $_ -eq 1 }, but [collection] @() contains no items to compare.' }
@{ Actual = @(); Expected = 'Expected at least one item in collection to pass filter { $_ -eq 1 }, but [Object[]] @() contains no items to compare.' }
) {
$err = { $Actual | Should-Any -FilterScript { $_ -eq 1 } } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal $Expected
Expand Down
51 changes: 21 additions & 30 deletions tst/functions/assert/Collection/Should-BeCollection.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,36 +1,27 @@
Set-StrictMode -Version Latest

# TODO: Implement the Should-BeCollection tests, I just don't want to remove it from the current PR just to put it back afterwards.
return

InPesterModuleScope {
Describe "Should-BeCollection" {
It "Passes when collections have the same count and items" -ForEach @(
@{ Actual = @(1); Expected = @(1) }
@{ Actual = @(1, 2); Expected = @(1, 2) }
) {
$actual | Should-BeCollection $expected
}

It "Fails when collections don't have the same count" -ForEach @(
@{ Actual = @(1); Expected = @(1, 2) }
@{ Actual = @(1, 2); Expected = @(1) }
) {
$err = { $actual | Should-BeCollection $expected } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected int '1' to be present in collection '5', but it was not there."
}

# It "Passes when collection of multiple items contains the expected item" {
# @(1,2,3) | Assert-Contain 1
# }
Describe "Should-BeCollection" {
It "Passes when collections have the same count and items" -ForEach @(
@{ Actual = @(1); Expected = @(1) }
@{ Actual = 1; Expected = @(1) }
@{ Actual = @(1, 2); Expected = @(1, 2) }
@{ Actual = @(1..3); Expected = @(1..3) }
) {
$actual | Should-BeCollection $expected
}

# It "Fails when collection of multiple items does not contain the expected item" {
# $err = { @(5,6,7) | Assert-Contain 1 } | Verify-AssertionFailed
# $err.Exception.Message | Verify-Equal "Expected int '1' to be present in collection '5, 6, 7', but it was not there."
# }
It "Fails when collections don't have the same count" -ForEach @(
@{ Actual = @(1, 2); Expected = @(1, 2, 3) }
@{ Actual = @(1, 2, 3); Expected = @(1, 2) }
) {
$err = { $actual | Should-BeCollection $expected } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected [Object[]] @($($expected -join ", ")) to be present in [Object[]] @($($actual -join ", ")), but they don't have the same number of items."
}

# It "Can be called with positional parameters" {
# { Assert-Contain 1 3,4,5 } | Verify-AssertionFailed
# }
It "Fails when collections don't have the same items" -ForEach @(
@{ Actual = @(1, 2, 3, 4, 5); Expected = @(5, 6, 7, 8, 9) }
) {
$err = { $actual | Should-BeCollection $expected } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected [Object[]] @(5, 6, 7, 8, 9) to be present in [Object[]] @(1, 2, 3, 4, 5) in any order, but some values were not.`nMissing in actual: '6 (index 1), 7 (index 2), 8 (index 3), 9 (index 4)'`nExtra in actual: '1 (index 0), 2 (index 1), 3 (index 2), 4 (index 3)'"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
Set-StrictMode -Version Latest

# TODO:
return;

InPesterModuleScope {
Describe "Should-ContainCollection" {
It "Passes when collection of single item contains the expected item" {
Expand Down