Refactored xml reporter in terms of xmlwriter and filled out new events

This commit is contained in:
Phil Nash 2010-12-10 20:01:40 +00:00
parent a35e4b5670
commit 68eec929e4
3 changed files with 127 additions and 39 deletions

View File

@ -15,7 +15,6 @@
#include "internal/catch_capture.hpp" #include "internal/catch_capture.hpp"
#include "internal/catch_reporter_registry.hpp" #include "internal/catch_reporter_registry.hpp"
#include "internal/catch_xmlwriter.hpp" #include "internal/catch_xmlwriter.hpp"
#include <iostream>
namespace Catch namespace Catch
{ {

View File

@ -14,7 +14,7 @@
#include "internal/catch_capture.hpp" #include "internal/catch_capture.hpp"
#include "internal/catch_reporter_registry.hpp" #include "internal/catch_reporter_registry.hpp"
#include <iostream> #include "internal/catch_xmlwriter.hpp"
namespace Catch namespace Catch
{ {
@ -35,19 +35,58 @@ namespace Catch
private: // ITestReporter private: // ITestReporter
virtual void StartTesting(){} ///////////////////////////////////////////////////////////////////////////
virtual void EndTesting( std::size_t succeeded, std::size_t failed ){(succeeded, failed);} virtual void StartTesting()
{
m_xml = XmlWriter( m_config.stream() );
m_xml.startElement( "AllTests" );
}
virtual void StartGroup( const std::string& groupName ){(groupName);} ///////////////////////////////////////////////////////////////////////////
virtual void EndGroup( const std::string& groupName, std::size_t succeeded, std::size_t failed ){(groupName, succeeded, failed);} virtual void EndTesting( std::size_t succeeded, std::size_t failed )
{
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", succeeded )
.writeAttribute( "failures", failed );
}
virtual void StartSection( const std::string& sectionName, const std::string description ){(sectionName,description);} ///////////////////////////////////////////////////////////////////////////
virtual void EndSection( const std::string& sectionName, std::size_t succeeded, std::size_t failed ){(sectionName, succeeded, failed);} virtual void StartGroup( const std::string& groupName )
{
m_xml.startElement( "Group" )
.writeAttribute( "name", groupName );
}
///////////////////////////////////////////////////////////////////////////
virtual void EndGroup( const std::string& groupName, std::size_t succeeded, std::size_t failed )
{
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", succeeded )
.writeAttribute( "failures", failed );
m_xml.endElement();
}
///////////////////////////////////////////////////////////////////////////
virtual void StartSection( const std::string& sectionName, const std::string description )
{
m_xml.startElement( "Section" )
.writeAttribute( "name", sectionName )
.writeAttribute( "description", description );
}
///////////////////////////////////////////////////////////////////////////
virtual void EndSection( const std::string& sectionName, std::size_t succeeded, std::size_t failed )
{
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes", succeeded )
.writeAttribute( "failures", failed );
m_xml.endElement();
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) virtual void StartTestCase( const Catch::TestCaseInfo& testInfo )
{ {
m_config.stream() << "<TestCase name='" << testInfo.getName() << "'>\n"; m_xml.startElement( "TestCase" ).writeAttribute( "name", testInfo.getName() );
m_currentTestSuccess = true; m_currentTestSuccess = true;
} }
@ -59,47 +98,54 @@ namespace Catch
if( resultInfo.hasExpression() ) if( resultInfo.hasExpression() )
{ {
m_config.stream() << "\t<Expression success='" << (resultInfo.ok() ? "true" : "false") << "' " m_xml.startElement( "Expression" )
<< "filename='" << resultInfo.getFilename() << "' line='" << resultInfo.getLine() << "'>\n" .writeAttribute( "success", resultInfo.ok() )
<< "\t\t<Original>" << resultInfo.getExpression() << "</Original>\n" .writeAttribute( "filename", resultInfo.getFilename() )
<< "\t\t<Expanded>" << resultInfo.getExpandedExpression() << "</Expanded>\n"; .writeAttribute( "line", resultInfo.getLine() );
m_xml.scopedElement( "Original" )
.writeText( resultInfo.getExpression() );
m_xml.scopedElement( "Expanded" )
.writeText( resultInfo.getExpandedExpression() );
m_currentTestSuccess |= resultInfo.ok(); m_currentTestSuccess |= resultInfo.ok();
} }
switch( resultInfo.getResultType() ) switch( resultInfo.getResultType() )
{ {
case ResultWas::ThrewException: case ResultWas::ThrewException:
if( resultInfo.hasExpression() ) m_xml.scopedElement( "Exception" )
m_config.stream() << "\t"; .writeText( resultInfo.getMessage() );
m_config.stream() << "\t<Exception>" << resultInfo.getMessage() << "</Exception>\n";
m_currentTestSuccess = false; m_currentTestSuccess = false;
break; break;
case ResultWas::Info: case ResultWas::Info:
m_config.stream() << "\t<Info>" << resultInfo.getMessage() << "</Info>\n"; m_xml.scopedElement( "Info" )
.writeText( resultInfo.getMessage() );
break; break;
case ResultWas::Warning: case ResultWas::Warning:
m_config.stream() << "\t<Warning>" << resultInfo.getMessage() << "</Warning>\n"; m_xml.scopedElement( "Warning" )
.writeText( resultInfo.getMessage() );
break; break;
case ResultWas::ExplicitFailure: case ResultWas::ExplicitFailure:
m_config.stream() << "\t<Failure>" << resultInfo.getMessage() << "</Failure>\n"; m_xml.scopedElement( "Failure" )
.writeText( resultInfo.getMessage() );
m_currentTestSuccess = false; m_currentTestSuccess = false;
break; break;
} }
if( resultInfo.hasExpression() ) if( resultInfo.hasExpression() )
{ m_xml.endElement();
m_config.stream() << "\t</Expression>\n";
}
} }
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void EndTestCase( const Catch::TestCaseInfo&, const std::string& stdOut, const std::string& stdErr ) virtual void EndTestCase( const Catch::TestCaseInfo&, const std::string& stdOut, const std::string& stdErr )
{ {
m_config.stream() << "\t<OverallResult success='" << (m_currentTestSuccess ? "true" : "false" ) << "/>\n"; m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
m_config.stream() << "</TestCase>" << std::endl; m_xml.endElement();
} }
private: private:
const ReporterConfig& m_config; const ReporterConfig& m_config;
bool m_currentTestSuccess; bool m_currentTestSuccess;
XmlWriter m_xml;
}; };
} // end namespace Catch } // end namespace Catch

View File

@ -11,6 +11,10 @@
#ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
#include <sstream>
#include <string>
#include <vector>
namespace Catch namespace Catch
{ {
class XmlWriter class XmlWriter
@ -42,15 +46,28 @@ namespace Catch
m_writer->writeText( text ); m_writer->writeText( text );
return *this; return *this;
} }
template<typename T>
ScopedElement& writeAttribute( const std::string& name, const T& attribute )
{
m_writer->writeAttribute( name, attribute );
return *this;
}
private: private:
mutable XmlWriter* m_writer; mutable XmlWriter* m_writer;
}; };
XmlWriter()
: m_tagIsOpen( false ),
m_needsNewline( false ),
m_os( &std::cout )
{
}
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 )
{ {
} }
@ -62,11 +79,27 @@ namespace Catch
} }
} }
XmlWriter& operator = ( const XmlWriter& other )
{
XmlWriter temp( other );
swap( temp );
return *this;
}
void swap( XmlWriter& other )
{
std::swap( m_tagIsOpen, other.m_tagIsOpen );
std::swap( m_needsNewline, other.m_needsNewline );
std::swap( m_tags, other.m_tags );
std::swap( m_indent, other.m_indent );
std::swap( m_os, other.m_os );
}
XmlWriter& startElement( const std::string& name ) XmlWriter& startElement( const std::string& name )
{ {
ensureTagClosed(); ensureTagClosed();
newlineIfNecessary(); newlineIfNecessary();
m_os << m_indent << "<" << name; stream() << m_indent << "<" << name;
m_tags.push_back( name ); m_tags.push_back( name );
m_indent += " "; m_indent += " ";
m_tagIsOpen = true; m_tagIsOpen = true;
@ -86,12 +119,12 @@ namespace Catch
m_indent = m_indent.substr( 0, m_indent.size()-2 ); m_indent = m_indent.substr( 0, m_indent.size()-2 );
if( m_tagIsOpen ) if( m_tagIsOpen )
{ {
m_os << "/>\n"; stream() << "/>\n";
m_tagIsOpen = false; m_tagIsOpen = false;
} }
else else
{ {
m_os << m_indent << "</" << m_tags.back() << ">\n"; stream() << m_indent << "</" << m_tags.back() << ">\n";
} }
m_tags.pop_back(); m_tags.pop_back();
return *this; return *this;
@ -101,19 +134,24 @@ namespace Catch
{ {
if( !name.empty() && !attribute.empty() ) if( !name.empty() && !attribute.empty() )
{ {
m_os << " " << name << "=\""; stream() << " " << name << "=\"";
writeEncodedText( attribute ); writeEncodedText( attribute );
m_os << "\""; stream() << "\"";
} }
return *this; return *this;
} }
XmlWriter& writeAttribute( const std::string& name, bool attribute )
{
stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
return *this;
}
template<typename T> template<typename T>
XmlWriter& writeAttribute( const std::string& name, const T& attribute ) XmlWriter& writeAttribute( const std::string& name, const T& attribute )
{ {
if( !name.empty() ) if( !name.empty() )
{ {
m_os << " " << name << "=\"" << attribute << "\""; stream() << " " << name << "=\"" << attribute << "\"";
} }
return *this; return *this;
} }
@ -125,7 +163,7 @@ namespace Catch
bool tagWasOpen = m_tagIsOpen; bool tagWasOpen = m_tagIsOpen;
ensureTagClosed(); ensureTagClosed();
if( tagWasOpen ) if( tagWasOpen )
m_os << m_indent; stream() << m_indent;
writeEncodedText( text ); writeEncodedText( text );
m_needsNewline = true; m_needsNewline = true;
} }
@ -135,7 +173,7 @@ namespace Catch
XmlWriter& writeComment( const std::string& text ) XmlWriter& writeComment( const std::string& text )
{ {
ensureTagClosed(); ensureTagClosed();
m_os << m_indent << "<!--" << text << "-->"; stream() << m_indent << "<!--" << text << "-->";
m_needsNewline = true; m_needsNewline = true;
return *this; return *this;
} }
@ -143,17 +181,22 @@ namespace Catch
XmlWriter& writeBlankLine() XmlWriter& writeBlankLine()
{ {
ensureTagClosed(); ensureTagClosed();
m_os << "\n"; stream() << "\n";
return *this; return *this;
} }
private: private:
std::ostream& stream()
{
return *m_os;
}
void ensureTagClosed() void ensureTagClosed()
{ {
if( m_tagIsOpen ) if( m_tagIsOpen )
{ {
m_os << ">\n"; stream() << ">\n";
m_tagIsOpen = false; m_tagIsOpen = false;
} }
} }
@ -162,7 +205,7 @@ namespace Catch
{ {
if( m_needsNewline ) if( m_needsNewline )
{ {
m_os << "\n"; stream() << "\n";
m_needsNewline = false; m_needsNewline = false;
} }
} }
@ -174,7 +217,7 @@ namespace Catch
!findReplaceableString( text, "&", "&amp;" ) && !findReplaceableString( text, "&", "&amp;" ) &&
!findReplaceableString( text, "\"", "&quote;" ) ) !findReplaceableString( text, "\"", "&quote;" ) )
{ {
m_os << text; stream() << text;
} }
} }
@ -183,7 +226,7 @@ namespace Catch
std::string::size_type pos = text.find_first_of( replaceWhat ); std::string::size_type pos = text.find_first_of( replaceWhat );
if( pos != std::string::npos ) if( pos != std::string::npos )
{ {
m_os << text.substr( 0, pos ) << replaceWith; stream() << text.substr( 0, pos ) << replaceWith;
writeEncodedText( text.substr( pos+1 ) ); writeEncodedText( text.substr( pos+1 ) );
return true; return true;
} }
@ -194,7 +237,7 @@ namespace Catch
bool m_needsNewline; bool m_needsNewline;
std::vector<std::string> m_tags; std::vector<std::string> m_tags;
std::string m_indent; std::string m_indent;
std::ostream& m_os; std::ostream* m_os;
}; };
} }