Refactored reporter related code into interface based design

This commit is contained in:
Phil Nash 2010-12-31 22:07:47 +00:00
parent 6ea8f298a4
commit e846e0744d
11 changed files with 273 additions and 135 deletions

View File

@ -26,6 +26,7 @@
#ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_HPP_INCLUDED #define TWOBLUECUBES_CATCH_HPP_INCLUDED
#include "internal/catch_hub.hpp"
#include "internal/catch_registry.hpp" #include "internal/catch_registry.hpp"
#include "internal/catch_capture.hpp" #include "internal/catch_capture.hpp"
#include "internal/catch_section.hpp" #include "internal/catch_section.hpp"

View File

@ -17,11 +17,11 @@
namespace Catch namespace Catch
{ {
class BasicReporter : public ITestReporter class BasicReporter : public IReporter
{ {
public: public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
BasicReporter( const ReporterConfig& config ) BasicReporter( const IReporterConfig& config )
: m_config( config ) : m_config( config )
{ {
} }
@ -47,7 +47,7 @@ namespace Catch
m_config.stream() << succeeded << " test(s) passed but " << failed << " test(s) failed"; m_config.stream() << succeeded << " test(s) passed but " << failed << " test(s) failed";
} }
private: // ITestReporter private: // IReporter
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTesting() virtual void StartTesting()
@ -166,7 +166,7 @@ namespace Catch
} }
private: private:
const ReporterConfig& m_config; const IReporterConfig& m_config;
bool m_firstSectionInTestCase; bool m_firstSectionInTestCase;
}; };

View File

@ -18,7 +18,7 @@
namespace Catch namespace Catch
{ {
class JunitReporter : public Catch::ITestReporter class JunitReporter : public Catch::IReporter
{ {
struct TestStats struct TestStats
{ {
@ -66,7 +66,7 @@ namespace Catch
public: public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
JunitReporter( const ReporterConfig& config = ReporterConfig() ) JunitReporter( const IReporterConfig& config )
: m_config( config ), : m_config( config ),
m_testSuiteStats( "AllTests" ), m_testSuiteStats( "AllTests" ),
m_currentStats( &m_testSuiteStats ) m_currentStats( &m_testSuiteStats )
@ -79,7 +79,7 @@ namespace Catch
return "Reports test results in an XML format that looks like Ant's junitreport target"; return "Reports test results in an XML format that looks like Ant's junitreport target";
} }
private: // ITestReporter private: // IReporter
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTesting() virtual void StartTesting()
@ -245,7 +245,7 @@ namespace Catch
} }
private: private:
const ReporterConfig& m_config; const IReporterConfig& m_config;
bool m_currentTestSuccess; bool m_currentTestSuccess;
Stats m_testSuiteStats; Stats m_testSuiteStats;

View File

@ -18,11 +18,11 @@
namespace Catch namespace Catch
{ {
class XmlReporter : public Catch::ITestReporter class XmlReporter : public Catch::IReporter
{ {
public: public:
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
XmlReporter( const ReporterConfig& config = ReporterConfig() ) XmlReporter( const IReporterConfig& config )
: m_config( config ) : m_config( config )
{ {
} }
@ -33,7 +33,7 @@ namespace Catch
return "Reports test results as an XML document"; return "Reports test results as an XML document";
} }
private: // ITestReporter private: // IReporter
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
virtual void StartTesting() virtual void StartTesting()
@ -145,7 +145,7 @@ namespace Catch
} }
private: private:
const ReporterConfig& m_config; const IReporterConfig& m_config;
bool m_currentTestSuccess; bool m_currentTestSuccess;
XmlWriter m_xml; XmlWriter m_xml;
}; };

View File

@ -19,6 +19,8 @@
#include "catch_reporter_xml.hpp" #include "catch_reporter_xml.hpp"
#include "catch_reporter_junit.hpp" #include "catch_reporter_junit.hpp"
#include <fstream>
namespace Catch namespace Catch
{ {
inline int Main( int argc, char * const argv[] ) inline int Main( int argc, char * const argv[] )

View File

@ -220,7 +220,6 @@ struct IResultListener
}; };
class ResultsCapture class ResultsCapture
{ {
private: private:
@ -249,7 +248,6 @@ public:
} }
private: private:
MutableResultInfo currentResult;
IResultListener* m_listener; IResultListener* m_listener;
}; };

49
internal/catch_hub.hpp Normal file
View File

@ -0,0 +1,49 @@
/*
* catch_hub.hpp
* Test
*
* Created by Phil on 31/12/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_HUB_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_HUB_HPP_INCLUDED
#include <memory>
namespace Catch
{
struct IResultListener;
struct IReporterRegistry;
struct ITestCaseRegistry;
class Hub
{
public:
Hub();
static IResultListener* getListener();
static IReporterRegistry* getReporterRegistry();
static ITestCaseRegistry* getTestCaseRegistry();
private:
std::auto_ptr<IReporterRegistry> m_reporterRegistry;
};
}
////// -- new file --
#include "catch_reporter_registry.hpp"
namespace Catch
{
inline Hub::Hub()
: m_reporterRegistry( new ReporterRegistry )
{
}
}
#endif // TWOBLUECUBES_CATCH_HUB_HPP_INCLUDED

View File

@ -0,0 +1,129 @@
/*
* catch_ireporterregistry.h
* Test
*
* Created by Phil on 31/12/2010.
* Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#ifndef TWOBLUECUBES_CATCH_IREPORTERREGISTRY_INCLUDED
#define TWOBLUECUBES_CATCH_IREPORTERREGISTRY_INCLUDED
#include "catch_common.h"
#include <string>
#include <ostream>
namespace Catch
{
///////////////////////////////////////////////////////////////////////////
struct IReporterConfig
{
virtual std::ostream& stream
() const = 0;
virtual bool includeSuccessfulResults
() const = 0;
};
class TestCaseInfo;
class ResultInfo;
///////////////////////////////////////////////////////////////////////////
struct IReporter : NonCopyable
{
virtual ~IReporter
(){}
virtual void StartTesting
() = 0;
virtual void EndTesting
( std::size_t succeeded,
std::size_t failed
) = 0;
virtual void StartGroup
( const std::string& groupName
) = 0;
virtual void EndGroup
( const std::string& groupName,
std::size_t succeeded,
std::size_t failed
) = 0;
virtual void StartSection
( const std::string& sectionName,
const std::string description
) = 0;
virtual void EndSection
( const std::string& sectionName,
std::size_t succeeded,
std::size_t failed
) = 0;
virtual void StartTestCase
( const TestCaseInfo& testInfo
) = 0;
virtual void EndTestCase
( const TestCaseInfo& testInfo,
const std::string& stdOut,
const std::string& stdErr
) = 0;
virtual void Result
( const ResultInfo& result
) = 0;
};
///////////////////////////////////////////////////////////////////////////
struct IReporterFactory
{
virtual ~IReporterFactory
(){}
virtual IReporter* create
( const IReporterConfig& config
) const = 0;
virtual std::string getDescription
() const = 0;
};
///////////////////////////////////////////////////////////////////////////
struct IReporterRegistry
{
virtual ~IReporterRegistry
(){}
virtual IReporter* create
( const std::string& name,
const IReporterConfig& config
) const = 0;
virtual void registerReporter
( const std::string& name,
IReporterFactory* factory
) = 0;
};
///////////////////////////////////////////////////////////////////////////
inline std::string trim( const std::string& str )
{
std::string::size_type start = str.find_first_not_of( "\n\r\t " );
std::string::size_type end = str.find_last_not_of( "\n\r\t " );
return start < end ? str.substr( start, 1+end-start ) : "";
}
}
#endif // TWOBLUECUBES_CATCH_IREPORTERREGISTRY_INCLUDED

View File

@ -12,120 +12,14 @@
#ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #ifndef TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#include "catch_testcaseinfo.hpp" #include "catch_ireporterregistry.h"
#include "catch_resultinfo.hpp"
#include "catch_common.h"
#include <map> #include <map>
#include <iostream>
#include <fstream>
namespace Catch namespace Catch
{ {
///////////////////////////////////////////////////////////////////////////
static std::string trim( const std::string& str )
{
std::string::size_type start = str.find_first_not_of( "\n\r\t " );
std::string::size_type end = str.find_last_not_of( "\n\r\t " );
return start < end ? str.substr( start, 1+end-start ) : ""; class ReporterRegistry : public IReporterRegistry
}
class ReporterConfig
{
private:
ReporterConfig( const ReporterConfig& other );
ReporterConfig& operator = ( const ReporterConfig& other );
public:
struct Include { enum What
{
FailedOnly,
SuccessfulResults
}; };
public:
///////////////////////////////////////////////////////////////////////////
explicit ReporterConfig( Include::What includeWhat = Include::FailedOnly )
: m_includeWhat( includeWhat ),
m_os( std::cout.rdbuf() )
{
}
///////////////////////////////////////////////////////////////////////////
bool includeSuccessfulResults() const
{
return m_includeWhat == Include::SuccessfulResults;
}
///////////////////////////////////////////////////////////////////////////
void setIncludeWhat(Include::What includeWhat )
{
m_includeWhat = includeWhat;
}
///////////////////////////////////////////////////////////////////////////
std::ostream& stream() const
{
return m_os;
}
///////////////////////////////////////////////////////////////////////////
void setStreamBuf( std::streambuf* buf )
{
m_os.rdbuf( buf );
}
private:
Include::What m_includeWhat;
mutable std::ostream m_os;
};
struct ITestReporter : NonCopyable
{
virtual ~ITestReporter(){}
virtual void StartTesting() = 0;
virtual void EndTesting( std::size_t succeeded, std::size_t failed ) = 0;
virtual void StartGroup( const std::string& groupName ) = 0;
virtual void EndGroup( const std::string& groupName, std::size_t succeeded, std::size_t failed ) = 0;
virtual void StartSection( const std::string& sectionName, const std::string description ) = 0;
virtual void EndSection( const std::string& sectionName, std::size_t succeeded, std::size_t failed ) = 0;
virtual void StartTestCase( const TestCaseInfo& testInfo ) = 0;
virtual void EndTestCase( const TestCaseInfo& testInfo, const std::string& stdOut, const std::string& stdErr ) = 0;
virtual void Result( const ResultInfo& result ) = 0;
};
struct IReporterFactory
{
virtual ~IReporterFactory(){}
virtual ITestReporter* create( const ReporterConfig& config ) = 0;
virtual std::string getDescription() const = 0;
};
template<typename T>
class ReporterFactory : public IReporterFactory
{
virtual ITestReporter* create( const ReporterConfig& config )
{
return new T( config );
}
virtual std::string getDescription() const
{
return T::getDescription();
}
};
class ReporterRegistry
{ {
public: public:
@ -145,7 +39,7 @@ namespace Catch
} }
} }
ITestReporter* create( const std::string& name, const ReporterConfig& config ) virtual IReporter* create( const std::string& name, const IReporterConfig& config ) const
{ {
FactoryMap::const_iterator it = m_factories.find( name ); FactoryMap::const_iterator it = m_factories.find( name );
if( it == m_factories.end() ) if( it == m_factories.end() )
@ -153,10 +47,9 @@ namespace Catch
return it->second->create( config ); return it->second->create( config );
} }
template<typename T> void registerReporter( const std::string& name, IReporterFactory* factory )
void registerReporter( const std::string& name )
{ {
m_factories.insert( std::make_pair( name, new ReporterFactory<T>() ) ); m_factories.insert( std::make_pair( name, factory ) );
} }
typedef std::map<std::string, IReporterFactory*> FactoryMap; typedef std::map<std::string, IReporterFactory*> FactoryMap;
@ -170,12 +63,25 @@ namespace Catch
FactoryMap m_factories; FactoryMap m_factories;
}; };
template<typename T>
class ReporterFactory : public IReporterFactory
{
virtual IReporter* create( const IReporterConfig& config ) const
{
return new T( config );
}
virtual std::string getDescription() const
{
return T::getDescription();
}
};
template<typename T> template<typename T>
struct ReporterRegistrar struct ReporterRegistrar
{ {
ReporterRegistrar( const std::string& name ) ReporterRegistrar( const std::string& name )
{ {
ReporterRegistry::instance().registerReporter<T>( name ); ReporterRegistry::instance().registerReporter( name, new ReporterFactory<T>() );
} }
}; };
} }

View File

@ -251,7 +251,7 @@ namespace Catch
const RunnerConfig& m_config; const RunnerConfig& m_config;
std::size_t m_successes; std::size_t m_successes;
std::size_t m_failures; std::size_t m_failures;
ITestReporter* m_reporter; IReporter* m_reporter;
std::vector<ScopedInfo*> m_scopedInfos; std::vector<ScopedInfo*> m_scopedInfos;
std::vector<ResultInfo> m_info; std::vector<ResultInfo> m_info;
}; };

View File

@ -21,6 +21,59 @@
namespace Catch namespace Catch
{ {
class ReporterConfig : public IReporterConfig
{
private:
ReporterConfig( const ReporterConfig& other );
ReporterConfig& operator = ( const ReporterConfig& other );
public:
struct Include { enum What
{
FailedOnly,
SuccessfulResults
}; };
public:
///////////////////////////////////////////////////////////////////////////
explicit ReporterConfig( Include::What includeWhat = Include::FailedOnly )
: m_includeWhat( includeWhat ),
m_os( std::cout.rdbuf() )
{
}
///////////////////////////////////////////////////////////////////////////
virtual bool includeSuccessfulResults() const
{
return m_includeWhat == Include::SuccessfulResults;
}
///////////////////////////////////////////////////////////////////////////
void setIncludeWhat(Include::What includeWhat )
{
m_includeWhat = includeWhat;
}
///////////////////////////////////////////////////////////////////////////
virtual std::ostream& stream() const
{
return m_os;
}
///////////////////////////////////////////////////////////////////////////
void setStreamBuf( std::streambuf* buf )
{
m_os.rdbuf( buf );
}
private:
Include::What m_includeWhat;
mutable std::ostream m_os;
};
class RunnerConfig class RunnerConfig
{ {
public: public:
@ -80,19 +133,19 @@ namespace Catch
m_message = errorMessage + "\n\n" + "Usage: ..."; m_message = errorMessage + "\n\n" + "Usage: ...";
} }
void setReporter( ITestReporter* reporter ) void setReporter( IReporter* reporter )
{ {
m_reporter = std::auto_ptr<ITestReporter>( reporter ); m_reporter = std::auto_ptr<IReporter>( reporter );
} }
ITestReporter* getReporter() IReporter* getReporter()
{ {
if( !m_reporter.get() ) if( !m_reporter.get() )
setReporter( ReporterRegistry::instance().create( "basic", m_reporterConfig ) ); setReporter( ReporterRegistry::instance().create( "basic", m_reporterConfig ) );
return m_reporter.get(); return m_reporter.get();
} }
ITestReporter* getReporter() const IReporter* getReporter() const
{ {
return const_cast<RunnerConfig*>( this )->getReporter(); return const_cast<RunnerConfig*>( this )->getReporter();
} }
@ -133,7 +186,7 @@ namespace Catch
} }
std::auto_ptr<ITestReporter> m_reporter; std::auto_ptr<IReporter> m_reporter;
std::string m_filename; std::string m_filename;
ReporterConfig m_reporterConfig; ReporterConfig m_reporterConfig;
std::string m_message; std::string m_message;