Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/Format2.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,25 @@ function Format-Object2 ($Value, $Property, [switch]$Pretty) {
}

function Format-String2 ($Value) {
if ('' -eq $Value) {
# Use .Length instead of '' -eq $Value because PowerShell's -eq operator
# considers some control characters (NUL, BEL, BS, ESC) equal to empty string.
if ($null -eq $Value -or $Value.Length -eq 0) {
return '<empty>'
}

# Escape control characters so they are visible in error messages.
# Without this, chars like ESC (0x1B used in ANSI sequences) are invisible
# and make error output confusing. See https://github.com/pester/Pester/issues/2561
$Value = $Value `
-replace "`0", '␀' `
-replace "`a", '␇' `
-replace "`b", '␈' `
-replace "`t", '␉' `
-replace "`f", '␌' `
-replace "`r", '␍' `
-replace "`n", '␊' `
-replace "`e", '␛'
Comment on lines +58 to +66
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feels like we are re-constructing the same string so many times this way, we should have some similar code that does this by prepenting the code point with a bit that makes it visible. and does that via string builder and a loop. basically re-building the whole string just once.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

special chars are uncommon, so this should be as cheap as possible.


"'$Value'"
}

Expand Down
60 changes: 60 additions & 0 deletions tst/Format2.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,65 @@ InPesterModuleScope {
It "Formats string to be sorrounded by quotes" {
Format-String2 -Value "abc" | Verify-Equal "'abc'"
}

# Regression tests for https://github.com/pester/Pester/issues/2561
# Control characters must be escaped to Unicode control pictures so they are
# visible in error messages instead of being invisible or breaking output.
It "Escapes null character to control picture" {
Format-String2 -Value "`0" | Verify-Equal "'`u{2400}'"
}

It "Escapes bell character to control picture" {
Format-String2 -Value "`a" | Verify-Equal "'`u{2407}'"
}

It "Escapes backspace character to control picture" {
Format-String2 -Value "`b" | Verify-Equal "'`u{2408}'"
}

It "Escapes tab character to control picture" {
Format-String2 -Value "`t" | Verify-Equal "'`u{2409}'"
}

It "Escapes form feed character to control picture" {
Format-String2 -Value "`f" | Verify-Equal "'`u{240C}'"
}

It "Escapes carriage return character to control picture" {
Format-String2 -Value "`r" | Verify-Equal "'`u{240D}'"
}

It "Escapes newline character to control picture" {
Format-String2 -Value "`n" | Verify-Equal "'`u{240A}'"
}

It "Escapes ESC character to control picture" {
Format-String2 -Value "$([char]27)" | Verify-Equal "'`u{241B}'"
}

It "Leaves normal strings unchanged" {
Format-String2 -Value "hello" | Verify-Equal "'hello'"
}

It "Escapes ANSI sequence making escape char visible" {
# ESC[31m is a common ANSI red color code; the ESC byte should become ␛
$ansi = "$([char]27)[31m"
$result = Format-String2 -Value $ansi
$result | Verify-Equal "'`u{241B}[31m'"
}

It "Escapes multiple control chars in one string" {
$value = "a`t`nb"
$result = Format-String2 -Value $value
$result | Verify-Equal "'a`u{2409}`u{240A}b'"
}

It "Escaped output contains no actual control characters" {
# Round-trip: the escaped output should be a clean displayable string
$value = "`0`a`b`t`f`r`n$([char]27)"
$result = Format-String2 -Value $value
# The result should not contain any of the original control characters
$result | Should -Not -Match '[\x00-\x1F]'
}
}
}
Loading