diff --git a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlTransformer.cs b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlTransformer.cs
index af5313cf1b..d75c2e8311 100644
--- a/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlTransformer.cs
+++ b/src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlTransformer.cs
@@ -36,7 +36,10 @@ public void Transform(string xmlFile, string htmlFile)
using XmlReader xr = XmlReader.Create(xmlFile, new XmlReaderSettings() { CheckCharacters = false });
// Use output settings from the xslt, especially the output method, which is HTML, which avoids outputting broken
tags.
- using XmlWriter xw = XmlWriter.Create(htmlFile, _xslTransform.OutputSettings);
+ // However, we also need to ensure the writer is tolerant of invalid XML characters, similar to the reader.
+ var outputSettings = _xslTransform.OutputSettings?.Clone() ?? new XmlWriterSettings();
+ outputSettings.CheckCharacters = false;
+ using XmlWriter xw = XmlWriter.Create(htmlFile, outputSettings);
_xslTransform.Transform(xr, xw);
}
diff --git a/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs b/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs
index 821093aa91..523fb78c94 100644
--- a/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs
+++ b/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs
@@ -591,6 +591,66 @@ public void TestCompleteHandlerShouldNotDivideByZeroWhenThereAre0TestResults()
Assert.AreEqual(0, _htmlLogger.TestRunDetails.Summary.PassPercentage);
}
+ [TestMethod]
+ public void TestResultHandlerShouldHandleSpecialCharactersInDataRowWithoutThrowingException()
+ {
+ // This test is for the issue where HTML logger throws exception when DataRow contains special characters
+ var testCase = CreateTestCase("TestWithSpecialChars");
+ testCase.DisplayName = "TestMethod(\"test with special chars: \\u0001\\u0002\\uFFFF\")";
+
+ var testResult = new ObjectModel.TestResult(testCase)
+ {
+ Outcome = TestOutcome.Passed,
+ DisplayName = "TestMethod(\"test with special chars: \\u0001\\u0002\\uFFFF\")",
+ ErrorMessage = "Error with special chars: \u0001\u0002\uFFFF"
+ };
+
+ // This should not throw an exception
+ try
+ {
+ _htmlLogger.TestResultHandler(new object(), new Mock(testResult).Object);
+ Assert.AreEqual(1, _htmlLogger.TotalTests, "Total Tests");
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"TestResultHandler threw an exception when handling special characters: {ex.Message}");
+ }
+ }
+
+ [TestMethod]
+ public void TestCompleteHandlerShouldHandleSpecialCharactersInDataRowDuringTransformation()
+ {
+ // Create a test case with special characters that would cause XML writing issues
+ var testCase = CreateTestCase("TestWithSpecialChars");
+ testCase.DisplayName = "TestMethod with special characters";
+
+ var testResult = new ObjectModel.TestResult(testCase)
+ {
+ Outcome = TestOutcome.Failed,
+ DisplayName = "TestMethod(\"special chars: \u0001\u0002\")",
+ ErrorMessage = "Error message with special chars: \u0001\u0002\uFFFF",
+ ErrorStackTrace = "Stack trace with special chars: \u0001\u0002"
+ };
+
+ _mockFileHelper.Setup(x => x.GetStream(It.IsAny(), FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ .Returns(new MemoryStream());
+
+ try
+ {
+ _htmlLogger.TestResultHandler(new object(), new Mock(testResult).Object);
+
+ // This is where the issue would typically occur - during TestRunCompleteHandler
+ // when XML is serialized and then transformed to HTML
+ _htmlLogger.TestRunCompleteHandler(new object(), new TestRunCompleteEventArgs(null, false, true, null, null, null, TimeSpan.Zero));
+
+ Assert.AreEqual(1, _htmlLogger.TotalTests, "Total Tests");
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"HTML logger threw an exception when handling special characters during transformation: {ex.Message}");
+ }
+ }
+
private static TestCase CreateTestCase(string testCaseName)
{
return new TestCase(testCaseName, new Uri("some://uri"), "DummySourceFileName");
diff --git a/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlTransformerTests.cs b/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlTransformerTests.cs
new file mode 100644
index 0000000000..7284bb5512
--- /dev/null
+++ b/test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlTransformerTests.cs
@@ -0,0 +1,102 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.VisualStudio.TestPlatform.Extensions.HtmlLogger;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests;
+
+[TestClass]
+public class HtmlTransformerTests
+{
+ [TestMethod]
+ public void TransformShouldHandleSpecialCharactersWithoutThrowingException()
+ {
+ // Create a simple XML with special characters that could cause issues
+ var xmlContent = @"
+
+
+
+
+
+
+";
+
+ var xmlFile = Path.GetTempFileName();
+ var htmlFile = Path.ChangeExtension(xmlFile, ".html");
+
+ try
+ {
+ File.WriteAllText(xmlFile, xmlContent, Encoding.UTF8);
+
+ var transformer = new HtmlTransformer();
+ // This should not throw an exception, even with special characters
+ try
+ {
+ transformer.Transform(xmlFile, htmlFile);
+ }
+ catch (Exception ex)
+ {
+ Assert.Fail($"HtmlTransformer.Transform should not throw an exception with special characters: {ex.Message}");
+ }
+
+ // Verify that HTML file was created
+ Assert.IsTrue(File.Exists(htmlFile), "HTML file should be created");
+
+ // Verify that HTML file has content
+ var htmlContent = File.ReadAllText(htmlFile);
+ Assert.IsFalse(string.IsNullOrEmpty(htmlContent), "HTML content should not be empty");
+ }
+ finally
+ {
+ if (File.Exists(xmlFile)) File.Delete(xmlFile);
+ if (File.Exists(htmlFile)) File.Delete(htmlFile);
+ }
+ }
+
+ [TestMethod]
+ public void TransformShouldCreateValidHtmlOutput()
+ {
+ // Create a basic XML structure
+ var xmlContent = @"
+
+
+
+
+
+
+";
+
+ var xmlFile = Path.GetTempFileName();
+ var htmlFile = Path.ChangeExtension(xmlFile, ".html");
+
+ try
+ {
+ File.WriteAllText(xmlFile, xmlContent, Encoding.UTF8);
+
+ var transformer = new HtmlTransformer();
+ transformer.Transform(xmlFile, htmlFile);
+
+ // Verify that HTML file was created and has content
+ Assert.IsTrue(File.Exists(htmlFile), "HTML file should be created");
+ var htmlContent = File.ReadAllText(htmlFile);
+ Assert.IsFalse(string.IsNullOrEmpty(htmlContent), "HTML content should not be empty");
+ }
+ finally
+ {
+ if (File.Exists(xmlFile)) File.Delete(xmlFile);
+ if (File.Exists(htmlFile)) File.Delete(htmlFile);
+ }
+ }
+}