Skip to content

Commit d9f8347

Browse files
authored
fix: sanitize out and err text in loggers (#188)
* fix: sanitize out and err text in loggers * chore: update base version to 7.x * fix: skip system-out/err at suitelevel if empty * test: fix tests to expect null system-out/err * test: test hang fix on windows
1 parent d8707e9 commit d9f8347

File tree

9 files changed

+127
-29
lines changed

9 files changed

+127
-29
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
33
<SourceRoot Condition="$(SourceRoot) == ''">$(MSBuildThisFileDirectory)</SourceRoot>
4-
<SourcePrefix>6.0.0</SourcePrefix>
4+
<SourcePrefix>7.0.0</SourcePrefix>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/JUnit.Xml.TestLogger/JunitXmlSerializer.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,26 @@ private XElement CreateTestSuiteElement(List<TestResultInfo> results, TestRunCon
298298
// Adding required properties, system-out, and system-err elements in the correct
299299
// positions as required by the xsd. In system-out collapse consecutive newlines to a
300300
// single newline.
301-
var element = new XElement(
301+
var suiteElement = new XElement(
302302
"testsuite",
303303
new XElement("properties"),
304-
testCaseElements,
305-
new XElement("system-out", new XCData(stdOut.ToString())),
306-
new XElement("system-err", new XCData(stdErr.ToString())));
304+
testCaseElements);
305+
306+
// Add system-out and system-err elements only if they have content
307+
var systemOutContent = this.InputSanitizer.Sanitize(stdOut.ToString());
308+
var systemErrContent = this.InputSanitizer.Sanitize(stdErr.ToString());
309+
310+
if (!string.IsNullOrWhiteSpace(systemOutContent))
311+
{
312+
suiteElement.Add(new XElement("system-out", systemOutContent));
313+
}
314+
315+
if (!string.IsNullOrWhiteSpace(systemErrContent))
316+
{
317+
suiteElement.Add(new XElement("system-err", systemErrContent));
318+
}
319+
320+
var element = suiteElement;
307321

308322
element.SetAttributeValue("name", Path.GetFileName(results.First().AssemblyPath));
309323

@@ -410,12 +424,12 @@ private XElement CreateTestCaseElement(TestResultInfo result)
410424

411425
if (!string.IsNullOrWhiteSpace(stdOut.ToString()))
412426
{
413-
testcaseElement.Add(new XElement("system-out", new XCData(stdOut.ToString())));
427+
testcaseElement.Add(new XElement("system-out", this.InputSanitizer.Sanitize(stdOut.ToString())));
414428
}
415429

416430
if (!string.IsNullOrWhiteSpace(stdErr.ToString()))
417431
{
418-
testcaseElement.Add(new XElement("system-err", new XCData(stdErr.ToString())));
432+
testcaseElement.Add(new XElement("system-err", this.InputSanitizer.Sanitize(stdErr.ToString())));
419433
}
420434

421435
testcaseElement.Add(CreatePropertiesElement(result));

src/NUnit.Xml.TestLogger/NUnitXmlSerializer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ private static TestSuite CreateFixture(IGrouping<string, TestResultInfo> results
242242

243243
private static XElement CreateTestCaseElement(TestResultInfo result)
244244
{
245+
var sanitizer = new InputSanitizerXml();
245246
var element = new XElement(
246247
"test-case",
247248
new XAttribute("name", result.DisplayName),
@@ -267,7 +268,7 @@ private static XElement CreateTestCaseElement(TestResultInfo result)
267268

268269
if (!string.IsNullOrWhiteSpace(stdOut.ToString()))
269270
{
270-
element.Add(new XElement("output", new XCData(stdOut.ToString())));
271+
element.Add(new XElement("output", sanitizer.Sanitize(stdOut.ToString())));
271272
}
272273

273274
if (result.Outcome == TestOutcome.Failed)

src/Xunit.Xml.TestLogger/XunitXmlSerializer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ private static bool IsError(TestResultInfo result)
248248

249249
private static XElement CreateTestElement(TestResultInfo result)
250250
{
251+
var sanitizer = new InputSanitizerXml();
251252
var element = new XElement(
252253
"test",
253254
new XAttribute("name", result.DisplayName),
@@ -266,7 +267,7 @@ private static XElement CreateTestElement(TestResultInfo result)
266267
else if (m.Category == "skipReason")
267268
{
268269
// Using the self-defined category skipReason for now
269-
element.Add(new XElement("reason", new XCData(m.Text)));
270+
element.Add(new XElement("reason", sanitizer.Sanitize(m.Text)));
270271
}
271272
}
272273

test/JUnit.Xml.TestLogger.AcceptanceTests/JUnitTestLoggerStoreConsoleOutputOptionsAcceptanceTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public void StoreConsoleOutput_False_DoesNotContainConsoleOut()
128128
Assert.DoesNotContain("{998AC9EC-7429-42CD-AD55-72037E7AF3D8}", passedTestCaseStdOutNode.Value);
129129

130130
var testSuiteStdOutNode = resultsXml.XPathSelectElement("/testsuites/testsuite/system-out");
131-
Assert.IsTrue(testSuiteStdOutNode.Value.Equals(string.Empty));
131+
Assert.IsNull(testSuiteStdOutNode);
132132

133133
TestCaseShouldHaveAttachmentInStandardOut(resultsXml, "PassTest11");
134134
}
@@ -149,7 +149,7 @@ public void StoreConsoleOutput_False_DoesNotContainConsoleErr()
149149
Assert.IsNull(failedTestCaseStdErrNode);
150150

151151
var testSuiteStdErrNode = resultsXml.XPathSelectElement("/testsuites/testsuite/system-err");
152-
Assert.IsTrue(testSuiteStdErrNode.Value.Equals(string.Empty));
152+
Assert.IsNull(testSuiteStdErrNode);
153153
}
154154

155155
[TestMethod]
@@ -214,7 +214,7 @@ public void StoreConsoleOutput_TestCase_ContainsConsoleOutOnlyForTestCase()
214214
Assert.Contains("{998AC9EC-7429-42CD-AD55-72037E7AF3D8}", passedTestCaseStdOutNode.Value);
215215

216216
var testSuiteStdOutNode = resultsXml.XPathSelectElement("/testsuites/testsuite/system-out");
217-
Assert.IsTrue(testSuiteStdOutNode.Value.Equals(string.Empty));
217+
Assert.IsNull(testSuiteStdOutNode);
218218

219219
TestCaseShouldHaveAttachmentInStandardOut(resultsXml, "PassTest11");
220220
}
@@ -236,7 +236,7 @@ public void StoreConsoleOutput_TestCase_ContainsConsoleErrOnlyForTestCase()
236236
Assert.Contains("{33F5FD22-6F40-499D-98E4-481D87FAEAA1}", failedTestCaseStdErrNode.Value);
237237

238238
var testSuiteStdErrNode = resultsXml.XPathSelectElement("/testsuites/testsuite/system-err");
239-
Assert.IsTrue(testSuiteStdErrNode.Value.Equals(string.Empty));
239+
Assert.IsNull(testSuiteStdErrNode);
240240
}
241241

242242
private static void TestCaseShouldHaveAttachmentInStandardOut(XDocument resultsXml, string testcaseName)

test/JUnit.Xml.TestLogger.UnitTests/JUnitXmlTestSerializerTests.cs

Lines changed: 94 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void CreateTestSuiteShouldGroupTestSuitesByName()
6565
}
6666

6767
[TestMethod]
68-
public void TestCaseSystemOutShouldUseCDATA()
68+
public void TestCaseSystemOutShouldBeSanitized()
6969
{
7070
var serializer = new JunitXmlSerializer();
7171
var result = CreateTestResultInfo(
@@ -79,7 +79,7 @@ public void TestCaseSystemOutShouldUseCDATA()
7979
}
8080

8181
[TestMethod]
82-
public void TestCaseSystemErrShouldUseCDATA()
82+
public void TestCaseSystemErrShouldBeSanitized()
8383
{
8484
var serializer = new JunitXmlSerializer();
8585
var result = CreateTestResultInfo(
@@ -93,7 +93,7 @@ public void TestCaseSystemErrShouldUseCDATA()
9393
}
9494

9595
[TestMethod]
96-
public void TestSuiteSystemOutShouldUseCDATA()
96+
public void TestSuiteSystemOutShouldBeSanitized()
9797
{
9898
var serializer = new JunitXmlSerializer();
9999
var results = new List<TestResultInfo> { CreateTestResultInfo() };
@@ -112,13 +112,12 @@ public void TestSuiteSystemOutShouldUseCDATA()
112112
var systemOutElement = doc.XPathSelectElement("//testsuite/system-out");
113113

114114
Assert.IsNotNull(systemOutElement);
115-
Assert.IsTrue(systemOutElement.FirstNode is XCData);
116-
var cdata = (XCData)systemOutElement.FirstNode;
117-
StringAssert.Contains(cdata.Value, "Framework info with <xml> & characters");
115+
Assert.IsTrue(systemOutElement.FirstNode is System.Xml.Linq.XText);
116+
StringAssert.Contains(systemOutElement.Value, "Framework info with <xml> & characters");
118117
}
119118

120119
[TestMethod]
121-
public void TestSuiteSystemErrShouldUseCDATA()
120+
public void TestSuiteSystemErrShouldBeSanitized()
122121
{
123122
var serializer = new JunitXmlSerializer();
124123
var results = new List<TestResultInfo> { CreateTestResultInfo() };
@@ -137,9 +136,92 @@ public void TestSuiteSystemErrShouldUseCDATA()
137136
var systemErrElement = doc.XPathSelectElement("//testsuite/system-err");
138137

139138
Assert.IsNotNull(systemErrElement);
140-
Assert.IsTrue(systemErrElement.FirstNode is XCData);
141-
var cdata = (XCData)systemErrElement.FirstNode;
142-
StringAssert.Contains(cdata.Value, "Error - Error message with <xml> & characters");
139+
Assert.IsTrue(systemErrElement.FirstNode is System.Xml.Linq.XText);
140+
StringAssert.Contains(systemErrElement.Value, "Error - Error message with <xml> & characters");
141+
}
142+
143+
[TestMethod]
144+
public void TestSuiteShouldNotIncludeEmptySystemOutElement()
145+
{
146+
var serializer = new JunitXmlSerializer();
147+
var results = new List<TestResultInfo> { CreateTestResultInfo() };
148+
var messages = new List<TestMessageInfo>(); // No messages
149+
150+
var xml = serializer.Serialize(
151+
CreateTestLoggerConfiguration(),
152+
CreateTestRunConfiguration(),
153+
results,
154+
messages);
155+
156+
var doc = XDocument.Parse(xml);
157+
var systemOutElement = doc.XPathSelectElement("//testsuite/system-out");
158+
159+
Assert.IsNull(systemOutElement, "Empty system-out element should not be included in test suite");
160+
}
161+
162+
[TestMethod]
163+
public void TestSuiteShouldNotIncludeEmptySystemErrElement()
164+
{
165+
var serializer = new JunitXmlSerializer();
166+
var results = new List<TestResultInfo> { CreateTestResultInfo() };
167+
var messages = new List<TestMessageInfo>(); // No messages
168+
169+
var xml = serializer.Serialize(
170+
CreateTestLoggerConfiguration(),
171+
CreateTestRunConfiguration(),
172+
results,
173+
messages);
174+
175+
var doc = XDocument.Parse(xml);
176+
var systemErrElement = doc.XPathSelectElement("//testsuite/system-err");
177+
178+
Assert.IsNull(systemErrElement, "Empty system-err element should not be included in test suite");
179+
}
180+
181+
[TestMethod]
182+
public void TestSuiteShouldIncludeSystemOutElementWhenContentExists()
183+
{
184+
var serializer = new JunitXmlSerializer();
185+
var results = new List<TestResultInfo> { CreateTestResultInfo() };
186+
var messages = new List<TestMessageInfo>
187+
{
188+
new TestMessageInfo(TestMessageLevel.Informational, "Framework info message")
189+
};
190+
191+
var xml = serializer.Serialize(
192+
CreateTestLoggerConfiguration(),
193+
CreateTestRunConfiguration(),
194+
results,
195+
messages);
196+
197+
var doc = XDocument.Parse(xml);
198+
var systemOutElement = doc.XPathSelectElement("//testsuite/system-out");
199+
200+
Assert.IsNotNull(systemOutElement, "Non-empty system-out element should be included in test suite");
201+
Assert.IsTrue(systemOutElement.Value.Contains("Framework info message"));
202+
}
203+
204+
[TestMethod]
205+
public void TestSuiteShouldIncludeSystemErrElementWhenContentExists()
206+
{
207+
var serializer = new JunitXmlSerializer();
208+
var results = new List<TestResultInfo> { CreateTestResultInfo() };
209+
var messages = new List<TestMessageInfo>
210+
{
211+
new TestMessageInfo(TestMessageLevel.Error, "Error message")
212+
};
213+
214+
var xml = serializer.Serialize(
215+
CreateTestLoggerConfiguration(),
216+
CreateTestRunConfiguration(),
217+
results,
218+
messages);
219+
220+
var doc = XDocument.Parse(xml);
221+
var systemErrElement = doc.XPathSelectElement("//testsuite/system-err");
222+
223+
Assert.IsNotNull(systemErrElement, "Non-empty system-err element should be included in test suite");
224+
Assert.IsTrue(systemErrElement.Value.Contains("Error - Error message"));
143225
}
144226

145227
private static LoggerConfiguration CreateTestLoggerConfiguration()
@@ -193,9 +275,9 @@ private static string SerializeAndExtractElementContent(JunitXmlSerializer seria
193275
var targetElement = testCaseElement.Element(elementName);
194276

195277
Assert.IsNotNull(targetElement, $"Element '{elementName}' not found in testcase");
196-
Assert.IsTrue(targetElement.FirstNode is XCData, $"Element '{elementName}' does not contain CDATA");
278+
Assert.IsTrue(targetElement.FirstNode is System.Xml.Linq.XText, $"Element '{elementName}' should contain text node");
197279

198-
return ((XCData)targetElement.FirstNode).Value;
280+
return targetElement.Value;
199281
}
200282

201283
private static TestSuite CreateTestSuite(string name)

test/TestLogger.Fixtures/DotnetTestFixture.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,8 @@ public string Execute(string assemblyName, string loggerArgs, bool collectCovera
5353
}
5454
};
5555
cleanProcess.Start();
56-
var cleanOutput = cleanProcess.StandardOutput.ReadToEnd();
56+
cleanProcess.StandardOutput.ReadToEnd();
5757
cleanProcess.WaitForExit();
58-
Console.WriteLine("\n\n## Clean output:\n" + cleanOutput);
5958
}
6059

6160
if (!isMTP)

test/TestLogger.UnitTests/InputSanitizerXmlTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public void ReplaceInvalidXmlCharShouldIgnoreEmptyOrNullInput(string input)
2424
[DataRow("aa\0\vbb", @"aa\u0000\u000bbb")]
2525
[DataRow("aa\uFFFE", @"aa\ufffe")]
2626
[DataRow("aa\u001F", @"aa\u001f")] // 0x1F from original JUnit logger bug report.
27+
[DataRow("Hello\x1B[4mWorld", @"Hello\u001b[4mWorld")] // ANSI escape character \x1B
2728
public void ReplaceInvalidXmlCharShouldReplaceInvalidXmlCharWithUnicode(string input, string output)
2829
{
2930
var sut = new InputSanitizerXml();

test/Xunit.Xml.TestLogger.AcceptanceTests/TestResultsXmlTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,9 +422,9 @@ public void SkippedTestElementShouldContainSkippingReason(string resultFileName)
422422
Assert.Equal(1, reasonNodes.Count);
423423

424424
var reasonNode = reasonNodes[0].FirstChild;
425-
Assert.IsType<XmlCDataSection>(reasonNode);
425+
Assert.IsType<XmlText>(reasonNode);
426426

427-
XmlCDataSection reasonData = (XmlCDataSection)reasonNode;
427+
XmlText reasonData = (XmlText)reasonNode;
428428

429429
string expectedReason = "Skipped";
430430
Assert.Equal(expectedReason, reasonData.Value);

0 commit comments

Comments
 (0)