Functions/Assertions/PesterThrow.ps1
function PesterThrow([scriptblock] $ActualValue, $ExpectedMessage, $ErrorId, [switch] $Negate) { $script:ActualExceptionMessage = "" $script:ActualExceptionWasThrown = $false if ($null -eq $ActualValue) { throw (New-Object -TypeName ArgumentNullException -ArgumentList "ActualValue","Scriptblock not found. Input to 'Throw' and 'Not Throw' must be enclosed in curly braces.") } # This is superfluous, here for now. $ExpectedErrorId = $ErrorId try { do { $null = & $ActualValue } until ($true) } catch { $script:ActualExceptionWasThrown = $true $script:ActualExceptionMessage = $_.Exception.Message $script:ActualErrorId = $_.FullyQualifiedErrorId $script:ActualExceptionLine = Get-ExceptionLineInfo $_.InvocationInfo } [bool] $succeeded = $false if ($ActualExceptionWasThrown) { $succeeded = (Get-DoValuesMatch $script:ActualExceptionMessage $ExpectedMessage) -and (Get-DoValuesMatch $script:ActualErrorId $ExpectedErrorId) } if ($Negate) { $succeeded = -not $succeeded } $failureMessage = '' if (-not $succeeded) { if ($Negate) { $failureMessage = NotPesterThrowFailureMessage -ActualValue $ActualValue -ExpectedMessage $ExpectedMessage -ExpectedErrorId $ExpectedErrorId } else { $failureMessage = PesterThrowFailureMessage -ActualValue $ActualValue -ExpectedMessage $ExpectedMessage -ExpectedErrorId $ExpectedErrorId } } return New-Object psobject -Property @{ Succeeded = $succeeded FailureMessage = $failureMessage } } function Get-DoValuesMatch($ActualValue, $ExpectedValue) { #user did not specify any message filter, so any message matches if ($null -eq $ExpectedValue ) { return $true } return $ActualValue.ToString().IndexOf($ExpectedValue, [System.StringComparison]::InvariantCultureIgnoreCase) -ge 0 } function Get-ExceptionLineInfo($info) { # $info.PositionMessage has a leading blank line that we need to account for in PowerShell 2.0 $positionMessage = $info.PositionMessage -split '\r?\n' -match '\S' -join "`r`n" return ($positionMessage -replace "^At ","from ") } function PesterThrowFailureMessage($ActualValue, $ExpectedMessage, $ExpectedErrorId) { $StringBuilder = Microsoft.PowerShell.Utility\New-Object System.Text.StringBuilder $null = $StringBuilder.Append('Expected: the expression to throw an exception') if ($ExpectedMessage -or $ExpectedErrorId) { $null = $StringBuilder.Append(' with ') $Expected = switch ($null) { { $ExpectedMessage } { 'message {{{0}}}' -f $ExpectedMessage } { $ExpectedErrorId } { 'error id {{{0}}}' -f $ExpectedErrorId } } $Actual = switch ($null) { { $ExpectedMessage } { 'message was {{{0}}}' -f $ActualExceptionMessage } { $ExpectedErrorId } { 'error id was {{{0}}}' -f $ActualErrorId } } $null = $StringBuilder.Append(("{0}, an exception was {1}raised, {2}$([System.Environment]::NewLine) {3}" -f ($Expected -join ' and '), @{$true="";$false="not "}[$ActualExceptionWasThrown], ($Actual -join ' and '), ($ActualExceptionLine -replace "`n","$([System.Environment]::NewLine) ") )) } return $StringBuilder.ToString() } function NotPesterThrowFailureMessage($ActualValue, $ExpectedMessage, $ExpectedErrorId) { $StringBuilder = New-Object System.Text.StringBuilder $null = $StringBuilder.Append('Expected: the expression not to throw an exception') if ($ExpectedMessage -or $ExpectedErrorId) { $null = $StringBuilder.Append(' with ') $Expected = switch ($null) { { $ExpectedMessage } { 'message {{{0}}}' -f $ExpectedMessage } { $ExpectedErrorId } { 'error id {{{0}}}' -f $ExpectedErrorId } } $Actual = switch ($null) { { $ExpectedMessage } { 'message was {{{0}}}' -f $ActualExceptionMessage } { $ExpectedErrorId } { 'error id was {{{0}}}' -f $ActualErrorId } } $null = $StringBuilder.Append(("{0}, an exception was {1}raised, {2}$([System.Environment]::NewLine) {3}" -f ($Expected -join ' and '), (@{$true="";$false="not "}[$ActualExceptionWasThrown]), ($Actual -join ' and '), ($ActualExceptionLine -replace "$([System.Environment]::NewLine)","$([System.Environment]::NewLine) ") )) } else { $null = $StringBuilder.Append((". Message was {{{0}}}$([System.Environment]::NewLine) {1}" -f $ActualExceptionMessage, ($ActualExceptionLine -replace "$([System.Environment]::NewLine)","$([System.Environment]::NewLine) "))) } return $StringBuilder.ToString() } Add-AssertionOperator -Name Throw ` -Test $function:PesterThrow |