Functions/Assert-That.ps1
# Copyright 2012 - 2015 Aaron Jensen # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. function Assert-That { <# .SYNOPSIS Asserts that an object meets certain conditions and throws an exception when they aren't. .DESCRIPTION The `Assert-That` function checks that a given set of condiions are true and if they aren't, it throws a `Blade.AssertionException`. .EXAMPLE Assert-That { throw 'Fubar!' } -Throws [Management.Automation.RuntimeException] Demonstrates how to check that a script block throws an exception. .EXAMPLE Assert-That { } -DoesNotThrowException Demonstrates how to check that a script block doesn't throw an exception. .EXAMPLE Assert-That @( 1, 2, 3 ) -Contains 2 Demonstrates how to check if an array, list, or other collection contains an object. .EXAMPLE Assert-That @{ 'fubar' = 'snafu' } -Contains 'fubar' Demonstrates how to check if a hashtable/dictionary object contains a value. .EXAMPLE Assert-That 'fubar' -Contains 'UBA' Demonstrates how to check if a string contains a substring. The search is case-insensitive. #> [CmdletBinding()] param( [Parameter(Mandatory=$true,Position=0)] [object] # The object whose conditions you're checking. $InputObject, [Parameter(Mandatory=$true,ParameterSetName='Contains')] [object] # Asserts that `InputObject` contains a value. `InputObject` can be an array, list, hashtable, dictionary, collection or a single string. If `InputObject` is another type, it is first converted to a string before being searched. # # If `InputObject` is an array or list, this function uses PowerShell's `-contains` operator to determine if it contains `Contains`, e.g. `$InputObject -contains $Contains`. # # If `InputObject` is a dictionary, this function uses its `Contains` method to determine if it contains `Contains`, e.g. `$InputObject.Contains($Contains)`. # # If `InputObject` is a collection, this function enumerates through each item in the collection and uses PowerShell's `-eq` operator to determine if it matches/is equal to `Contains` e.g. # # foreach( $item in $InputObject.GetEnumerator() ) # { # if( $item -eq $Contains ) # { # } # } # # In all other cases, `InputObject` and `Contains` are converted to strings and compared using the `-like` operator. Any wildcards in `Contains` are escaped and it is wrapped in the `*` wildcard, e.g. `$InputObject -like ('*{0}*' -f [Management.Automation.WildcardPattern]::Escape($Contains))`. $Contains, [Parameter(Mandatory=$true,ParameterSetName='DoesNotContain')] [object] # Asserts that `InputObject` does not contain a value. `InputObject` can be an array, list, hashtable, dictionary, collection or a single string. If `InputObject` is another type, it is first converted to a string before being searched. # # If `InputObject` is an array or list, this function uses PowerShell's `-contains` operator to determine if it contains `Contains`, e.g. `$InputObject -contains $Contains`. # # If `InputObject` is a dictionary, this function uses its `Contains` method to determine if it contains `Contains`, e.g. `$InputObject.Contains($Contains)`. # # If `InputObject` is a collection, this function enumerates through each item in the collection and uses PowerShell's `-eq` operator to determine if it matches/is equal to `Contains` e.g. # # foreach( $item in $InputObject.GetEnumerator() ) # { # if( $item -eq $Contains ) # { # } # } # # In all other cases, `InputObject` and `Contains` are converted to strings and compared using the `-like` operator. Any wildcards in `Contains` are escaped and it is wrapped in the `*` wildcard, e.g. `$InputObject -like ('*{0}*' -f [Management.Automation.WildcardPattern]::Escape($Contains))`. $DoesNotContain, [Parameter(Mandatory=$true,ParameterSetName='DoesNotThrowException')] [Switch] # Asserts that the script block given by `InputObject` does not throw an exception. $DoesNotThrowException, [Parameter(Mandatory=$true,ParameterSetName='ThrowsException')] [Type] # The type of the exception `$InputObject` should throw. When this parameter is provided, $INputObject should be a script block. $Throws, [Parameter(ParameterSetName='ThrowsException')] [string] # Used with the `Throws` switch. Checks that the thrown exception message matches a regular rexpression. $AndMessageMatches, [Parameter(ParameterSetName='Contains',Position=1)] [Parameter(ParameterSetName='DoesNotContain',Position=1)] [Parameter(ParameterSetName='ThrowsException',Position=1)] [string] # The message to show when the assertion fails. $Message ) Set-StrictMode -Version 'Latest' switch( $PSCmdlet.ParameterSetName ) { 'Contains' { $interfaces = $InputObject.GetType().GetInterfaces() $failureMessage = @' ---------------------------------------------------------------------- {0} ---------------------------------------------------------------------- does not contain ---------------------------------------------------------------------- {1} ---------------------------------------------------------------------- {2} '@ -f $InputObject,$Contains,$Message if( ($interfaces | Where-Object { $_.Name -eq 'IList' } ) ) { if( $InputObject -notcontains $Contains ) { Fail $failureMessage return } } elseif( ($interfaces | Where-Object { $_.Name -eq 'IDictionary' }) ) { if( -not $InputObject.Contains( $Contains ) ) { Fail $failureMessage } } elseif( ($interfaces | Where-Object { $_.Name -eq 'ICollection' } ) ) { $found = $false foreach( $item in $InputObject.GetEnumerator() ) { if( $item -eq $Contains ) { $found = $true break } } if( -not $found ) { Fail $failureMessage } } else { if( $InputObject.ToString() -notlike ('*{0}*' -f [Management.Automation.WildcardPattern]::Escape($Contains.ToString())) ) { Fail $failureMessage } } } 'DoesNotContain' { $interfaces = $InputObject.GetType().GetInterfaces() $failureMessage = @' ---------------------------------------------------------------------- {0} ---------------------------------------------------------------------- contains ---------------------------------------------------------------------- {1} ---------------------------------------------------------------------- {2} '@ -f $InputObject,$DoesNotContain,$Message if( ($interfaces | Where-Object { $_.Name -eq 'IList' } ) ) { if( $InputObject -contains $DoesNotContain ) { Fail $failureMessage return } } elseif( ($interfaces | Where-Object { $_.Name -eq 'IDictionary' }) ) { if( $InputObject.Contains( $DoesNotContain ) ) { Fail $failureMessage } } elseif( ($interfaces | Where-Object { $_.Name -eq 'ICollection' } ) ) { $found = $false foreach( $item in $InputObject.GetEnumerator() ) { if( $item -eq $DoesNotContain ) { $found = $true break } } if( $found ) { Fail $failureMessage } } else { if( $Contains -eq $null ) { $Contains = '' } if( $InputObject.ToString() -like ('*{0}*' -f [Management.Automation.WildcardPattern]::Escape($DoesNotContain.ToString())) ) { Fail $failureMessage } } } 'DoesNotThrowException' { if( $InputObject -isnot [scriptblock] ) { throw 'When using `DoesNotThrowException` parameter, `-InputObject` must be a ScriptBlock.' } try { Invoke-Command -ScriptBlock $InputObject } catch { Fail ('Script block threw an exception: {0}{1}{2}{1}{3}' -f $_.Exception.Message,([Environment]::NewLine),$_.ScriptStackTrace,$Message) } } 'ThrowsException' { if( $InputObject -isnot [scriptblock] ) { throw 'When using `Throws` parameter, `-InputObject` must be a ScriptBlock.' } $threwException = $false $ex = $null try { Invoke-Command -ScriptBlock $InputObject } catch { $ex = $_.Exception if( $ex -is $Throws ) { $threwException = $true } else { Fail ('Expected ScriptBlock to throw a {0} exception, but it threw: {1} {2}' -f $Throws,$ex,$Message) } } if( -not $threwException ) { Fail ('ScriptBlock did not throw a ''{0}'' exception. {1}' -f $Throws.FullName,$Message) } if( $AndMessageMatches ) { if( $ex.Message -notmatch $AndMessageMatches ) { Fail ('Exception message ''{0}'' doesn''t match ''{1}''.' -f $ex.Message,$AndMessageMatches) } } } } } |