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-Throw/Should -Throw to handle expected message with escaped wildcard #2559

Merged
merged 8 commits into from
Oct 1, 2024
3 changes: 2 additions & 1 deletion src/functions/assert/Exception/Should-Throw.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function Should-Throw {
```powershell
{ throw 'error' } | Should-Throw
{ throw 'error' } | Should-Throw -ExceptionMessage 'error'
{ throw 'wildcard character []' } | Should-Throw -ExceptionMessage '*character `[`]'
{ throw 'error' } | Should-Throw -ExceptionType 'System.Management.Automation.RuntimeException'
{ throw 'error' } | Should-Throw -FullyQualifiedErrorId 'RuntimeException'
{ throw 'error' } | Should-Throw -FullyQualifiedErrorId '*Exception'
Expand Down Expand Up @@ -100,7 +101,7 @@ function Should-Throw {

$filterOnMessage = -not ([string]::IsNullOrWhiteSpace($ExceptionMessage))
if ($filterOnMessage) {
$filters += "with message '$ExceptionMessage'"
$filters += "with message like '$([System.Management.Automation.WildcardPattern]::Unescape($ExceptionMessage))'"
if ($err.ExceptionMessage -notlike $ExceptionMessage) {
$buts += "the message was '$($err.ExceptionMessage)'"
}
Expand Down
14 changes: 11 additions & 3 deletions src/functions/assertions/PesterThrow.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@
# this is for Should -Not -Throw. Once *any* exception was thrown we should fail the assertion
# there is no point in filtering the exception, because there should be none
$succeeded = -not $actualExceptionWasThrown
if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } }
if ($true -eq $succeeded) {
return [Pester.ShouldResult]@{Succeeded = $succeeded }
}

$failureMessage = "Expected no exception to be thrown,$(Format-Because $Because) but an exception `"$actualExceptionMessage`" was thrown $actualExceptionLine."
return [Pester.ShouldResult] @{
Expand All @@ -96,7 +98,8 @@

$filterOnMessage = -not [string]::IsNullOrWhitespace($ExpectedMessage)
if ($filterOnMessage) {
$filters += "message like $(Format-Nicely $ExpectedMessage)"
$unescapedExpectedMessage = [System.Management.Automation.WildcardPattern]::Unescape($ExpectedMessage)
$filters += "message like $(Format-Nicely $unescapedExpectedMessage)"
if ($actualExceptionWasThrown -and (-not (Get-DoValuesMatch $actualExceptionMessage $ExpectedMessage))) {
$buts += "the message was $(Format-Nicely $actualExceptionMessage)"
}
Expand All @@ -120,7 +123,12 @@
$failureMessage = "Expected an exception$(if($filter) { " with $filter" }) to be thrown,$(Format-Because $Because) but $but. $actualExceptionLine".Trim()

$ActualValue = $actualExceptionMessage
$ExpectedValue = if ($filterOnExceptionType) { "type $(Format-Nicely $ExceptionType)" } else { 'any exception' }
$ExpectedValue = if ($filterOnExceptionType) {
"type $(Format-Nicely $ExceptionType)"
}
else {
'any exception'
}

return [Pester.ShouldResult] @{
Succeeded = $false
Expand Down
17 changes: 13 additions & 4 deletions tst/functions/assert/Exception/Should-Throw.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ Describe "Should-Throw" {
It "Fails when exception does not match the message with wildcard" {
{ { throw [ArgumentException]"A is null!" } | Should-Throw -ExceptionMessage '*flabbergasted*' } | Verify-AssertionFailed
}

It "Passes when exception match the message with escaped wildcard" {
{ throw [ArgumentException]"[]" } | Should-Throw -ExceptionMessage '`[`]'
}
}

Context "Filtering with FullyQualifiedErrorId" {
Expand Down Expand Up @@ -86,7 +90,7 @@ Describe "Should-Throw" {

It "Given exception that does not match on message it returns the correct message" {
$err = { { throw [ArgumentException]"fail!" } | Should-Throw -ExceptionMessage 'halt!' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with message 'halt!' to be thrown, but the message was 'fail!'."
$err.Exception.Message | Verify-Equal "Expected an exception, with message like 'halt!' to be thrown, but the message was 'fail!'."
}

It "Given exception that does not match on FullyQualifiedErrorId it returns the correct message" {
Expand All @@ -96,7 +100,7 @@ Describe "Should-Throw" {

It "Given exception that does not match on type and message it returns the correct message" {
$err = { { throw [ArgumentException]"fail!" } | Should-Throw -ExceptionType ([System.InvalidOperationException]) -ExceptionMessage 'halt!' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, of type [InvalidOperationException], with message 'halt!' to be thrown, but the exception type was [ArgumentException] and the message was 'fail!'."
$err.Exception.Message | Verify-Equal "Expected an exception, of type [InvalidOperationException], with message like 'halt!' to be thrown, but the exception type was [ArgumentException] and the message was 'fail!'."
}

It "Given exception that does not match on type and FullyQualifiedErrorId it returns the correct message" {
Expand All @@ -106,12 +110,17 @@ Describe "Should-Throw" {

It "Given exception that does not match on message and FullyQualifiedErrorId it returns the correct message" {
$err = { { throw [ArgumentException]"halt!" } | Should-Throw -ExceptionMessage 'fail!' -FullyQualifiedErrorId 'fail!' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with message 'fail!', with FullyQualifiedErrorId 'fail!' to be thrown, but the message was 'halt!' and the FullyQualifiedErrorId was 'halt!'."
$err.Exception.Message | Verify-Equal "Expected an exception, with message like 'fail!', with FullyQualifiedErrorId 'fail!' to be thrown, but the message was 'halt!' and the FullyQualifiedErrorId was 'halt!'."
}

It "Given exception that does not match on type, message and FullyQualifiedErrorId it returns the correct message" {
$err = { { throw [ArgumentException]"halt!" } | Should-Throw -ExceptionType ([System.InvalidOperationException]) -ExceptionMessage 'fail!' -FullyQualifiedErrorId 'fail!' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, of type [InvalidOperationException], with message 'fail!' and with FullyQualifiedErrorId 'fail!' to be thrown, but the exception type was [ArgumentException], the message was 'halt!' and the FullyQualifiedErrorId was 'halt!'."
$err.Exception.Message | Verify-Equal "Expected an exception, of type [InvalidOperationException], with message like 'fail!' and with FullyQualifiedErrorId 'fail!' to be thrown, but the exception type was [ArgumentException], the message was 'halt!' and the FullyQualifiedErrorId was 'halt!'."
}

It "Given exception that does not match on a message with escaped wildcard it returns the correct message" {
$err = { { throw [ArgumentException]"[!]" } | Should-Throw -ExceptionMessage '`[`]' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with message like '[]' to be thrown, but the message was '[!]'."
}
}

Expand Down
12 changes: 12 additions & 0 deletions tst/functions/assertions/PesterThrow.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ InPesterModuleScope {
$err.Exception.Message | Verify-Equal "Expected an exception with FullyQualifiedErrorId 'id' to be thrown, but no exception was thrown."
}

It "returns the correct assertion message when message filter is used and contain escaped wildcard character" {
$testDrive = (Get-PSDrive TestDrive).Root
$testScriptPath = Join-Path $testDrive test.ps1
Set-Content -Path $testScriptPath -Value "throw [ArgumentException]'[!]'"

# use the real path of the script, because we don't know it beforehand
$assertionMessage = "Expected an exception with message like '[]' to be thrown, but the message was '[!]'. from ##path##:1 char:" -replace "##path##", $testScriptPath

$err = { { & $testScriptPath } | Should -Throw -ExpectedMessage '`[`]' } | Verify-AssertionFailed
$err.Exception.Message -replace "(`r|`n)" -replace '\s+', ' ' -replace '(char:).*$', '$1' | Verify-Equal $assertionMessage
}

It 'returns the correct assertion message when exceptions messages differ' {
$testDrive = (Get-PSDrive TestDrive).Root
$testScriptPath = Join-Path $testDrive test.ps1
Expand Down