Skip to content

TestContext.Progress and TestContext.Error silently drop text that is not properly XML encoded #1891

@KrzysFR

Description

@KrzysFR

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&#32;World");
	TestContext.Progress.WriteLine("Hello&lt;World");
	TestContext.Progress.WriteLine("Hello&amp;World");
	TestContext.Progress.WriteLine("Hello&gt;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&#32;World
Hello&lt;World
Hello&amp;World
Hello&gt;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?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions