Skip to content

Commit

Permalink
Update error messages in Should -Throw (#2354)
Browse files Browse the repository at this point in the history
  • Loading branch information
fflaten committed Jun 7, 2023
1 parent ea70451 commit 9f9f285
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 37 deletions.
35 changes: 9 additions & 26 deletions src/functions/assertions/PesterThrow.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
It does not throw an error, so the test passes.
#>
param (
[ScriptBlock] $ActualValue,
$ActualValue,
[string] $ExpectedMessage,
[string] $ErrorId,
[type] $ExceptionType,
Expand All @@ -45,8 +45,8 @@
$actualException = $null
$actualExceptionLine = $null

if ($null -eq $ActualValue) {
throw [ArgumentNullException] "Input is not a ScriptBlock. Input to '-Throw' and '-Not -Throw' must be enclosed in curly braces."
if ($null -eq $ActualValue -or $ActualValue -isnot [ScriptBlock]) {
throw [ArgumentException] "Input is missing or not a ScriptBlock. Input to '-Throw' and '-Not -Throw' must be enclosed in curly braces."
}

try {
Expand Down Expand Up @@ -87,29 +87,12 @@
# the rest is for Should -Throw, we must fail the assertion when no exception is thrown
# or when the exception does not match our filter

function Join-And ($Items, $Threshold = 2) {

if ($null -eq $items -or $items.count -lt $Threshold) {
$items -join ', '
}
else {
$c = $items.count
($items[0..($c - 2)] -join ', ') + ' and ' + $items[-1]
}
}

function Add-SpaceToNonEmptyString ([string]$Value) {
if ($Value) {
" $Value"
}
}

$buts = @()
$filters = @()

$filterOnExceptionType = $null -ne $ExceptionType
if ($filterOnExceptionType) {
$filters += "with type $(Format-Nicely $ExceptionType)"
$filters += "type $(Format-Nicely $ExceptionType)"

if ($actualExceptionWasThrown -and $actualException -isnot $ExceptionType) {
$buts += "the exception type was $(Format-Nicely ($actualException.GetType()))"
Expand All @@ -118,28 +101,28 @@

$filterOnMessage = -not [string]::IsNullOrWhitespace($ExpectedMessage)
if ($filterOnMessage) {
$filters += "with message $(Format-Nicely $ExpectedMessage)"
$filters += "message like $(Format-Nicely $ExpectedMessage)"
if ($actualExceptionWasThrown -and (-not (Get-DoValuesMatch $actualExceptionMessage $ExpectedMessage))) {
$buts += "the message was $(Format-Nicely $actualExceptionMessage)"
}
}

$filterOnId = -not [string]::IsNullOrWhitespace($ErrorId)
if ($filterOnId) {
$filters += "with FullyQualifiedErrorId $(Format-Nicely $ErrorId)"
$filters += "FullyQualifiedErrorId $(Format-Nicely $ErrorId)"
if ($actualExceptionWasThrown -and (-not (Get-DoValuesMatch $actualErrorId $ErrorId))) {
$buts += "the FullyQualifiedErrorId was $(Format-Nicely $actualErrorId)"
}
}

if (-not $actualExceptionWasThrown) {
$buts += "no exception was thrown"
$buts += 'no exception was thrown'
}

if ($buts.Count -ne 0) {
$filter = Add-SpaceToNonEmptyString ( Join-And $filters -Threshold 3 )
$filter = Join-And $filters
$but = Join-And $buts
$failureMessage = "Expected an exception,$filter to be thrown,$(Format-Because $Because) but $but. $actualExceptionLine".Trim()
$failureMessage = "Expected an exception$(if($filter) { " with $filter" }) to be thrown,$(Format-Because $Because) but $but. $actualExceptionLine".Trim()

return [PSCustomObject] @{
Succeeded = $false
Expand Down
22 changes: 11 additions & 11 deletions tst/functions/assertions/PesterThrow.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -146,22 +146,22 @@ InPesterModuleScope {
Context 'Assertion messages' {
It 'returns the correct assertion message when no exception is thrown' {
$err = { { } | Should -Throw } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, to be thrown, but no exception was thrown."
$err.Exception.Message | Verify-Equal "Expected an exception to be thrown, but no exception was thrown."
}

It 'returns the correct assertion message when type filter is used, but no exception is thrown' {
$err = { { } | Should -Throw -ExceptionType ([System.ArgumentException]) } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with type [System.ArgumentException] to be thrown, but no exception was thrown."
$err.Exception.Message | Verify-Equal "Expected an exception with type [System.ArgumentException] to be thrown, but no exception was thrown."
}

It 'returns the correct assertion message when message filter is used, but no exception is thrown' {
$err = { { } | Should -Throw -ExpectedMessage 'message' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with message 'message' to be thrown, but no exception was thrown."
$err.Exception.Message | Verify-Equal "Expected an exception with message like 'message' to be thrown, but no exception was thrown."
}

It 'returns the correct assertion message when errorId filter is used, but no exception is thrown' {
$err = { { } | Should -Throw -ErrorId 'id' } | Verify-AssertionFailed
$err.Exception.Message | Verify-Equal "Expected an exception, with FullyQualifiedErrorId 'id' to be thrown, but no exception was thrown."
$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 exceptions messages differ' {
Expand All @@ -170,7 +170,7 @@ InPesterModuleScope {
Set-Content -Path $testScriptPath -Value "throw 'error1'"

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

$err = { { & $testScriptPath } | Should -Throw -ExpectedMessage error2 } | Verify-AssertionFailed
$err.Exception.Message -replace "(`r|`n)" -replace '\s+', ' ' -replace '(char:).*$', '$1' | Verify-Equal $assertionMessage
Expand All @@ -182,7 +182,7 @@ InPesterModuleScope {
Set-Content -Path $testScriptPath -Value "throw 'error1'"

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

$err = { { & $testScriptPath } | Should -Throw -ExpectedMessage error2 -Because 'reason' } | Verify-AssertionFailed
$err.Exception.Message -replace "(`r|`n)" -replace '\s+', ' ' -replace '(char:).*$', '$1' | Verify-Equal $assertionMessage
Expand All @@ -192,27 +192,27 @@ InPesterModuleScope {
It "given scriptblock that throws an exception where <notMatching> parameter(s) don't match, it fails with correct assertion message$([System.Environment]::NewLine)actual: id <actualId>, message <actualMess>, type <actualType>$([System.Environment]::NewLine)expected: id <expectedId>, message <expectedMess> type <expectedType>" -TestCases @(
@{ actualId = "-id"; actualMess = "+mess"; actualType = ([System.InvalidOperationException])
expectedId = "+id"; expectedMess = "+mess"; expectedType = ([System.InvalidOperationException])
notMatching = 1; assertionMessage = "Expected an exception, with type [System.InvalidOperationException], with message '+mess' and with FullyQualifiedErrorId '+id' to be thrown, but the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
notMatching = 1; assertionMessage = "Expected an exception with type [System.InvalidOperationException], message like '+mess' and FullyQualifiedErrorId '+id' to be thrown, but the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
}

@{ actualId = "-id"; actualMess = "-mess"; actualType = ([System.InvalidOperationException])
expectedId = "+id"; expectedMess = "+mess"; expectedType = ([System.InvalidOperationException])
notMatching = 2; assertionMessage = "Expected an exception, with type [System.InvalidOperationException], with message '+mess' and with FullyQualifiedErrorId '+id' to be thrown, but the message was '-mess' and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
notMatching = 2; assertionMessage = "Expected an exception with type [System.InvalidOperationException], message like '+mess' and FullyQualifiedErrorId '+id' to be thrown, but the message was '-mess' and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
}

@{ actualId = "+id"; actualMess = "-mess"; actualType = ([System.ArgumentException])
expectedId = "+id"; expectedMess = "+mess"; expectedType = ([System.InvalidOperationException])
notMatching = 2; assertionMessage = "Expected an exception, with type [System.InvalidOperationException], with message '+mess' and with FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException] and the message was '-mess'. from ##path##:8 char:"
notMatching = 2; assertionMessage = "Expected an exception with type [System.InvalidOperationException], message like '+mess' and FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException] and the message was '-mess'. from ##path##:8 char:"
}

@{ actualId = "-id"; actualMess = "+mess"; actualType = ([System.ArgumentException])
expectedId = "+id"; expectedMess = "+mess"; expectedType = ([System.InvalidOperationException])
notMatching = 2; assertionMessage = "Expected an exception, with type [System.InvalidOperationException], with message '+mess' and with FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException] and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
notMatching = 2; assertionMessage = "Expected an exception with type [System.InvalidOperationException], message like '+mess' and FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException] and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
}

@{ actualId = "-id"; actualMess = "-mess"; actualType = ([System.ArgumentException])
expectedId = "+id"; expectedMess = "+mess"; expectedType = ([System.InvalidOperationException])
notMatching = 3; assertionMessage = "Expected an exception, with type [System.InvalidOperationException], with message '+mess' and with FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException], the message was '-mess' and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
notMatching = 3; assertionMessage = "Expected an exception with type [System.InvalidOperationException], message like '+mess' and FullyQualifiedErrorId '+id' to be thrown, but the exception type was [System.ArgumentException], the message was '-mess' and the FullyQualifiedErrorId was '-id'. from ##path##:8 char:"
}
) {
$exception = New-Object ($actualType.FullName) $actualMess
Expand Down

0 comments on commit 9f9f285

Please sign in to comment.