-
Notifications
You must be signed in to change notification settings - Fork 748
Description
I upgraded my test cases from NUnit 2.x to 3.x and replaced all occurrences of Console.WriteLine(...)
to use either TestContext.Out
, TestContext.Error
or TestContext.Progress
. After doing this, I started to see random parts of the test output missing.
After some investigation, I found that both TestContext.Progress
and TestContext.Error
do not work well with text that is not properly encoded XML.
Using NUnit 3.5, the following test only outputs the 1st and last line, because the 2nd and 3rd lines contain <
and &
that are not valid XML tokens (while >
is allowed)
[Test]
public void Test_Non_Xml_Output()
{
TestContext.Progress.WriteLine("Hello World");
TestContext.Progress.WriteLine("Hello<World");
TestContext.Progress.WriteLine("Hello&World");
TestContext.Progress.WriteLine("Hello>World");
}
Output:
Hello World
Hello>World
If I use TestContext.Out.WriteLine(...)
instead,I get the expected result once the test finishes.
Hello World
Hello<World
Hello&World
Hello>World
If I change the text to be manually XML encoded, then I get some output, although the literal has been changed to be the XML decoded version:
[Test]
public void Test_Non_Xml_Output()
{
TestContext.Progress.WriteLine("Hello World");
TestContext.Progress.WriteLine("Hello<World");
TestContext.Progress.WriteLine("Hello&World");
TestContext.Progress.WriteLine("Hello>World");
}
Output:
Hello World
Hello<World
Hello&World
Hello>World
This works, but then again the output is not what was written (especially troublesome for tests that validate proper encoding of custom text formats)
And if I switch to TestContext.Out
I get the expected result:
Hello World
Hello<World
Hello&World
Hello>World
Are both TestContext.Progress
and TestContext.Error
only intended to send XML-friendly messages? Or are they supposed to write arbitrary literal text like TestContext.Out
and Console.WriteLine(..)
would ?
Looking at the code in TestOutput.ToXml()
, it looks like the Text
property is not encoded at all when generating the <test-output>
XML fragment:
/// <summary>
/// Convert the TestOutput object to an XML string
/// </summary>
public string ToXml()
{
return TestName != null
? string.Format("<test-output stream='{0}' testname='{1}'>{2}</test-output>", Stream, TestName, Text)
: string.Format("<test-output stream='{0}'>{1}</test-output>", Stream, Text);
}
This would explain the issue above, and also would be open to abuse if someone would do something like TestContext.Progress.WriteLine("</<test-output><!--");
. The Stream
and TestName
values should probably also be XML encoded, though in this case I would think they are safe (unless a C# method name can contain characters that require XML encoding?)
My guess is that the receiving end of the event will fail to decode the XML fragment, and silently drop the XmlException, hence not seeing anything in the output.
Side question: maybe if an instance of TestOutput
is created for each line written, it should be a struct
instead of a class
, to recuce GC overhead?