From d19716edc480f8856bb887e5e16b0d8f8b52dc80 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Fri, 3 Apr 2026 11:42:22 +0200 Subject: [PATCH] Fix #2649: Catch ToString() exceptions in NUnit3 output Copilot-generated fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/functions/TestResults.NUnit3.ps1 | 7 +++- tst/Pester.RSpec.TestResults.NUnit3.ts.ps1 | 46 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/functions/TestResults.NUnit3.ps1 b/src/functions/TestResults.NUnit3.ps1 index 2066c562a..85ecfa6cf 100644 --- a/src/functions/TestResults.NUnit3.ps1 +++ b/src/functions/TestResults.NUnit3.ps1 @@ -554,7 +554,12 @@ function Format-CDataString ($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() } + $line = if ($null -eq $out[$i]) { + [String]::Empty + } + else { + try { $out[$i].ToString() } catch { "" } + } if (0 -gt $line.IndexOfAny($script:invalidCDataChars)) { # No special chars that need replacing. diff --git a/tst/Pester.RSpec.TestResults.NUnit3.ts.ps1 b/tst/Pester.RSpec.TestResults.NUnit3.ts.ps1 index cd16755ec..4f32547b6 100644 --- a/tst/Pester.RSpec.TestResults.NUnit3.ts.ps1 +++ b/tst/Pester.RSpec.TestResults.NUnit3.ts.ps1 @@ -955,4 +955,50 @@ i -PassThru:$PassThru { $xmlResult.Validate({ throw $args[1].Exception }) } } + + # Regression test for https://github.com/pester/Pester/issues/2649 + # When a test outputs an object whose ToString() throws, the NUnit3 report + # writer (Format-CDataString) would crash, losing the entire report. + # The fix wraps ToString() in try/catch and uses a fallback string. + b "NUnit3 report handles objects with broken ToString()" { + t "should produce valid report when test output object throws on ToString" { + # Create a class whose ToString() throws + $typeAdded = try { [BrokenToString] } catch { $false } + if (-not $typeAdded) { + Add-Type -TypeDefinition ' + public class BrokenToString { + public override string ToString() { + throw new System.InvalidOperationException("ToString failed"); + } + } + ' + } + + $sb = { + Describe 'Describe' { + It 'Outputs broken object' { + # Output an object whose ToString() will throw + [BrokenToString]::new() + $true | Should -Be $true + } + } + } + + $r = Invoke-Pester -Configuration ([PesterConfiguration]@{ + Run = @{ ScriptBlock = $sb; PassThru = $true } + Output = @{ Verbosity = 'None' } + }) + + # The test itself should pass + $r.Result | Verify-Equal 'Passed' + + # Converting to NUnit3 report should NOT throw + $xmlResult = $r | ConvertTo-NUnitReport -Format NUnit3 + + # The output section should contain the fallback message + $xmlTest = $xmlResult.'test-run'.'test-suite'.'test-suite'.'test-case' + $xmlTest.result | Verify-Equal 'Passed' + $xmlTest.output.'#cdata-section' | Verify-Like '*ToString() failed*' + } + } }