From 5095619955f9f408e503dfcf561923ac6e48e3ce Mon Sep 17 00:00:00 2001 From: Robert A Zeh Date: Wed, 24 Aug 2016 09:38:24 -0500 Subject: [PATCH] Fixes for XML encoding. This commit fixes the following scenario: * You have a test that compares strings with embedded control characters. * The test fails. * You are using JUnit tests within TeamCity. Before this commit, the JUnit report watcher fails on parsing the XML for two reasons: the control characters are missing a semicolon at the end, and the XML document doesn't specify that it is XML 1.1. XML 1.0 --- what we get if we don't specify an XML version --- doesn't support embedding control characters --- see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml for all of the gory details. This is based on PR #588 by @mrpi --- include/internal/catch_xmlwriter.hpp | 16 ++++++++++++---- projects/SelfTest/MiscTests.cpp | 28 ++++++++++++++-------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/internal/catch_xmlwriter.hpp b/include/internal/catch_xmlwriter.hpp index c59725b0..97890d2f 100644 --- a/include/internal/catch_xmlwriter.hpp +++ b/include/internal/catch_xmlwriter.hpp @@ -55,9 +55,10 @@ namespace Catch { break; default: - // Escape control chars - based on contribution by @espenalb in PR #465 + // Escape control chars - based on contribution by @espenalb in PR #465 and + // by @mrpi PR #588 if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) - os << "&#x" << std::uppercase << std::hex << static_cast( c ); + os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast( c ) << ';'; else os << c; } @@ -112,13 +113,20 @@ namespace Catch { : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &Catch::cout() ) - {} + { + // We encode control characters, which requires + // XML 1.1 + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + *m_os << "\n"; + } XmlWriter( std::ostream& os ) : m_tagIsOpen( false ), m_needsNewline( false ), m_os( &os ) - {} + { + *m_os << "\n"; + } ~XmlWriter() { while( !m_tags.empty() ) diff --git a/projects/SelfTest/MiscTests.cpp b/projects/SelfTest/MiscTests.cpp index 9a2a2ab6..bb9cbf0a 100644 --- a/projects/SelfTest/MiscTests.cpp +++ b/projects/SelfTest/MiscTests.cpp @@ -406,27 +406,27 @@ TEST_CASE( "Tabs and newlines show in output", "[.][whitespace][failing]" ) { TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) { - const wchar_t * const s = L"wide load"; - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + const wchar_t * const s = L"wide load"; + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) { - const wchar_t * s = L"wide load"; - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + const wchar_t * s = L"wide load"; + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) { - wchar_t * const s = const_cast( L"wide load" ); - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + wchar_t * const s = const_cast( L"wide load" ); + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) { - wchar_t * s = const_cast( L"wide load" ); - std::string result = Catch::toString( s ); - CHECK( result == "\"wide load\"" ); + wchar_t * s = const_cast( L"wide load" ); + std::string result = Catch::toString( s ); + CHECK( result == "\"wide load\"" ); } inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) { @@ -458,10 +458,10 @@ TEST_CASE( "XmlEncode" ) { REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" ); } SECTION( "string with control char (1)" ) { - REQUIRE( encode( "[\x01]" ) == "[]" ); + REQUIRE( encode( "[\x01]" ) == "[]" ); } SECTION( "string with control char (x7F)" ) { - REQUIRE( encode( "[\x7F]" ) == "[]" ); + REQUIRE( encode( "[\x7F]" ) == "[]" ); } }