From 211dcb84b8f6b7cc64bbc119d4b41ca7f0562469 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Thu, 18 Jun 2026 14:06:17 +0200 Subject: [PATCH 1/3] Use Unicode Control Pictures for special characters in assertions Replace \n, \r, \t etc. with visible Unicode glyphs (U+2400 block) in Expand-SpecialCharacters, reusing the existing C# implementation in [Pester.Formatter]::EscapeControlChars(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/functions/assertions/Be.ps1 | 2 +- .../assert/String/Should-BeString.Tests.ps1 | 12 +++--------- tst/functions/assertions/Be.Tests.ps1 | 6 +++--- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/functions/assertions/Be.ps1 b/src/functions/assertions/Be.ps1 index 8e1356e08..ca0a61fe2 100644 --- a/src/functions/assertions/Be.ps1 +++ b/src/functions/assertions/Be.ps1 @@ -312,7 +312,7 @@ function Expand-SpecialCharacters { [AllowEmptyString()] [string[]]$InputObject) process { - $InputObject -replace "`n", "\n" -replace "`r", "\r" -replace "`t", "\t" -replace "`0", "\0" -replace "`b", "\b" + [Pester.Formatter]::EscapeControlChars($InputObject) } } diff --git a/tst/functions/assert/String/Should-BeString.Tests.ps1 b/tst/functions/assert/String/Should-BeString.Tests.ps1 index 4786c5b78..6659404fa 100644 --- a/tst/functions/assert/String/Should-BeString.Tests.ps1 +++ b/tst/functions/assert/String/Should-BeString.Tests.ps1 @@ -155,14 +155,8 @@ But was: 'abc' It "Shows expanded whitespace characters in diff" { $err = { "abc`ndef" | Should-BeString "abc`r`ndef" } | Verify-AssertionFailed - $err.Exception.Message | Verify-Equal (@' -Expected strings to be the same, but they were different. -Expected length: 8 -Actual length: 7 -Strings differ at index 3. -Expected: 'abc\r\ndef' -But was: 'abc\ndef' - ----^ -'@ -replace "`r`n", "`n") + $cr = [char]0x240D + $lf = [char]0x240A + $err.Exception.Message | Verify-Equal ("Expected strings to be the same, but they were different.`nExpected length: 8`nActual length: 7`nStrings differ at index 3.`nExpected: 'abc${cr}${lf}def'`nBut was: 'abc${lf}def'`n ---^" -replace "`r`n", "`n") } } diff --git a/tst/functions/assertions/Be.Tests.ps1 b/tst/functions/assertions/Be.Tests.ps1 index 4ff9de268..a72bd8e00 100644 --- a/tst/functions/assertions/Be.Tests.ps1 +++ b/tst/functions/assertions/Be.Tests.ps1 @@ -151,15 +151,15 @@ InPesterModuleScope { } It "Replaces non-printable characters correctly" { - ShouldBeFailureMessage "`n`r`b`0`tx" "`n`r`b`0`ty" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 6.`nStrings differ at index 5.`nExpected: '\n\r\b\0\ty'`nBut was: '\n\r\b\0\tx'`n ----------^" + ShouldBeFailureMessage "`n`r`b`0`tx" "`n`r`b`0`ty" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 6.`nStrings differ at index 5.`nExpected: '$(([char]0x240A))$(([char]0x240D))$(([char]0x2408))$(([char]0x2400))$(([char]0x2409))y'`nBut was: '$(([char]0x240A))$(([char]0x240D))$(([char]0x2408))$(([char]0x2400))$(([char]0x2409))x'`n -----^" } It "The arrow points to the correct position when non-printable characters are replaced before the difference" { - ShouldBeFailureMessage "123`n456" "123`n789" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 7.`nStrings differ at index 4.`nExpected: '123\n789'`nBut was: '123\n456'`n -----^" + ShouldBeFailureMessage "123`n456" "123`n789" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 7.`nStrings differ at index 4.`nExpected: '123$(([char]0x240A))789'`nBut was: '123$(([char]0x240A))456'`n ----^" } It "The arrow points to the correct position when non-printable characters are replaced after the difference" { - ShouldBeFailureMessage "abcd`n123" "abc!`n123" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 8.`nStrings differ at index 3.`nExpected: 'abc!\n123'`nBut was: 'abcd\n123'`n ---^" + ShouldBeFailureMessage "abcd`n123" "abc!`n123" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 8.`nStrings differ at index 3.`nExpected: 'abc!$(([char]0x240A))123'`nBut was: 'abcd$(([char]0x240A))123'`n ---^" } } } From 9635aba1129277f9e84934db250201832f8d904a Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 23 Jun 2026 11:58:07 +0200 Subject: [PATCH 2/3] Remove redundant diff index recomputation and use literal Unicode chars in tests Control pictures are 1-to-1 replacements (1 char -> 1 char), so the expanded diff index equals the original. Remove the second scan loop from Be.ps1 and Should-BeString.ps1. Use actual Unicode control picture characters in test expectations instead of [char]0x24XX expressions so the expected output is readable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/functions/assert/String/Should-BeString.ps1 | 14 +------------- src/functions/assertions/Be.ps1 | 16 ---------------- .../assert/String/Should-BeString.Tests.ps1 | 4 +--- tst/functions/assertions/Be.Tests.ps1 | 6 +++--- 4 files changed, 5 insertions(+), 35 deletions(-) diff --git a/src/functions/assert/String/Should-BeString.ps1 b/src/functions/assert/String/Should-BeString.ps1 index fedc3e097..8dc53d57f 100644 --- a/src/functions/assert/String/Should-BeString.ps1 +++ b/src/functions/assert/String/Should-BeString.ps1 @@ -149,22 +149,10 @@ function Get-StringDifferenceMessage { $expectedExpanded = Expand-SpecialCharacters -InputObject $Expected $actualExpanded = Expand-SpecialCharacters -InputObject $Actual - # Recompute difference index on expanded strings - $maxLength = [Math]::Max($expectedExpanded.Length, $actualExpanded.Length) - $expandedDiffIndex = $null - for ($i = 0; $i -lt $maxLength -and ($null -eq $expandedDiffIndex); ++$i) { - if ($CaseSensitive) { - if ($expectedExpanded[$i] -cne $actualExpanded[$i]) { $expandedDiffIndex = $i } - } - else { - if ($expectedExpanded[$i] -ne $actualExpanded[$i]) { $expandedDiffIndex = $i } - } - } - $prefix = "Expected: '" $lines += "$prefix$expectedExpanded'" $lines += "But was: '$actualExpanded'" - $lines += (' ' * ($prefix.Length - 1)) + ('-' * $expandedDiffIndex) + '^' + $lines += (' ' * ($prefix.Length - 1)) + ('-' * $differenceIndex) + '^' $lines -join "`n" } diff --git a/src/functions/assertions/Be.ps1 b/src/functions/assertions/Be.ps1 index ca0a61fe2..891d405e7 100644 --- a/src/functions/assertions/Be.ps1 +++ b/src/functions/assertions/Be.ps1 @@ -207,24 +207,8 @@ function Get-CompareStringMessage { "Strings differ at index $differenceIndex." } - # find the difference in the string with expanded characters, this is the fastest and most foolproof way of - # getting the updated difference index. we could also inspect the new string and try to find every occurrence - # of special character before the difference index, but '\n' is valid piece of string - # or inspect the original string, but then we need to make sure that we look for all the special characters. - # instead we just compare it again. - $actualExpanded = Expand-SpecialCharacters -InputObject $actual $expectedExpanded = Expand-SpecialCharacters -InputObject $ExpectedValue - $maxLength = if ($expectedExpanded.Length -gt $actualExpanded.Length) { $expectedExpanded.Length } else { $actualExpanded.Length } - $differenceIndex = $null - for ($i = 0; $i -lt $maxLength -and ($null -eq $differenceIndex); ++$i) { - $differenceIndex = if ($CaseSensitive -and ($expectedExpanded[$i] -cne $actualExpanded[$i])) { - $i - } - elseif ($expectedExpanded[$i] -ne $actualExpanded[$i]) { - $i - } - } $ellipsis = "..." # we will surround the output with Expected: '' and But was: '', from which the Expected: '' is longer diff --git a/tst/functions/assert/String/Should-BeString.Tests.ps1 b/tst/functions/assert/String/Should-BeString.Tests.ps1 index 6659404fa..c9fc33ff9 100644 --- a/tst/functions/assert/String/Should-BeString.Tests.ps1 +++ b/tst/functions/assert/String/Should-BeString.Tests.ps1 @@ -155,8 +155,6 @@ But was: 'abc' It "Shows expanded whitespace characters in diff" { $err = { "abc`ndef" | Should-BeString "abc`r`ndef" } | Verify-AssertionFailed - $cr = [char]0x240D - $lf = [char]0x240A - $err.Exception.Message | Verify-Equal ("Expected strings to be the same, but they were different.`nExpected length: 8`nActual length: 7`nStrings differ at index 3.`nExpected: 'abc${cr}${lf}def'`nBut was: 'abc${lf}def'`n ---^" -replace "`r`n", "`n") + $err.Exception.Message | Verify-Equal ("Expected strings to be the same, but they were different.`nExpected length: 8`nActual length: 7`nStrings differ at index 3.`nExpected: 'abc␍␊def'`nBut was: 'abc␊def'`n ---^" -replace "`r`n", "`n") } } diff --git a/tst/functions/assertions/Be.Tests.ps1 b/tst/functions/assertions/Be.Tests.ps1 index a72bd8e00..303294c28 100644 --- a/tst/functions/assertions/Be.Tests.ps1 +++ b/tst/functions/assertions/Be.Tests.ps1 @@ -151,15 +151,15 @@ InPesterModuleScope { } It "Replaces non-printable characters correctly" { - ShouldBeFailureMessage "`n`r`b`0`tx" "`n`r`b`0`ty" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 6.`nStrings differ at index 5.`nExpected: '$(([char]0x240A))$(([char]0x240D))$(([char]0x2408))$(([char]0x2400))$(([char]0x2409))y'`nBut was: '$(([char]0x240A))$(([char]0x240D))$(([char]0x2408))$(([char]0x2400))$(([char]0x2409))x'`n -----^" + ShouldBeFailureMessage "`n`r`b`0`tx" "`n`r`b`0`ty" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 6.`nStrings differ at index 5.`nExpected: '␊␍␈␀␉y'`nBut was: '␊␍␈␀␉x'`n -----^" } It "The arrow points to the correct position when non-printable characters are replaced before the difference" { - ShouldBeFailureMessage "123`n456" "123`n789" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 7.`nStrings differ at index 4.`nExpected: '123$(([char]0x240A))789'`nBut was: '123$(([char]0x240A))456'`n ----^" + ShouldBeFailureMessage "123`n456" "123`n789" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 7.`nStrings differ at index 4.`nExpected: '123␊789'`nBut was: '123␊456'`n ----^" } It "The arrow points to the correct position when non-printable characters are replaced after the difference" { - ShouldBeFailureMessage "abcd`n123" "abc!`n123" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 8.`nStrings differ at index 3.`nExpected: 'abc!$(([char]0x240A))123'`nBut was: 'abcd$(([char]0x240A))123'`n ---^" + ShouldBeFailureMessage "abcd`n123" "abc!`n123" | Verify-Equal "Expected strings to be the same, but they were different.`nString lengths are both 8.`nStrings differ at index 3.`nExpected: 'abc!␊123'`nBut was: 'abcd␊123'`n ---^" } } } From 639c7f2b5e4069c0ff18e89b1f224d9957fcff29 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 23 Jun 2026 12:31:41 +0200 Subject: [PATCH 3/3] Use here-string format in test for readability Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tst/functions/assert/String/Should-BeString.Tests.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tst/functions/assert/String/Should-BeString.Tests.ps1 b/tst/functions/assert/String/Should-BeString.Tests.ps1 index c9fc33ff9..fdaaeabc4 100644 --- a/tst/functions/assert/String/Should-BeString.Tests.ps1 +++ b/tst/functions/assert/String/Should-BeString.Tests.ps1 @@ -155,6 +155,14 @@ But was: 'abc' It "Shows expanded whitespace characters in diff" { $err = { "abc`ndef" | Should-BeString "abc`r`ndef" } | Verify-AssertionFailed - $err.Exception.Message | Verify-Equal ("Expected strings to be the same, but they were different.`nExpected length: 8`nActual length: 7`nStrings differ at index 3.`nExpected: 'abc␍␊def'`nBut was: 'abc␊def'`n ---^" -replace "`r`n", "`n") + $err.Exception.Message | Verify-Equal (@' +Expected strings to be the same, but they were different. +Expected length: 8 +Actual length: 7 +Strings differ at index 3. +Expected: 'abc␍␊def' +But was: 'abc␊def' + ---^ +'@ -replace "`r`n", "`n") } }