From fa6f0b210c1ae7e5425da0dcff7e497affcffac5 Mon Sep 17 00:00:00 2001 From: Justin Grote Date: Tue, 16 Apr 2024 03:21:04 -0700 Subject: [PATCH] Feature Request: ShouldResult property (#2381) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feature Request: Expected, Actual, and Because as Test Property Fields Fixes #1993 * Add lingering "Be" because value * Add missing because argument * Add a strong type to ShouldResult * Fix issue with HaveCount having a typed ExpectedValue parameter * Update src/functions/assertions/Should.ps1 Co-authored-by: Frode Flaten <3436158+fflaten@users.noreply.github.com> * Refactor to guard clauses to ensure success records do not have additional properties * CreateShouldErrorRecord to object type * Add ExpectResult and strong typing to Should -Invoke * Remove null failuremessage --------- Co-authored-by: Frode Flaten <3436158+fflaten@users.noreply.github.com> Co-authored-by: Jakub Jareš --- .vscode/settings.json | 3 +- src/csharp/Pester/Factory.cs | 18 +++-- src/csharp/Pester/ShouldResult.cs | 21 ++++++ src/csharp/Pester/Test.cs | 1 - src/functions/Mock.ps1 | 73 ++++++++++++++----- src/functions/assertions/Be.ps1 | 48 +++++++----- src/functions/assertions/BeGreaterThan.ps1 | 18 ++++- src/functions/assertions/BeIn.ps1 | 16 +++- src/functions/assertions/BeLessThan.ps1 | 18 ++++- src/functions/assertions/BeLike.ps1 | 16 +++- src/functions/assertions/BeLikeExactly.ps1 | 16 +++- src/functions/assertions/BeNullOrEmpty.ps1 | 25 ++++--- src/functions/assertions/BeOfType.ps1 | 24 ++++-- src/functions/assertions/BeTrueOrFalse.ps1 | 20 ++++- src/functions/assertions/Contain.ps1 | 16 +++- src/functions/assertions/Exist.ps1 | 21 ++++-- src/functions/assertions/FileContentMatch.ps1 | 23 ++++-- .../assertions/FileContentMatchExactly.ps1 | 23 ++++-- .../assertions/FileContentMatchMultiline.ps1 | 23 ++++-- .../FileContentMatchMultilineExactly.ps1 | 9 ++- src/functions/assertions/HaveCount.ps1 | 22 +++++- src/functions/assertions/HaveParameter.ps1 | 31 +++++--- src/functions/assertions/Match.ps1 | 23 ++++-- src/functions/assertions/MatchExactly.ps1 | 23 ++++-- src/functions/assertions/PesterThrow.ps1 | 29 ++++---- src/functions/assertions/Should.ps1 | 3 +- 26 files changed, 398 insertions(+), 165 deletions(-) create mode 100644 src/csharp/Pester/ShouldResult.cs diff --git a/.vscode/settings.json b/.vscode/settings.json index 6c62047c7..6231dcbb5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -22,5 +22,6 @@ "systemId": "https://raw.githubusercontent.com/PowerShell/PowerShell/master/src/Schemas/Types.xsd", "pattern": "**/*.Types.ps1xml" } - ] + ], + "dotnet.defaultSolution": "src/csharp/Pester.sln" } diff --git a/src/csharp/Pester/Factory.cs b/src/csharp/Pester/Factory.cs index dc5ce126e..e2f543899 100644 --- a/src/csharp/Pester/Factory.cs +++ b/src/csharp/Pester/Factory.cs @@ -1,8 +1,8 @@ -using System.Management.Automation; -using System.Collections.Generic; using System; -using System.Text; +using System.Collections.Generic; using System.IO; +using System.Management.Automation; +using System.Text; namespace Pester { @@ -33,13 +33,12 @@ public static List CreateCollection() { return new List(); } - - public static ErrorRecord CreateShouldErrorRecord(string message, string file, string line, string lineText, bool terminating) + public static ErrorRecord CreateShouldErrorRecord(string message, string file, string line, string lineText, bool terminating, object shouldResult = null) { - return CreateErrorRecord("PesterAssertionFailed", message, file, line, lineText, terminating); + return CreateErrorRecord("PesterAssertionFailed", message, file, line, lineText, terminating, shouldResult); } - public static ErrorRecord CreateErrorRecord(string errorId, string message, string file, string line, string lineText, bool terminating) + public static ErrorRecord CreateErrorRecord(string errorId, string message, string file, string line, string lineText, bool terminating, object shouldResult = null) { var exception = new Exception(message); // we use ErrorRecord.TargetObject to pass structured information about the error to a reporting system. @@ -51,6 +50,11 @@ public static ErrorRecord CreateErrorRecord(string errorId, string message, stri ["LineText"] = lineText, ["Terminating"] = terminating, }; + + if (shouldResult is not null) + { + targetObject["ShouldResult"] = shouldResult; + } return new ErrorRecord(exception, errorId, ErrorCategory.InvalidResult, targetObject); } diff --git a/src/csharp/Pester/ShouldResult.cs b/src/csharp/Pester/ShouldResult.cs new file mode 100644 index 000000000..d8ad08b5f --- /dev/null +++ b/src/csharp/Pester/ShouldResult.cs @@ -0,0 +1,21 @@ +namespace Pester +{ + public class ShouldResult + { + public bool Succeeded { get; set; } + public string FailureMessage { get; set; } + public ShouldExpectResult ExpectResult { get; set; } + } + + public class ShouldExpectResult + { + public string Actual { get; set; } + public string Expected { get; set; } + public string Because { get; set; } + + public override string ToString() + { + return $"Expected: {Expected} Actual: {Actual} Because: {Because}"; + } + } +} diff --git a/src/csharp/Pester/Test.cs b/src/csharp/Pester/Test.cs index a44031ba8..aad7c3276 100644 --- a/src/csharp/Pester/Test.cs +++ b/src/csharp/Pester/Test.cs @@ -34,7 +34,6 @@ public Test() public object Data { get; set; } public string ExpandedName { get; set; } public string ExpandedPath { get; set; } - public string Result { get; set; } public List ErrorRecord { get; set; } public object StandardOutput { get; set; } diff --git a/src/functions/Mock.ps1 b/src/functions/Mock.ps1 index 53e3d8f43..430b6eaad 100644 --- a/src/functions/Mock.ps1 +++ b/src/functions/Mock.ps1 @@ -300,6 +300,7 @@ function Create-MockHook ($contextInfo, $InvokeMockCallback) { function Should-InvokeVerifiableInternal { [CmdletBinding()] + [OutputType([Pester.ShouldResult])] param( [Parameter(Mandatory)] $Behaviors, @@ -315,31 +316,45 @@ function Should-InvokeVerifiableInternal { } if ($filteredBehaviors.Count -gt 0) { - if ($Negate) { $message = "$([System.Environment]::NewLine)Expected no verifiable mocks to be called,$(Format-Because $Because) but these were:" } - else { $message = "$([System.Environment]::NewLine)Expected all verifiable mocks to be called,$(Format-Because $Because) but these were not:" } - + [string]$filteredBehaviorMessage = '' foreach ($b in $filteredBehaviors) { - $message += "$([System.Environment]::NewLine) Command $($b.CommandName) " + $filteredBehaviorMessage += "$([System.Environment]::NewLine) Command $($b.CommandName) " if ($b.ModuleName) { - $message += "from inside module $($b.ModuleName) " + $filteredBehaviorMessage += "from inside module $($b.ModuleName) " } - if ($null -ne $b.Filter) { $message += "with { $($b.Filter.ToString().Trim()) }" } + if ($null -ne $b.Filter) { $filteredBehaviorMessage += "with { $($b.Filter.ToString().Trim()) }" } + } + + if ($Negate) { + $message = "$([System.Environment]::NewLine)Expected no verifiable mocks to be called,$(Format-Because $Because) but these were:$filteredBehaviorMessage" + $ExpectedValue = 'No verifiable mocks to be called' + $ActualValue = "These mocks were called:$filteredBehaviorMessage" + } + else { + $message = "$([System.Environment]::NewLine)Expected all verifiable mocks to be called,$(Format-Because $Because) but these were not:$filteredBehaviorMessage" + $ExpectedValue = 'All verifiable mocks to be called' + $ActualValue = "These mocks were not called:$filteredBehaviorMessage" } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = $message + ExpectResult = @{ + Expected = $ExpectedValue + Actual = $ActualValue + Because = Format-Because $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true - FailureMessage = $null } } function Should-InvokeInternal { [CmdletBinding(DefaultParameterSetName = 'ParameterFilter')] + [OutputType([Pester.ShouldResult])] param( [Parameter(Mandatory = $true)] [hashtable] $ContextInfo, @@ -452,43 +467,67 @@ function Should-InvokeInternal { if ($Negate) { # Negative checks - if ($matchingCalls.Count -eq $Times -and ($Exactly -or !$PSBoundParameters.ContainsKey("Times"))) { - return [PSCustomObject] @{ + if ($matchingCalls.Count -eq $Times -and ($Exactly -or !$PSBoundParameters.ContainsKey('Times'))) { + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected ${commandName}${moduleMessage} not to be called exactly $Times times,$(Format-Because $Because) but it was" + ExpectResult = [Pester.ShouldExpectResult]@{ + Expected = "${commandName}${moduleMessage} not to be called exactly $Times times" + Actual = "${commandName}${moduleMessage} was called $($matchingCalls.count) times" + Because = Format-Because $Because + } } } elseif ($matchingCalls.Count -ge $Times -and !$Exactly) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected ${commandName}${moduleMessage} to be called less than $Times times,$(Format-Because $Because) but was called $($matchingCalls.Count) times" + ExpectResult = [Pester.ShouldExpectResult]@{ + Expected = "${commandName}${moduleMessage} to be called less than $Times times" + Actual = "${commandName}${moduleMessage} was called $($matchingCalls.count) times" + Because = Format-Because $Because + } } } } else { if ($matchingCalls.Count -ne $Times -and ($Exactly -or ($Times -eq 0))) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected ${commandName}${moduleMessage} to be called $Times times exactly,$(Format-Because $Because) but was called $($matchingCalls.Count) times" + ExpectResult = [Pester.ShouldExpectResult]@{ + Expected = "${commandName}${moduleMessage} to be called $Times times exactly" + Actual = "${commandName}${moduleMessage} was called $($matchingCalls.count) times" + Because = Format-Because $Because + } } } elseif ($matchingCalls.Count -lt $Times) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected ${commandName}${moduleMessage} to be called at least $Times times,$(Format-Because $Because) but was called $($matchingCalls.Count) times" + ExpectResult = [Pester.ShouldExpectResult]@{ + Expected = "${commandName}${moduleMessage} to be called at least $Times times" + Actual = "${commandName}${moduleMessage} was called $($matchingCalls.count) times" + Because = Format-Because $Because + } } } elseif ($filterIsExclusive -and $nonMatchingCalls.Count -gt 0) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected ${commandName}${moduleMessage} to only be called with with parameters matching the specified filter,$(Format-Because $Because) but $($nonMatchingCalls.Count) non-matching calls were made" + ExpectResult = [Pester.ShouldExpectResult]@{ + Expected = "${commandName}${moduleMessage} to only be called with with parameters matching the specified filter" + Actual = "${commandName}${moduleMessage} was called $($nonMatchingCalls.Count) times with non-matching parameters" + Because = Format-Because $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true - FailureMessage = $null } } diff --git a/src/functions/assertions/Be.ps1 b/src/functions/assertions/Be.ps1 index 748a9475f..0ac42406b 100644 --- a/src/functions/assertions/Be.ps1 +++ b/src/functions/assertions/Be.ps1 @@ -26,18 +26,23 @@ function Should-Be ($ActualValue, $ExpectedValue, [switch] $Negate, [string] $Be $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because - } - else { - $failureMessage = ShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because + } + else { + $failureMessage = ShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } @@ -64,9 +69,9 @@ function NotShouldBeFailureMessage($ActualValue, $ExpectedValue, $Because) { } & $script:SafeCommands['Add-ShouldOperator'] -Name Be ` - -InternalName Should-Be ` - -Test ${function:Should-Be} ` - -Alias 'EQ' ` + -InternalName Should-Be ` + -Test ${function:Should-Be} ` + -Alias 'EQ' ` -SupportsArrayInput Set-ShouldOperatorHelpMessage -OperatorName Be ` @@ -99,18 +104,23 @@ function Should-BeExactly($ActualValue, $ExpectedValue, $Because) { $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because - } - else { - $failureMessage = ShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because + } + else { + $failureMessage = ShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/BeGreaterThan.ps1 b/src/functions/assertions/BeGreaterThan.ps1 index 00aafc167..d3b1c004a 100644 --- a/src/functions/assertions/BeGreaterThan.ps1 +++ b/src/functions/assertions/BeGreaterThan.ps1 @@ -14,13 +14,18 @@ } if ($ActualValue -le $ExpectedValue) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected the actual value to be greater than $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } @@ -47,13 +52,18 @@ function Should-BeLessOrEqual($ActualValue, $ExpectedValue, [switch] $Negate, [s } if ($ActualValue -gt $ExpectedValue) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected the actual value to be less than or equal to $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/BeIn.ps1 b/src/functions/assertions/BeIn.ps1 index dbad24a8e..ed719d568 100644 --- a/src/functions/assertions/BeIn.ps1 +++ b/src/functions/assertions/BeIn.ps1 @@ -16,20 +16,30 @@ if (-not $succeeded) { if ($Negate) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected collection $(Format-Nicely $ExpectedValue) to not contain $(Format-Nicely $ActualValue),$(Format-Because $Because) but it was found." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } else { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected collection $(Format-Nicely $ExpectedValue) to contain $(Format-Nicely $ActualValue),$(Format-Because $Because) but it was not found." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/BeLessThan.ps1 b/src/functions/assertions/BeLessThan.ps1 index 2ba09e5e0..b983c79f9 100644 --- a/src/functions/assertions/BeLessThan.ps1 +++ b/src/functions/assertions/BeLessThan.ps1 @@ -14,13 +14,18 @@ } if ($ActualValue -ge $ExpectedValue) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected the actual value to be less than $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } @@ -47,13 +52,18 @@ function Should-BeGreaterOrEqual($ActualValue, $ExpectedValue, [switch] $Negate, } if ($ActualValue -lt $ExpectedValue) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected the actual value to be greater than or equal to $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/BeLike.ps1 b/src/functions/assertions/BeLike.ps1 index 132712546..7a4320aff 100644 --- a/src/functions/assertions/BeLike.ps1 +++ b/src/functions/assertions/BeLike.ps1 @@ -24,20 +24,30 @@ if (-not $succeeded) { if ($Negate) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected like wildcard $(Format-Nicely $ExpectedValue) to not match $(Format-Nicely $ActualValue),$(Format-Because $Because) but it did match." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } else { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected like wildcard $(Format-Nicely $ExpectedValue) to match $(Format-Nicely $ActualValue),$(Format-Because $Because) but it did not match." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/BeLikeExactly.ps1 b/src/functions/assertions/BeLikeExactly.ps1 index 36242bbbf..d476cc9fc 100644 --- a/src/functions/assertions/BeLikeExactly.ps1 +++ b/src/functions/assertions/BeLikeExactly.ps1 @@ -23,20 +23,30 @@ if (-not $succeeded) { if ($Negate) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected case sensitive like wildcard $(Format-Nicely $ExpectedValue) to not match $(Format-Nicely $ActualValue),$(Format-Because $Because) but it did match." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } else { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected case sensitive like wildcard $(Format-Nicely $ExpectedValue) to match $(Format-Nicely $ActualValue),$(Format-Because $Because) but it did not match." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/BeNullOrEmpty.ps1 b/src/functions/assertions/BeNullOrEmpty.ps1 index 3c29198ef..99099c83c 100644 --- a/src/functions/assertions/BeNullOrEmpty.ps1 +++ b/src/functions/assertions/BeNullOrEmpty.ps1 @@ -48,19 +48,26 @@ function Should-BeNullOrEmpty($ActualValue, [switch] $Negate, [string] $Because) $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldBeNullOrEmptyFailureMessage -Because $Because - } - else { - $valueToFormat = if ($singleValue) { $expandedValue } else { $ActualValue } - $failureMessage = ShouldBeNullOrEmptyFailureMessage -ActualValue $valueToFormat -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{ Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldBeNullOrEmptyFailureMessage -Because $Because + } + else { + $valueToFormat = if ($singleValue) { $expandedValue } else { $ActualValue } + $failureMessage = ShouldBeNullOrEmptyFailureMessage -ActualValue $valueToFormat -Because $Because } - return [PSCustomObject] @{ + $ExpectedValue = if ($Negate) { '$null or empty' } else { 'a value' } + + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/BeOfType.ps1 b/src/functions/assertions/BeOfType.ps1 index 1b58343c7..591dc1187 100644 --- a/src/functions/assertions/BeOfType.ps1 +++ b/src/functions/assertions/BeOfType.ps1 @@ -51,18 +51,26 @@ function Should-BeOfType($ActualValue, $ExpectedType, [switch] $Negate, [string] $actualType = $null } - if (-not $succeded) { - if ($Negate) { - $failureMessage = "Expected the value to not have type $(Format-Nicely $ExpectedType) or any of its subtypes,$(Format-Because $Because) but got $(Format-Nicely $ActualValue) with type $(Format-Nicely $actualType)." - } - else { - $failureMessage = "Expected the value to have type $(Format-Nicely $ExpectedType) or any of its subtypes,$(Format-Because $Because) but got $(Format-Nicely $ActualValue) with type $(Format-Nicely $actualType)." - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + + if ($Negate) { + $failureMessage = "Expected the value to not have type $(Format-Nicely $ExpectedType) or any of its subtypes,$(Format-Because $Because) but got $(Format-Nicely $ActualValue) with type $(Format-Nicely $actualType)." + } + else { + $failureMessage = "Expected the value to have type $(Format-Nicely $ExpectedType) or any of its subtypes,$(Format-Because $Because) but got $(Format-Nicely $ActualValue) with type $(Format-Nicely $actualType)." } - return [PSCustomObject] @{ + $ExpectedValue = if ($Negate) { "not $(Format-Nicely $ExpectedType) or any of its subtypes" } else { "a $(Format-Nicely $ExpectedType) or any of its subtypes" } + + return [Pester.ShouldResult] @{ Succeeded = $succeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/BeTrueOrFalse.ps1 b/src/functions/assertions/BeTrueOrFalse.ps1 index 99e81f5e2..028363865 100644 --- a/src/functions/assertions/BeTrueOrFalse.ps1 +++ b/src/functions/assertions/BeTrueOrFalse.ps1 @@ -25,13 +25,19 @@ if (-not $ActualValue) { $failureMessage = "Expected `$true,$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." - return [PSCustomObject] @{ + $ExpectedValue = $true + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } @@ -63,13 +69,19 @@ function Should-BeFalse($ActualValue, [switch] $Negate, $Because) { if ($ActualValue) { $failureMessage = "Expected `$false,$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." - return [PSCustomObject] @{ + $ExpectedValue = $false + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/Contain.ps1 b/src/functions/assertions/Contain.ps1 index e2624e4ed..5da8d9a40 100644 --- a/src/functions/assertions/Contain.ps1 +++ b/src/functions/assertions/Contain.ps1 @@ -16,20 +16,30 @@ if (-not $succeeded) { if ($Negate) { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected $(Format-Nicely $ExpectedValue) to not be found in collection $(Format-Nicely $ActualValue),$(Format-Because $Because) but it was found." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } else { - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "Expected $(Format-Nicely $ExpectedValue) to be found in collection $(Format-Nicely $ActualValue),$(Format-Because $Because) but it was not found." + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/Exist.ps1 b/src/functions/assertions/Exist.ps1 index ae79a7cfc..2b5895b75 100644 --- a/src/functions/assertions/Exist.ps1 +++ b/src/functions/assertions/Exist.ps1 @@ -20,18 +20,23 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = "Expected path $(Format-Nicely $ActualValue) to not exist,$(Format-Because $Because) but it did exist." - } - else { - $failureMessage = "Expected path $(Format-Nicely $ActualValue) to exist,$(Format-Because $Because) but it did not exist." - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = "Expected path $(Format-Nicely $ActualValue) to not exist,$(Format-Because $Because) but it did exist." + } + else { + $failureMessage = "Expected path $(Format-Nicely $ActualValue) to exist,$(Format-Because $Because) but it did not exist." } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = if ($Negate) { 'not exist' } else { 'exist' } + Because = $Because + } } } diff --git a/src/functions/assertions/FileContentMatch.ps1 b/src/functions/assertions/FileContentMatch.ps1 index 27dac43b7..be0ab6b76 100644 --- a/src/functions/assertions/FileContentMatch.ps1 +++ b/src/functions/assertions/FileContentMatch.ps1 @@ -42,18 +42,25 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldFileContentMatchFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } - else { - $failureMessage = ShouldFileContentMatchFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldFileContentMatchFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because } + else { + $failureMessage = ShouldFileContentMatchFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because + } + + $ExpectedValue = $ExpectedContent - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/FileContentMatchExactly.ps1 b/src/functions/assertions/FileContentMatchExactly.ps1 index 6e2e407c1..066470c7b 100644 --- a/src/functions/assertions/FileContentMatchExactly.ps1 +++ b/src/functions/assertions/FileContentMatchExactly.ps1 @@ -25,18 +25,25 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldFileContentMatchExactlyFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } - else { - $failureMessage = ShouldFileContentMatchExactlyFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldFileContentMatchExactlyFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because } + else { + $failureMessage = ShouldFileContentMatchExactlyFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because + } + + $ExpectedValue = $ExpectedContent - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/FileContentMatchMultiline.ps1 b/src/functions/assertions/FileContentMatchMultiline.ps1 index 1e4b11365..581d04491 100644 --- a/src/functions/assertions/FileContentMatchMultiline.ps1 +++ b/src/functions/assertions/FileContentMatchMultiline.ps1 @@ -34,18 +34,25 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldFileContentMatchMultilineFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } - else { - $failureMessage = ShouldFileContentMatchMultilineFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldFileContentMatchMultilineFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because } + else { + $failureMessage = ShouldFileContentMatchMultilineFailureMessage -ActualValue $ActualValue -ExpectedContent $ExpectedContent -Because $Because + } + + $ExpectedValue = $ExpectedContent - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/FileContentMatchMultilineExactly.ps1 b/src/functions/assertions/FileContentMatchMultilineExactly.ps1 index 18385382a..472c17082 100644 --- a/src/functions/assertions/FileContentMatchMultilineExactly.ps1 +++ b/src/functions/assertions/FileContentMatchMultilineExactly.ps1 @@ -60,9 +60,16 @@ } } - return [PSCustomObject] @{ + $ExpectedValue = $ExpectedContent + + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/HaveCount.ps1 b/src/functions/assertions/HaveCount.ps1 index a4a943f4d..c3857818d 100644 --- a/src/functions/assertions/HaveCount.ps1 +++ b/src/functions/assertions/HaveCount.ps1 @@ -40,9 +40,17 @@ else { "but got an empty collection." } - return [PSCustomObject] @{ + + $ExpectedResult = if ($expectingEmpty) { 'a non-empty collection' } else { "a collection with size different from $(Format-Nicely $ExpectedValue)" } + + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "$expect,$(Format-Because $Because) $but" + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedResult + Because = $Because + } } } else { @@ -58,14 +66,22 @@ else { "but got an empty collection." } - return [PSCustomObject] @{ + + $ExpectedResult = if ($expectingEmpty) { "an empty collection" } else { "a collection with size $(Format-Nicely $ExpectedValue)" } + + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = "$expect,$(Format-Because $Because) $but" + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedResult + Because = $Because + } } } } - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $true } } diff --git a/src/functions/assertions/HaveParameter.ps1 b/src/functions/assertions/HaveParameter.ps1 index 4d5f8811f..dd5d35f25 100644 --- a/src/functions/assertions/HaveParameter.ps1 +++ b/src/functions/assertions/HaveParameter.ps1 @@ -238,10 +238,10 @@ $buts += "the parameter is missing" } elseif ($Negate -and -not $hasKey) { - return [PSCustomObject] @{ Succeeded = $true } + return [Pester.ShouldResult] @{ Succeeded = $true } } elseif ($Negate -and $hasKey -and -not ($InParameterSet -or $Mandatory -or $Type -or $DefaultValue -or $HasArgumentCompleter)) { - $buts += "the parameter exists" + $buts += 'the parameter exists' } else { $attributes = $ActualValue.Parameters[$ParameterName].Attributes @@ -264,13 +264,13 @@ if ($Mandatory) { $testMandatory = $parameterAttributes | & $SafeCommands['Where-Object'] { $_.Mandatory } - $filters += "which is$(if ($Negate) {" not"}) mandatory" + $filters += "which is$(if ($Negate) {' not'}) mandatory" if (-not $Negate -and -not $testMandatory) { $buts += "it wasn't mandatory" } elseif ($Negate -and $testMandatory) { - $buts += "it was mandatory" + $buts += 'it was mandatory' } } @@ -280,7 +280,7 @@ # PS5> [datetime] [type]$actualType = $ActualValue.Parameters[$ParameterName].ParameterType $testType = ($Type -eq $actualType) - $filters += "$(if ($Negate) { "not " })of type [$($Type.FullName)]" + $filters += "$(if ($Negate) { 'not ' })of type [$($Type.FullName)]" if (-not $Negate -and -not $testType) { $buts += "it was of type [$($actualType.FullName)]" @@ -324,13 +324,13 @@ if (-not $testArgumentCompleter) { $testArgumentCompleter = Get-ArgumentCompleter -CommandName $ActualValue.Name -ParameterName $ParameterName } - $filters += "has ArgumentCompletion" + $filters += 'has ArgumentCompletion' if (-not $Negate -and -not $testArgumentCompleter) { - $buts += "has no ArgumentCompletion" + $buts += 'has no ArgumentCompletion' } elseif ($Negate -and $testArgumentCompleter) { - $buts += "has ArgumentCompletion" + $buts += 'has ArgumentCompletion' } } @@ -351,10 +351,10 @@ $aliases = $(Join-And ($faultyAliases -replace '^|$', "'")) $singular = $faultyAliases.Count -eq 1 if ($Negate) { - $buts += "it has $(if($singular) {"an alias"} else {"the aliases"} ) $aliases" + $buts += "it has $(if($singular) {'an alias'} else {'the aliases'} ) $aliases" } else { - $buts += "it didn't have $(if($singular) {"an alias"} else {"the aliases"} ) $aliases" + $buts += "it didn't have $(if($singular) {'an alias'} else {'the aliases'} ) $aliases" } } } @@ -365,13 +365,20 @@ $but = Join-And $buts $failureMessage = "Expected command $($ActualValue.Name)$filter,$(Format-Because $Because) but $but." - return [PSCustomObject] @{ + $ExpectedValue = "Parameter $($ActualValue.Name)$filter" + + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } else { - return [PSCustomObject] @{ Succeeded = $true } + return [Pester.ShouldResult] @{ Succeeded = $true } } } diff --git a/src/functions/assertions/Match.ps1 b/src/functions/assertions/Match.ps1 index 42c6b4cfc..ef80fa581 100644 --- a/src/functions/assertions/Match.ps1 +++ b/src/functions/assertions/Match.ps1 @@ -31,18 +31,25 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldMatchFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because - } - else { - $failureMessage = ShouldMatchFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldMatchFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because } + else { + $failureMessage = ShouldMatchFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because + } + + $ExpectedValue = $RegularExpression - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/MatchExactly.ps1 b/src/functions/assertions/MatchExactly.ps1 index 6f26dc0f4..e2c65da80 100644 --- a/src/functions/assertions/MatchExactly.ps1 +++ b/src/functions/assertions/MatchExactly.ps1 @@ -24,18 +24,25 @@ $failureMessage = '' - if (-not $succeeded) { - if ($Negate) { - $failureMessage = NotShouldMatchExactlyFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because - } - else { - $failureMessage = ShouldMatchExactlyFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because - } + if ($true -eq $succeeded) { return [Pester.ShouldResult]@{Succeeded = $succeeded } } + + if ($Negate) { + $failureMessage = NotShouldMatchExactlyFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because } + else { + $failureMessage = ShouldMatchExactlyFailureMessage -ActualValue $ActualValue -RegularExpression $RegularExpression -Because $Because + } + + $ExpectedValue = $RegularExpression - return [PSCustomObject] @{ + return [Pester.ShouldResult] @{ Succeeded = $succeeded FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } diff --git a/src/functions/assertions/PesterThrow.ps1 b/src/functions/assertions/PesterThrow.ps1 index 9ac8b9a03..f9bd97946 100644 --- a/src/functions/assertions/PesterThrow.ps1 +++ b/src/functions/assertions/PesterThrow.ps1 @@ -70,17 +70,12 @@ # 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 (-not $succeeded) { - $failureMessage = "Expected no exception to be thrown,$(Format-Because $Because) but an exception `"$actualExceptionMessage`" was thrown $actualExceptionLine." - return [PSCustomObject] @{ - Succeeded = $succeeded - FailureMessage = $failureMessage - } - } - else { - return [PSCustomObject] @{ - Succeeded = $true - } + 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] @{ + Succeeded = $succeeded + FailureMessage = $failureMessage } } @@ -124,13 +119,21 @@ $but = Join-And $buts $failureMessage = "Expected an exception$(if($filter) { " with $filter" }) to be thrown,$(Format-Because $Because) but $but. $actualExceptionLine".Trim() - return [PSCustomObject] @{ + $ActualValue = $actualExceptionMessage + $ExpectedValue = if ($filterOnExceptionType) { "type $(Format-Nicely $ExceptionType)" } else { 'any exception' } + + return [Pester.ShouldResult] @{ Succeeded = $false FailureMessage = $failureMessage + ExpectResult = @{ + Actual = Format-Nicely $ActualValue + Expected = Format-Nicely $ExpectedValue + Because = $Because + } } } - $result = [PSCustomObject] @{ + $result = [Pester.ShouldResult] @{ Succeeded = $true } diff --git a/src/functions/assertions/Should.ps1 b/src/functions/assertions/Should.ps1 index 38a7a43cb..428f44bdb 100644 --- a/src/functions/assertions/Should.ps1 +++ b/src/functions/assertions/Should.ps1 @@ -258,8 +258,7 @@ function Invoke-Assertion { $testResult = & $AssertionEntry.Test -ActualValue $ValueToTest -Negate:$Negate -CallerSessionState $CallerSessionState @BoundParameters if (-not $testResult.Succeeded) { - $errorRecord = [Pester.Factory]::CreateShouldErrorRecord($testResult.FailureMessage, $file, $lineNumber, $lineText, $shouldThrow) - + $errorRecord = [Pester.Factory]::CreateShouldErrorRecord($testResult.FailureMessage, $file, $lineNumber, $lineText, $shouldThrow, $testResult) if ($null -eq $AddErrorCallback -or $ShouldThrow) { # throw this error to fail the test immediately