mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-03 21:49:32 +01:00 
			
		
		
		
	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
This commit is contained in:
		@@ -55,9 +55,10 @@ namespace Catch {
 | 
				
			|||||||
                        break;
 | 
					                        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    default:
 | 
					                    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' )
 | 
					                        if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
 | 
				
			||||||
                            os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
 | 
					                            os << "&#x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>( c ) << ';';
 | 
				
			||||||
                        else
 | 
					                        else
 | 
				
			||||||
                            os << c;
 | 
					                            os << c;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -112,13 +113,20 @@ namespace Catch {
 | 
				
			|||||||
        :   m_tagIsOpen( false ),
 | 
					        :   m_tagIsOpen( false ),
 | 
				
			||||||
            m_needsNewline( false ),
 | 
					            m_needsNewline( false ),
 | 
				
			||||||
            m_os( &Catch::cout() )
 | 
					            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 << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        XmlWriter( std::ostream& os )
 | 
					        XmlWriter( std::ostream& os )
 | 
				
			||||||
        :   m_tagIsOpen( false ),
 | 
					        :   m_tagIsOpen( false ),
 | 
				
			||||||
            m_needsNewline( false ),
 | 
					            m_needsNewline( false ),
 | 
				
			||||||
            m_os( &os )
 | 
					            m_os( &os )
 | 
				
			||||||
        {}
 | 
					        {
 | 
				
			||||||
 | 
					            *m_os << "<?xml version=\"1.1\" encoding=\"UTF-8\"?>\n";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ~XmlWriter() {
 | 
					        ~XmlWriter() {
 | 
				
			||||||
            while( !m_tags.empty() )
 | 
					            while( !m_tags.empty() )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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]" ) {
 | 
					TEST_CASE( "toString on const wchar_t const pointer returns the string contents", "[toString]" ) {
 | 
				
			||||||
	const wchar_t * const s = L"wide load";
 | 
					        const wchar_t * const s = L"wide load";
 | 
				
			||||||
	std::string result = Catch::toString( s );
 | 
					        std::string result = Catch::toString( s );
 | 
				
			||||||
	CHECK( result == "\"wide load\"" );
 | 
					        CHECK( result == "\"wide load\"" );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
 | 
					TEST_CASE( "toString on const wchar_t pointer returns the string contents", "[toString]" ) {
 | 
				
			||||||
	const wchar_t * s = L"wide load";
 | 
					        const wchar_t * s = L"wide load";
 | 
				
			||||||
	std::string result = Catch::toString( s );
 | 
					        std::string result = Catch::toString( s );
 | 
				
			||||||
	CHECK( result == "\"wide load\"" );
 | 
					        CHECK( result == "\"wide load\"" );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
 | 
					TEST_CASE( "toString on wchar_t const pointer returns the string contents", "[toString]" ) {
 | 
				
			||||||
	wchar_t * const s = const_cast<wchar_t* const>( L"wide load" );
 | 
					        wchar_t * const s = const_cast<wchar_t* const>( L"wide load" );
 | 
				
			||||||
	std::string result = Catch::toString( s );
 | 
					        std::string result = Catch::toString( s );
 | 
				
			||||||
	CHECK( result == "\"wide load\"" );
 | 
					        CHECK( result == "\"wide load\"" );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
 | 
					TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
 | 
				
			||||||
	wchar_t * s = const_cast<wchar_t*>( L"wide load" );
 | 
					        wchar_t * s = const_cast<wchar_t*>( L"wide load" );
 | 
				
			||||||
	std::string result = Catch::toString( s );
 | 
					        std::string result = Catch::toString( s );
 | 
				
			||||||
	CHECK( result == "\"wide load\"" );
 | 
					        CHECK( result == "\"wide load\"" );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) {
 | 
					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" );
 | 
					        REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    SECTION( "string with control char (1)" ) {
 | 
					    SECTION( "string with control char (1)" ) {
 | 
				
			||||||
        REQUIRE( encode( "[\x01]" ) == "[]" );
 | 
					        REQUIRE( encode( "[\x01]" ) == "[]" );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    SECTION( "string with control char (x7F)" ) {
 | 
					    SECTION( "string with control char (x7F)" ) {
 | 
				
			||||||
        REQUIRE( encode( "[\x7F]" ) == "[]" );
 | 
					        REQUIRE( encode( "[\x7F]" ) == "[]" );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user