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
#define TWOBLUECUBES_CATCH_HPP_INCLUDED
#include "internal/catch_hub.hpp"
#include "internal/catch_registry.hpp"
#include "internal/catch_capture.hpp"
#include "internal/catch_section.hpp"

View File

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

View File

@ -18,7 +18,7 @@
namespace Catch
{
class JunitReporter : public Catch::ITestReporter
class JunitReporter : public Catch::IReporter
{
struct TestStats
{
@ -66,7 +66,7 @@ namespace Catch
public:
///////////////////////////////////////////////////////////////////////////
JunitReporter( const ReporterConfig& config = ReporterConfig() )
JunitReporter( const IReporterConfig& config )
: m_config( config ),
m_testSuiteStats( "AllTests" ),
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";
}
private: // ITestReporter
private: // IReporter
///////////////////////////////////////////////////////////////////////////
virtual void StartTesting()
@ -245,7 +245,7 @@ namespace Catch
}
private:
const ReporterConfig& m_config;
const IReporterConfig& m_config;
bool m_currentTestSuccess;
Stats m_testSuiteStats;

View File

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

View File

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

View File

@ -218,8 +218,7 @@ struct IResultListener
virtual void acceptExpression( const MutableResultInfo& resultInfo ) = 0;
virtual void acceptMessage( const std::string& msg ) = 0;
};
};
class ResultsCapture
{
@ -249,7 +248,6 @@ public:
}
private:
MutableResultInfo currentResult;
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
#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
#include "catch_testcaseinfo.hpp"
#include "catch_resultinfo.hpp"
#include "catch_common.h"
#include "catch_ireporterregistry.h"
#include <map>
#include <iostream>
#include <fstream>
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 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
class ReporterRegistry : public IReporterRegistry
{
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 );
if( it == m_factories.end() )
@ -153,10 +47,9 @@ namespace Catch
return it->second->create( config );
}
template<typename T>
void registerReporter( const std::string& name )
void registerReporter( const std::string& name, IReporterFactory* factory )
{
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;
@ -170,12 +63,25 @@ namespace Catch
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>
struct ReporterRegistrar
{
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;
std::size_t m_successes;
std::size_t m_failures;
ITestReporter* m_reporter;
IReporter* m_reporter;
std::vector<ScopedInfo*> m_scopedInfos;
std::vector<ResultInfo> m_info;
};

View File

@ -21,6 +21,59 @@
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
{
public:
@ -80,19 +133,19 @@ namespace Catch
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() )
setReporter( ReporterRegistry::instance().create( "basic", m_reporterConfig ) );
return m_reporter.get();
}
ITestReporter* getReporter() const
IReporter* getReporter() const
{
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;
ReporterConfig m_reporterConfig;
std::string m_message;