You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Should & Assert use pipeline to pass values to the assertions like this:
1,2,3| Should -HaveType ([int])
This brings problems with enumerating collections if a collection is provided. It also makes it impossible to tell which type of collection was provided on the left side. For example this will fail because the collection gets unwrapped, and also we don't know which type of collection was used before the pipeline:
1,2,3| Should -HaveType [object[]]
To solve this problem we can wrap the collection into an object artifically and make it pass the pipeline safely, by using the , array operator:
,(1,2,3) | Should -HaveType [object[]]
This is not very straight forward or readable, so instead a function could be introduced that would do this for us and would be used on the left side like this:
functionCollection ($Collection) {
,$Collection
}
Collection 1,2,3| Should -HaveType [object[]]
Taking this idea forward we could use the same pattern to clarify the intent of what we want to assert on the collection, such as:
All -ItemsIn 1,2,3| Should -Be 1
Any -ItemIn 1,2,3| Should -Be 5
By making the function output an object that would describe the intent, capture the collection to pass it though the pipeline unwrapped, and offer a nice fluent syntax.
On the other side of the pipeline, Should would then recognise the object pstype and carry out the appropriate assertion. This would also possibly limit the parameter set boom that would inevitably come when extending Should with collection related assertions where options like -Any, -All, -InAnyOrder, -NoOtherItems etc. are useful and would need to be defined for every assertion.
Here is a simple prototype that implements the idea:
functionShould
{
param (
[switch] $Be,$Expected,
[Parameter(ValueFromPipeline)]
$Actual
)
# we define what should happen when one item is comparedif ($Be) {
$predicate= { param($e,$a) $e-eq$a }
$description="be equal to"$message="Actual {0} is not equal to {1}."
}
# we recognize that the wrapping function was used before the pipeline# and decide what to do based on the type of the function usedif ( $null-ne$Actual-and$Actual.PSObject.TypeNames-eq'ShouldDescriptor' ) {
switch ($Actual.Action) {
"All" {
Should-All -Actual $Actual.Content-Expected $Expected-Predicate $predicate-Description $description-Message $message
}
"Any" {
Should-Any -Actual $Actual.Content-Expected $Expected-Predicate $predicate-Description $description-Message $message
}
Default {}
}
}
}
# this function wraps the collection in # a "should descriptor" object that Should recognizesfunctionAll ($ItemsIn) {
$collection=$($ItemsIn)
$type=$nullif ($null-ne$collection) {
$type=$collection.GetType()
}
if ([object]::ReferenceEquals($ItemsIn,$collection))
{
$ofType=$nullif ($null-ne$type) {
$ofType=" of type $($type.Name)"
}
throw"Provided object$ofType is not a collection. 'All' can only be used on collections."
}
[PSCustomObject] @{
PSTypeName='ShouldDescriptor'Action='All'Type=$typeContent=$collection
}
}
# this is another wrapper function this time for AnyfunctionAny ($ItemIn) {
$collection=$($ItemIn)
$type=$nullif ($null-ne$collection) {
$type=$collection.GetType()
}
if ([object]::ReferenceEquals($ItemIn,$collection))
{
$ofType=$nullif ($null-ne$type) {
$ofType=" of type $($type.Name)"
}
throw"Provided object$ofType is not a collection. 'Any' can only be used on collections."
}
[PSCustomObject] @{
PSTypeName='ShouldDescriptor'Action='Any'Type=$typeContent=$collection
}
}
# this will run when All was used and we ensure that all items in the collection# passed the predicatefunctionShould-All ($Actual,$Expected,$Predicate,$Description,$Message) {
$r=foreach ($ain$Actual) {
if (-not (&$Predicate$Expected$a)) {
$Message-f$a,$Expected
}
}
if ($r) {
throw"Expected all items in collection $Actual$Description$Expected, but:`n$([string]::Join("`t`n",$r))`n`n"
}
}
# this will run when Any was used and we ensure that at least one item in# the collection passed the predicatefunctionShould-Any ($Actual,$Expected,$Predicate,$Description,$Message) {
$oneFound=$false$r=foreach ($ain$Actual) {
if (&$Predicate$Expected$a) {
$oneFound=$true
}
}
if (-not$oneFound) {
throw"Expected at least one item in collection $([String]::join(', ',$Actual))$Description$Expected, but no such things were found."
}
}
# comment out the first assertion # and uncomment the second one to# see the second one fail as well
All -ItemsIn 1,2,3| Should -Be 1# Any -ItemIn 1,2,3 | Should -Be 5
Expected all items in collection 1 2 3 be equal to 1, but:
Actual 2 is not equal to 1.
Actual 3 is not equal to 1.
At line:94 char:9
+ throw "Expected all items in collection $Actual $Description ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Expected all it...t equal to 1.
:String) [], RuntimeException
+ FullyQualifiedErrorId : Expected all items in collection 1 2 3 be equal to 1, but:
Actual 2 is not equal to 1.
Actual 3 is not equal to 1.
The text was updated successfully, but these errors were encountered:
Should
&Assert
use pipeline to pass values to the assertions like this:This brings problems with enumerating collections if a collection is provided. It also makes it impossible to tell which type of collection was provided on the left side. For example this will fail because the collection gets unwrapped, and also we don't know which type of collection was used before the pipeline:
To solve this problem we can wrap the collection into an object artifically and make it pass the pipeline safely, by using the
,
array operator:This is not very straight forward or readable, so instead a function could be introduced that would do this for us and would be used on the left side like this:
Taking this idea forward we could use the same pattern to clarify the intent of what we want to assert on the collection, such as:
By making the function output an object that would describe the intent, capture the collection to pass it though the pipeline unwrapped, and offer a nice fluent syntax.
On the other side of the pipeline, Should would then recognise the object pstype and carry out the appropriate assertion. This would also possibly limit the parameter set boom that would inevitably come when extending Should with collection related assertions where options like -Any, -All, -InAnyOrder, -NoOtherItems etc. are useful and would need to be defined for every assertion.
Here is a simple prototype that implements the idea:
The text was updated successfully, but these errors were encountered: