mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 15:26:11 +01:00
Fixed Xml encoding
- don't encode apostrophes - only encode quotes in attributes - encode control characters (as in PR #465)
This commit is contained in:
parent
6de135c63a
commit
d6e59cd56f
@ -14,9 +14,65 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
class XmlEncode {
|
||||||
|
public:
|
||||||
|
enum ForWhat { ForTextNodes, ForAttributes };
|
||||||
|
|
||||||
|
XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes )
|
||||||
|
: m_str( str ),
|
||||||
|
m_forWhat( forWhat )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void encodeTo( std::ostream& os ) const {
|
||||||
|
|
||||||
|
// Apostrophe escaping not necessary if we always use " to write attributes
|
||||||
|
// (see: http://www.w3.org/TR/xml/#syntax)
|
||||||
|
|
||||||
|
for( std::size_t i = 0; i < m_str.size(); ++ i ) {
|
||||||
|
char c = m_str[i];
|
||||||
|
switch( c ) {
|
||||||
|
case '<': os << "<"; break;
|
||||||
|
case '&': os << "&"; break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
// See: http://www.w3.org/TR/xml/#syntax
|
||||||
|
if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
|
||||||
|
os << ">";
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
if( m_forWhat == ForAttributes )
|
||||||
|
os << """;
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Escape control chars - based on contribution by @espenalb in PR #465
|
||||||
|
if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' )
|
||||||
|
os << "&#x" << std::uppercase << std::hex << static_cast<int>( c );
|
||||||
|
else
|
||||||
|
os << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
|
||||||
|
xmlEncode.encodeTo( os );
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_str;
|
||||||
|
ForWhat m_forWhat;
|
||||||
|
};
|
||||||
|
|
||||||
class XmlWriter {
|
class XmlWriter {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -99,11 +155,8 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
|
||||||
if( !name.empty() && !attribute.empty() ) {
|
if( !name.empty() && !attribute.empty() )
|
||||||
stream() << " " << name << "=\"";
|
stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\"";
|
||||||
writeEncodedText( attribute );
|
|
||||||
stream() << "\"";
|
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,9 +167,9 @@ namespace Catch {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
|
||||||
if( !name.empty() )
|
std::ostringstream oss;
|
||||||
stream() << " " << name << "=\"" << attribute << "\"";
|
oss << attribute;
|
||||||
return *this;
|
return writeAttribute( name, oss.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlWriter& writeText( std::string const& text, bool indent = true ) {
|
XmlWriter& writeText( std::string const& text, bool indent = true ) {
|
||||||
@ -125,7 +178,7 @@ namespace Catch {
|
|||||||
ensureTagClosed();
|
ensureTagClosed();
|
||||||
if( tagWasOpen && indent )
|
if( tagWasOpen && indent )
|
||||||
stream() << m_indent;
|
stream() << m_indent;
|
||||||
writeEncodedText( text );
|
stream() << XmlEncode( text );
|
||||||
m_needsNewline = true;
|
m_needsNewline = true;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -170,30 +223,6 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeEncodedText( std::string const& text ) {
|
|
||||||
static const char* charsToEncode = "<&\"";
|
|
||||||
std::string mtext = text;
|
|
||||||
std::string::size_type pos = mtext.find_first_of( charsToEncode );
|
|
||||||
while( pos != std::string::npos ) {
|
|
||||||
stream() << mtext.substr( 0, pos );
|
|
||||||
|
|
||||||
switch( mtext[pos] ) {
|
|
||||||
case '<':
|
|
||||||
stream() << "<";
|
|
||||||
break;
|
|
||||||
case '&':
|
|
||||||
stream() << "&";
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
stream() << """;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mtext = mtext.substr( pos+1 );
|
|
||||||
pos = mtext.find_first_of( charsToEncode );
|
|
||||||
}
|
|
||||||
stream() << mtext;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_tagIsOpen;
|
bool m_tagIsOpen;
|
||||||
bool m_needsNewline;
|
bool m_needsNewline;
|
||||||
std::vector<std::string> m_tags;
|
std::vector<std::string> m_tags;
|
||||||
|
@ -797,6 +797,6 @@ with expansion:
|
|||||||
"first" == "second"
|
"first" == "second"
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 157 | 117 passed | 39 failed | 1 failed as expected
|
test cases: 158 | 118 passed | 39 failed | 1 failed as expected
|
||||||
assertions: 773 | 680 passed | 80 failed | 13 failed as expected
|
assertions: 783 | 690 passed | 80 failed | 13 failed as expected
|
||||||
|
|
||||||
|
@ -3762,6 +3762,128 @@ PASSED:
|
|||||||
with expansion:
|
with expansion:
|
||||||
""wide load"" == ""wide load""
|
""wide load"" == ""wide load""
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
normal string
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "normal string" ) == "normal string" )
|
||||||
|
with expansion:
|
||||||
|
"normal string" == "normal string"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
empty string
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "" ) == "" )
|
||||||
|
with expansion:
|
||||||
|
"" == ""
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with ampersand
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "smith & jones" ) == "smith & jones" )
|
||||||
|
with expansion:
|
||||||
|
"smith & jones" == "smith & jones"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with less-than
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "smith < jones" ) == "smith < jones" )
|
||||||
|
with expansion:
|
||||||
|
"smith < jones" == "smith < jones"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with greater-than
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "smith > jones" ) == "smith > jones" )
|
||||||
|
with expansion:
|
||||||
|
"smith > jones" == "smith > jones"
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" )
|
||||||
|
with expansion:
|
||||||
|
"smith ]]> jones"
|
||||||
|
==
|
||||||
|
"smith ]]> jones"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with quotes
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( stringWithQuotes ) == stringWithQuotes )
|
||||||
|
with expansion:
|
||||||
|
"don't "quote" me on that"
|
||||||
|
==
|
||||||
|
"don't "quote" me on that"
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" )
|
||||||
|
with expansion:
|
||||||
|
"don't "quote" me on that"
|
||||||
|
==
|
||||||
|
"don't "quote" me on that"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with control char (1)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "[\x01]" ) == "[]" )
|
||||||
|
with expansion:
|
||||||
|
"[]" == "[]"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
XmlEncode
|
||||||
|
string with control char (x7F)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
MiscTests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
MiscTests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( encode( "[\x7F]" ) == "[]" )
|
||||||
|
with expansion:
|
||||||
|
"[]" == "[]"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Process can be configured on command line
|
Process can be configured on command line
|
||||||
default - no arguments
|
default - no arguments
|
||||||
@ -8004,6 +8126,6 @@ with expansion:
|
|||||||
true
|
true
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 157 | 101 passed | 55 failed | 1 failed as expected
|
test cases: 158 | 102 passed | 55 failed | 1 failed as expected
|
||||||
assertions: 793 | 680 passed | 100 failed | 13 failed as expected
|
assertions: 803 | 690 passed | 100 failed | 13 failed as expected
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="all tests" errors="12" failures="88" tests="793" hostname="tbd" time="{duration}" timestamp="tbd">
|
<testsuite name="all tests" errors="12" failures="88" tests="803" hostname="tbd" time="{duration}" timestamp="tbd">
|
||||||
<testcase classname="global" name="toString(enum)" time="{duration}"/>
|
<testcase classname="global" name="toString(enum)" time="{duration}"/>
|
||||||
<testcase classname="global" name="toString(enum w/operator<<)" time="{duration}"/>
|
<testcase classname="global" name="toString(enum w/operator<<)" time="{duration}"/>
|
||||||
<testcase classname="global" name="toString(enum class)" time="{duration}"/>
|
<testcase classname="global" name="toString(enum class)" time="{duration}"/>
|
||||||
@ -463,6 +463,14 @@ MiscTests.cpp:<line number>
|
|||||||
<testcase classname="global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/>
|
<testcase classname="global" name="toString on const wchar_t pointer returns the string contents" time="{duration}"/>
|
||||||
<testcase classname="global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/>
|
<testcase classname="global" name="toString on wchar_t const pointer returns the string contents" time="{duration}"/>
|
||||||
<testcase classname="global" name="toString on wchar_t returns the string contents" time="{duration}"/>
|
<testcase classname="global" name="toString on wchar_t returns the string contents" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="normal string" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="empty string" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with ampersand" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with less-than" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with greater-than" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with quotes" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with control char (1)" time="{duration}"/>
|
||||||
|
<testcase classname="XmlEncode" name="string with control char (x7F)" time="{duration}"/>
|
||||||
<testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/>
|
<testcase classname="Process can be configured on command line" name="default - no arguments" time="{duration}"/>
|
||||||
<testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/>
|
<testcase classname="Process can be configured on command line" name="test lists/1 test" time="{duration}"/>
|
||||||
<testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/>
|
<testcase classname="Process can be configured on command line" name="test lists/Specify one test case exclusion using exclude:" time="{duration}"/>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
#include "catch_xmlwriter.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -381,6 +382,42 @@ TEST_CASE( "toString on wchar_t returns the string contents", "[toString]" ) {
|
|||||||
CHECK( result == "\"wide load\"" );
|
CHECK( result == "\"wide load\"" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::string encode( std::string const& str, Catch::XmlEncode::ForWhat forWhat = Catch::XmlEncode::ForTextNodes ) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << Catch::XmlEncode( str, forWhat );
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "XmlEncode" ) {
|
||||||
|
SECTION( "normal string" ) {
|
||||||
|
REQUIRE( encode( "normal string" ) == "normal string" );
|
||||||
|
}
|
||||||
|
SECTION( "empty string" ) {
|
||||||
|
REQUIRE( encode( "" ) == "" );
|
||||||
|
}
|
||||||
|
SECTION( "string with ampersand" ) {
|
||||||
|
REQUIRE( encode( "smith & jones" ) == "smith & jones" );
|
||||||
|
}
|
||||||
|
SECTION( "string with less-than" ) {
|
||||||
|
REQUIRE( encode( "smith < jones" ) == "smith < jones" );
|
||||||
|
}
|
||||||
|
SECTION( "string with greater-than" ) {
|
||||||
|
REQUIRE( encode( "smith > jones" ) == "smith > jones" );
|
||||||
|
REQUIRE( encode( "smith ]]> jones" ) == "smith ]]> jones" );
|
||||||
|
}
|
||||||
|
SECTION( "string with quotes" ) {
|
||||||
|
std::string stringWithQuotes = "don't \"quote\" me on that";
|
||||||
|
REQUIRE( encode( stringWithQuotes ) == stringWithQuotes );
|
||||||
|
REQUIRE( encode( stringWithQuotes, Catch::XmlEncode::ForAttributes ) == "don't "quote" me on that" );
|
||||||
|
}
|
||||||
|
SECTION( "string with control char (1)" ) {
|
||||||
|
REQUIRE( encode( "[\x01]" ) == "[]" );
|
||||||
|
}
|
||||||
|
SECTION( "string with control char (x7F)" ) {
|
||||||
|
REQUIRE( encode( "[\x7F]" ) == "[]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
|
//TEST_CASE( "Divide by Zero signal handler", "[.][sig]" ) {
|
||||||
// int i = 0;
|
// int i = 0;
|
||||||
// int x = 10/i; // This should cause the signal to fire
|
// int x = 10/i; // This should cause the signal to fire
|
||||||
|
Loading…
Reference in New Issue
Block a user