Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a bug where the NUnit-Report fails to generate if the test output contains Virtual Terminal Sequences #2511

Merged
merged 13 commits into from
Jul 1, 2024
39 changes: 33 additions & 6 deletions src/functions/TestResults.NUnit3.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# NUnit3 schema docs: https://docs.nunit.org/articles/nunit/technical-notes/usage/Test-Result-XML-Format.html

[char[]] $script:invalidCDataChars = foreach ($ch in (0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F)) { [char]$ch }

function Write-NUnit3Report([Pester.Run] $Result, [System.Xml.XmlWriter] $XmlWriter) {
# Write the XML Declaration
$XmlWriter.WriteStartDocument($false)
Expand Down Expand Up @@ -537,14 +539,39 @@ function Write-NUnit3TestCaseAttributes {
}

function Write-NUnit3OutputElement ($Output, [System.Xml.XmlWriter] $XmlWriter) {
$outputString = @(foreach ($o in $Output) {
if ($null -eq $o) {
[string]::Empty
} else {
$o.ToString()
# The characters in the range 0x01 to 0x20 are invalid for CData
# (with the exception of the characters 0x09, 0x0A and 0x0D)
# We convert each of these using the unicode printable version,
# which is obtained by adding 0x2400
[int]$unicodeControlPictures = 0x2400

# Avoid indexing into an enumerable, such as a `string`, when there is only one item in the
# output array.
$out = @($Output)
$linesCount = $out.Length
$o = for ($i = 0; $i -lt $linesCount; $i++) {
# The input is array of objects, convert them to strings.
$line = if ($null -eq $out[$i]) { [String]::Empty } else { $out[$i].ToString() }

if (0 -gt $line.IndexOfAny($script:invalidCDataChars)) {
# No special chars that need replacing.
$line
}
else {
$chars = [char[]]$line;
$charCount = $chars.Length
for ($j = 0; $j -lt $charCount; $j++) {
$char = $chars[$j]
if ($char -in $script:invalidCDataChars) {
$chars[$j] = [char]([int]$char + $unicodeControlPictures)
}
}

$chars -join ''
}
}) -join [System.Environment]::NewLine
}

$outputString = $o -join [Environment]::NewLine
$XmlWriter.WriteStartElement('output')
$XmlWriter.WriteCData($outputString)
$XmlWriter.WriteEndElement()
Expand Down
28 changes: 28 additions & 0 deletions tst/Pester.RSpec.TestResults.NUnit3.ts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,34 @@ i -PassThru:$PassThru {
$xmlResult.Validate({ throw $args[1].Exception })
}

t 'replaces virtual terminal escape sequences with their printable representations' {
$sb = {
Describe 'Describe VT Sequences' {
It "Successful" {
$esc = [char][int]0x1B
$bell = [char][int]0x07

# write escape sequences to output
"$esc[32mHello`tWorld$esc[0m"
"Ring the bell$bell"
}
}
}
$r = Invoke-Pester -Configuration ([PesterConfiguration]@{ Run = @{ ScriptBlock = $sb; PassThru = $true }; Output = @{ Verbosity = 'None' } })

$xmlResult = [xml] ($r | ConvertTo-NUnitReport -Format NUnit3)
$xmlResult.Schemas.XmlResolver = New-Object System.Xml.XmlUrlResolver
$xmlResult.Schemas.Add($null, $schemaPath) > $null
$xmlResult.Validate({ throw $args[1].Exception })
$xmlDescribe = $xmlResult.'test-run'.'test-suite'.'test-suite'
$xmlTest = $xmlDescribe.'test-case'
$message = $xmlTest.output.'#cdata-section' -split "`n"

# message has the escape sequences replaced with their printable representations
$message[0] | Verify-Equal "␛[32mHello`tWorld␛[0m"
$message[1] | Verify-Equal "Ring the bell␇"
}

t 'should use TestResult.TestSuiteName configuration value as name-attribute for run and root Assembly test-suite' {
$sb = {
Describe 'Describe' {
Expand Down