From c7703405086e8b47f56c43da113ff1ffc748a405 Mon Sep 17 00:00:00 2001 From: ili101 Date: Wed, 14 Aug 2019 11:08:45 +0300 Subject: [PATCH 1/4] Moved StrictOrder to Get-EquivalencyOption --- src/Equivalence/Assert-Equivalent.ps1 | 15 ++++++++------- tst/Equivalence/Assert-Equivalent.Tests.ps1 | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Equivalence/Assert-Equivalent.ps1 b/src/Equivalence/Assert-Equivalent.ps1 index f1221af..2f6c520 100644 --- a/src/Equivalence/Assert-Equivalent.ps1 +++ b/src/Equivalence/Assert-Equivalent.ps1 @@ -81,7 +81,7 @@ function Compare-CollectionEquivalent ($Expected, $Actual, $Property, $Options) v "`nSearching for `$Expected[$e]:" $currentExpected = $Expected[$e] $found = $false - if ($StrictOrder) { + if ($Options.StrictOrder) { $currentActual = $Actual[$e] if ($taken -notcontains $e -and (-not (Compare-Equivalent -Expected $currentExpected -Actual $currentActual -Path $Property -Options $Options))) { @@ -161,7 +161,7 @@ function Compare-DataTableEquivalent ($Expected, $Actual, $Property, $Options) { for ($e = 0; $e -lt $eEnd; $e++) { $currentExpected = $Expected.Rows[$e] $found = $false - if ($StrictOrder) { + if ($Options.StrictOrder) { $currentActual = $Actual.Rows[$e] if ((-not (Compare-Equivalent -Expected $currentExpected -Actual $currentActual -Path $Property -Options $Options)) -and $taken -notcontains $e) { $taken += $e @@ -660,8 +660,7 @@ function Assert-Equivalent { param( $Actual, $Expected, - $Options = (Get-EquivalencyOption), - [Switch] $StrictOrder + $Options = (Get-EquivalencyOption) ) $areDifferent = Compare-Equivalent -Actual $Actual -Expected $Expected -Options $Options | Out-String @@ -682,13 +681,15 @@ function Get-EquivalencyOption { [string[]] $ExcludePath = @(), [switch] $ExcludePathsNotOnExpected, [ValidateSet('Equivalency', 'Equality')] - [string] $Comparator = 'Equivalency' + [string] $Comparator = 'Equivalency', + [switch] $StrictOrder ) [PSCustomObject]@{ - ExcludedPaths = [string[]] $ExcludePath + ExcludedPaths = [string[]] $ExcludePath ExcludePathsNotOnExpected = [bool] $ExcludePathsNotOnExpected - Comparator = [string] $Comparator + Comparator = [string] $Comparator + StrictOrder = [bool] $StrictOrder } } diff --git a/tst/Equivalence/Assert-Equivalent.Tests.ps1 b/tst/Equivalence/Assert-Equivalent.Tests.ps1 index 4a32fce..8ee02a5 100644 --- a/tst/Equivalence/Assert-Equivalent.Tests.ps1 +++ b/tst/Equivalence/Assert-Equivalent.Tests.ps1 @@ -463,7 +463,7 @@ InModuleScope -ModuleName Assert { Assert-Equivalent -Actual $ActualDeserialized -Expected $ExpectedDeserialized Assert-Equivalent -Actual $Actual -Expected $ExpectedDeserialized - {Assert-Equivalent -Actual $Actual -Expected $Expected -StrictOrder} | Should -Throw + {Assert-Equivalent -Actual $Actual -Expected $Expected -Options (Get-EquivalencyOption -StrictOrder)} | Should -Throw $Actual.Rows[1].Name = 'D' {Assert-Equivalent -Actual $Actual -Expected $Expected} | Should -Throw From 6aea1e058bb2261f71f75b51a644284e73f2966f Mon Sep 17 00:00:00 2001 From: ili101 Date: Wed, 14 Aug 2019 19:35:58 +0300 Subject: [PATCH 2/4] Since PowerShell 7.0.0-preview.2 DBNull -eq $null. So for consistency: in mode "Equivalency" it will pass and fail for "Equality" in all PS versions. Also Deserialize DBNull support added as Deserialize DataTable and DataRow are already supported and it was missing. --- Format/src/Format.psm1 | 2 +- TypeClass/src/TypeClass.psm1 | 6 +++ src/Equivalence/Assert-Equivalent.ps1 | 45 ++++++++++++++----- .../Assert-Equivalent.Options.Tests.ps1 | 6 +++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/Format/src/Format.psm1 b/Format/src/Format.psm1 index 6e5a7ff..227fd77 100644 --- a/Format/src/Format.psm1 +++ b/Format/src/Format.psm1 @@ -72,7 +72,7 @@ function Format-Dictionary ($Value) { } function Format-Nicely ($Value, [switch]$Pretty) { - if ($null -eq $Value) + if (Is-Null -Value $Value) { return Format-Null -Value $Value } diff --git a/TypeClass/src/TypeClass.psm1 b/TypeClass/src/TypeClass.psm1 index 11581f9..b6cae49 100644 --- a/TypeClass/src/TypeClass.psm1 +++ b/TypeClass/src/TypeClass.psm1 @@ -1,3 +1,8 @@ +function Is-Null ($Value) { + # Since PowerShell 7.0 [DBNull] -eq $null. + $null -eq $Value -or $Value -is [DBNull] -or $Value.Psobject.TypeNames[0] -like '*System.DBNull' +} + function Is-Value ($Value) { $Value = $($Value) $Value -is [ValueType] -or $Value -is [string] -or $value -is [scriptblock] @@ -50,6 +55,7 @@ function Is-DataRow ($Value) { } Export-ModuleMember -Function @( + 'Is-Null' 'Is-Value' 'Is-Collection' 'Is-DataTable' diff --git a/src/Equivalence/Assert-Equivalent.ps1 b/src/Equivalence/Assert-Equivalent.ps1 index 2f6c520..620b015 100644 --- a/src/Equivalence/Assert-Equivalent.ps1 +++ b/src/Equivalence/Assert-Equivalent.ps1 @@ -191,6 +191,37 @@ function Compare-DataTableEquivalent ($Expected, $Actual, $Property, $Options) { } } +function Compare-NullEquivalent ($Actual, $Expected, $Property, $Options) { + if ("Equivalency" -eq $Options.Comparator) { + v "Equivalency comparator is used, values will be compared for equivalency." + if (Is-Null -Value $Actual) + { + v -Equivalence "`$Actual is equivalent to `$null." + return + } + } + else + { + v "Equality comparator is used, values will be compared for equality." + if ($Expected -isnot [Object] -and $Actual -isnot [Object]) + { + v -Equivalence "`$Actual is equal to `$null, because it is `$null." + return + } + if ($Expected -is [Object] -and $Actual -is [Object] -and + $Expected.Psobject.TypeNames[0] -like '*System.DBNull' -and + $Actual.Psobject.TypeNames[0] -like '*System.DBNull') + { + v -Equivalence "`$Actual is equal to DBNull, because it is DBNull." + return + } + } + # we terminate here, either we passed the test and return nothing, or we did not + # and return message here + v -Difference "`$Actual is not equivalent to $(Format-Nicely $Expected)." + return Get-ValueNotEquivalentMessage -Expected $Expected -Actual $Actual -Property $Property -Options $Options +} + function Compare-ValueEquivalent ($Actual, $Expected, $Property, $Options) { $Expected = $($Expected) if (-not (Is-Value -Value $Expected)) @@ -575,21 +606,13 @@ function Compare-Equivalent { #start by null checks to avoid implementing null handling #logic in the functions that follow - if ($null -eq $Expected) - { + if (Is-Null -Value $Expected) { v "`$Expected is `$null, so we are expecting `$null." - if ($Expected -ne $Actual) - { - v -Difference "`$Actual is not equivalent to $(Format-Nicely $Expected), because it has a value of type $(Format-Nicely $Actual.GetType())." - return Get-ValueNotEquivalentMessage -Expected $Expected -Actual $Actual -Property $Path -Options $Options - } - # we terminate here, either we passed the test and return nothing, or we did not - # and the previous statement returned message - v -Equivalence "`$Actual is equivalent to `$null, because it is `$null." + Compare-NullEquivalent -Expected $Expected -Actual $Actual -Property $Path -Options $Options return } - if ($null -eq $Actual) + if (Is-Null -Value $Actual) { v -Difference "`$Actual is $(Format-Nicely), but `$Expected has value of type $(Format-Nicely Get-Type $Expected), so they are not equivalent." return Get-ValueNotEquivalentMessage -Expected $Expected -Actual $Actual -Property $Path diff --git a/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 b/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 index 632b1d3..2815c20 100644 --- a/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 +++ b/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 @@ -355,6 +355,12 @@ $options = Get-EquivalencyOption -Comparator Equality { Assert-Equivalent -Actual $actual -Expected $expected -Options $options } | Verify-AssertionFailed + + $DBNull = [DBNull]::Value + Assert-Equivalent -Actual $null -Expected $DBNull + Assert-Equivalent -Actual $DBNull -Expected $null + {Assert-Equivalent -Actual $null -Expected $DBNull -Options $options} | Should -Throw -ExpectedMessage 'Expected and actual are not equivalent!' + {Assert-Equivalent -Actual $DBNull -Expected $null -Options $options} | Should -Throw -ExpectedMessage 'Expected and actual are not equivalent!' } } From 959c9ca38ee7eccbe4d03fc3a485c44b10b2b426 Mon Sep 17 00:00:00 2001 From: ili101 Date: Thu, 15 Aug 2019 12:26:38 +0300 Subject: [PATCH 3/4] StrictEquality --- src/Equivalence/Assert-Equivalent.ps1 | 30 ++++++++++++++++--- .../Assert-Equivalent.Options.Tests.ps1 | 28 +++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/Equivalence/Assert-Equivalent.ps1 b/src/Equivalence/Assert-Equivalent.ps1 index 620b015..3919272 100644 --- a/src/Equivalence/Assert-Equivalent.ps1 +++ b/src/Equivalence/Assert-Equivalent.ps1 @@ -19,7 +19,8 @@ function Get-ValueNotEquivalentMessage ($Expected, $Actual, $Property, $Options) $Expected = Format-Nicely -Value $Expected $Actual = Format-Nicely -Value $Actual $propertyInfo = if ($Property) { " property $Property with value" } - $comparison = if ("Equality" -eq $Options.Comparator) { 'equal' } else { 'equivalent' } + $comparison = if ("Equality" -eq $Options.Comparator) { 'equal' } + elseif ("StrictEquality" -eq $Options.Comparator) { 'strictly equal' } else { 'equivalent' } "Expected$propertyInfo '$Expected' to be $comparison to the actual value, but got '$Actual'." } @@ -200,9 +201,9 @@ function Compare-NullEquivalent ($Actual, $Expected, $Property, $Options) { return } } - else + elseif ("StrictEquality" -eq $Options.Comparator) { - v "Equality comparator is used, values will be compared for equality." + v "StrictEquality comparator is used, values will be compared for equality." if ($Expected -isnot [Object] -and $Actual -isnot [Object]) { v -Equivalence "`$Actual is equal to `$null, because it is `$null." @@ -216,6 +217,17 @@ function Compare-NullEquivalent ($Actual, $Expected, $Property, $Options) { return } } + else + { + v "Equality comparator is used, values will be compared for equality." + if ($Expected -is [Object] -and $Expected.Psobject.TypeNames[0] -like '*System.DBNull') {$Expected = [DBNull]::Value} + if ($Actual -is [Object] -and $Actual.Psobject.TypeNames[0] -like '*System.DBNull') {$Actual = [DBNull]::Value} + if ($Expected -eq $Actual) + { + v -Equivalence "`$Actual is equal to DBNull, because it is DBNull." + return + } + } # we terminate here, either we passed the test and return nothing, or we did not # and return message here v -Difference "`$Actual is not equivalent to $(Format-Nicely $Expected)." @@ -279,6 +291,16 @@ function Compare-ValueEquivalent ($Actual, $Expected, $Property, $Options) { return } } + elseif ("StrictEquality" -eq $Options.Comparator) + { + v "StrictEquality comparator is used, values will be compared for strict equality." + if ($Expected.GetType() -ne $Actual.GetType()) + { + v -Difference "`$Actual is not equivalent to `$Expected because their type differ." + return Get-ValueNotEquivalentMessage -Expected $Expected -Actual $Actual -Property $Path -Options $Options + } + v "types are matching, will be tested for values." + } else { v "Equality comparator is used, values will be compared for equality." @@ -703,7 +725,7 @@ function Get-EquivalencyOption { param( [string[]] $ExcludePath = @(), [switch] $ExcludePathsNotOnExpected, - [ValidateSet('Equivalency', 'Equality')] + [ValidateSet('Equivalency', 'Equality', 'StrictEquality')] [string] $Comparator = 'Equivalency', [switch] $StrictOrder ) diff --git a/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 b/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 index 2815c20..89cdf73 100644 --- a/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 +++ b/tst/Equivalence/Assert-Equivalent.Options.Tests.ps1 @@ -355,16 +355,32 @@ $options = Get-EquivalencyOption -Comparator Equality { Assert-Equivalent -Actual $actual -Expected $expected -Options $options } | Verify-AssertionFailed + } - $DBNull = [DBNull]::Value - Assert-Equivalent -Actual $null -Expected $DBNull - Assert-Equivalent -Actual $DBNull -Expected $null - {Assert-Equivalent -Actual $null -Expected $DBNull -Options $options} | Should -Throw -ExpectedMessage 'Expected and actual are not equivalent!' - {Assert-Equivalent -Actual $DBNull -Expected $null -Options $options} | Should -Throw -ExpectedMessage 'Expected and actual are not equivalent!' + $OptionsEquality = Get-EquivalencyOption -Comparator Equality + $OptionsStrictEquality = Get-EquivalencyOption -Comparator StrictEquality + $DBNull = [DBNull]::Value + It "Test vs with -Comparator 'Equivalency', 'Equality', 'StrictEquality'" -TestCases @( + @{ Actual = 'False' ; Expected = $false } + @{ Actual = $null; Expected = $DBNull } + @{ Actual = 5; Expected = '5' } + @{ Actual = { 'String' }; Expected = { 'String' } } + ) { + param($Expected, $Actual) + # Equivalent + Assert-Equivalent -Actual $Actual -Expected $Expected + Assert-Equivalent -Actual $Expected -Expected $Actual + # StrictEquality + { Assert-Equivalent -Actual $Actual -Expected $Expected -Options $OptionsStrictEquality } | Verify-AssertionFailed + { Assert-Equivalent -Actual $Expected -Expected $Actual -Options $OptionsStrictEquality } | Verify-AssertionFailed + # Equality + $AssertResult = try { Assert-Equivalent -Actual $Actual -Expected $Expected -Options $OptionsEquality ; $true} catch {$false} + $AssertResult -eq ($Expected -eq $Actual) | Verify-True + $AssertResult = try { Assert-Equivalent -Actual $Expected -Expected $Actual -Options $OptionsEquality ; $true} catch {$false} + $AssertResult -eq ($Actual -eq $Expected) | Verify-True } } - Describe "Printing Options into difference report" { It "Given options that exclude property it shows up in the difference report correctly" { From 6166abfdae360098c4c08a1988852e036f640ba4 Mon Sep 17 00:00:00 2001 From: ili101 Date: Thu, 15 Aug 2019 18:05:19 +0300 Subject: [PATCH 4/4] Test: SerializeDeserialize in memory --- tst/Equivalence/Assert-Equivalent.Tests.ps1 | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/tst/Equivalence/Assert-Equivalent.Tests.ps1 b/tst/Equivalence/Assert-Equivalent.Tests.ps1 index 8ee02a5..1963150 100644 --- a/tst/Equivalence/Assert-Equivalent.Tests.ps1 +++ b/tst/Equivalence/Assert-Equivalent.Tests.ps1 @@ -440,24 +440,9 @@ InModuleScope -ModuleName Assert { Assert-Equivalent -Actual $Actual -Expected $Expected function SerializeDeserialize ($InputObject) { - # psv2 compatibility - # $ExpectedDeserialized = [System.Management.Automation.PSSerializer]::Deserialize([System.Management.Automation.PSSerializer]::Serialize($Expected)) - # Alternatively this could be done in memory via https://github.com/Jaykul/Reflection/blob/master/CliXml.psm1, but I don't want to fiddle with more - # relfection right now - try { - $path = [IO.Path]::GetTempFileName() - - Export-Clixml -Path $path -InputObject $InputObject -Force | Out-Null - Import-Clixml -Path $path - } - finally { - if ($null -ne $path -and (Test-Path $path)) { - Remove-Item -Path $path -Force - } - } + , [System.Management.Automation.PSSerializer]::Deserialize([System.Management.Automation.PSSerializer]::Serialize($InputObject, 3)) } - $ExpectedDeserialized = SerializeDeserialize $Expected $ActualDeserialized = SerializeDeserialize $Actual Assert-Equivalent -Actual $ActualDeserialized -Expected $ExpectedDeserialized