mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-30 01:03:30 +01:00
Removed zombie files
These files were removed from the Catch2 branch, and crept back in when Catch2 merged with master
This commit is contained in:
parent
53f6d3fc8e
commit
4acf112c19
@ -1,272 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 31/10/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_RUNNER_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "internal/catch_commandline.hpp"
|
|
||||||
#include "internal/catch_list.hpp"
|
|
||||||
#include "internal/catch_run_context.hpp"
|
|
||||||
#include "internal/catch_test_spec.hpp"
|
|
||||||
#include "internal/catch_version.h"
|
|
||||||
#include "internal/catch_text.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) {
|
|
||||||
Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() );
|
|
||||||
if( !reporter ) {
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "No reporter registered with name: '" << reporterName << "'";
|
|
||||||
throw std::domain_error( oss.str() );
|
|
||||||
}
|
|
||||||
return reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(CATCH_CONFIG_DEFAULT_REPORTER)
|
|
||||||
#define CATCH_CONFIG_DEFAULT_REPORTER "console"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) {
|
|
||||||
std::vector<std::string> reporters = config->getReporterNames();
|
|
||||||
if( reporters.empty() )
|
|
||||||
reporters.push_back( CATCH_CONFIG_DEFAULT_REPORTER );
|
|
||||||
|
|
||||||
Ptr<IStreamingReporter> reporter;
|
|
||||||
for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end();
|
|
||||||
it != itEnd;
|
|
||||||
++it )
|
|
||||||
reporter = addReporter( reporter, createReporter( *it, config ) );
|
|
||||||
return reporter;
|
|
||||||
}
|
|
||||||
Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) {
|
|
||||||
IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners();
|
|
||||||
for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end();
|
|
||||||
it != itEnd;
|
|
||||||
++it )
|
|
||||||
reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) );
|
|
||||||
return reporters;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Totals runTests( Ptr<Config> const& config ) {
|
|
||||||
|
|
||||||
Ptr<IConfig const> iconfig = config.get();
|
|
||||||
|
|
||||||
Ptr<IStreamingReporter> reporter = makeReporter( config );
|
|
||||||
reporter = addListeners( iconfig, reporter );
|
|
||||||
|
|
||||||
RunContext context( iconfig, reporter );
|
|
||||||
|
|
||||||
Totals totals;
|
|
||||||
|
|
||||||
context.testGroupStarting( config->name(), 1, 1 );
|
|
||||||
|
|
||||||
TestSpec testSpec = config->testSpec();
|
|
||||||
if( !testSpec.hasFilters() )
|
|
||||||
testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
|
|
||||||
|
|
||||||
std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig );
|
|
||||||
for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end();
|
|
||||||
it != itEnd;
|
|
||||||
++it ) {
|
|
||||||
if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) )
|
|
||||||
totals += context.runTest( *it );
|
|
||||||
else
|
|
||||||
reporter->skipTest( *it );
|
|
||||||
}
|
|
||||||
|
|
||||||
context.testGroupEnded( iconfig->name(), totals, 1, 1 );
|
|
||||||
return totals;
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyFilenamesAsTags( IConfig const& config ) {
|
|
||||||
std::vector<TestCase> const& tests = getAllTestCasesSorted( config );
|
|
||||||
for(std::size_t i = 0; i < tests.size(); ++i ) {
|
|
||||||
TestCase& test = const_cast<TestCase&>( tests[i] );
|
|
||||||
std::set<std::string> tags = test.tags;
|
|
||||||
|
|
||||||
std::string filename = test.lineInfo.file;
|
|
||||||
std::string::size_type lastSlash = filename.find_last_of( "\\/" );
|
|
||||||
if( lastSlash != std::string::npos )
|
|
||||||
filename = filename.substr( lastSlash+1 );
|
|
||||||
|
|
||||||
std::string::size_type lastDot = filename.find_last_of( '.' );
|
|
||||||
if( lastDot != std::string::npos )
|
|
||||||
filename = filename.substr( 0, lastDot );
|
|
||||||
|
|
||||||
tags.insert( '#' + filename );
|
|
||||||
setTags( test, tags );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Session : NonCopyable {
|
|
||||||
static bool alreadyInstantiated;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
|
|
||||||
|
|
||||||
Session()
|
|
||||||
: m_cli( makeCommandLineParser() ) {
|
|
||||||
if( alreadyInstantiated ) {
|
|
||||||
std::string msg = "Only one instance of Catch::Session can ever be used";
|
|
||||||
Catch::cerr() << msg << std::endl;
|
|
||||||
throw std::logic_error( msg );
|
|
||||||
}
|
|
||||||
alreadyInstantiated = true;
|
|
||||||
}
|
|
||||||
~Session() {
|
|
||||||
Catch::cleanUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
void showHelp( std::string const& processName ) {
|
|
||||||
Catch::cout() << "\nCatch v" << libraryVersion() << "\n";
|
|
||||||
|
|
||||||
m_cli.usage( Catch::cout(), processName );
|
|
||||||
Catch::cout() << "For more detail usage please see the project docs\n" << std::endl;
|
|
||||||
}
|
|
||||||
void libIdentify() {
|
|
||||||
Catch::cout()
|
|
||||||
<< std::left << std::setw(16) << "description: " << "A Catch test executable\n"
|
|
||||||
<< std::left << std::setw(16) << "category: " << "testframework\n"
|
|
||||||
<< std::left << std::setw(16) << "framework: " << "Catch Test\n"
|
|
||||||
<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
|
|
||||||
try {
|
|
||||||
m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
|
|
||||||
m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData );
|
|
||||||
if( m_configData.showHelp )
|
|
||||||
showHelp( m_configData.processName );
|
|
||||||
if( m_configData.libIdentify )
|
|
||||||
libIdentify();
|
|
||||||
m_config.reset();
|
|
||||||
}
|
|
||||||
catch( std::exception& ex ) {
|
|
||||||
{
|
|
||||||
Colour colourGuard( Colour::Red );
|
|
||||||
Catch::cerr()
|
|
||||||
<< "\nError(s) in input:\n"
|
|
||||||
<< Text( ex.what(), TextAttributes().setIndent(2) )
|
|
||||||
<< "\n\n";
|
|
||||||
}
|
|
||||||
m_cli.usage( Catch::cout(), m_configData.processName );
|
|
||||||
return (std::numeric_limits<int>::max)();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void useConfigData( ConfigData const& _configData ) {
|
|
||||||
m_configData = _configData;
|
|
||||||
m_config.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
int run( int argc, char const* const* const argv ) {
|
|
||||||
|
|
||||||
int returnCode = applyCommandLine( argc, argv );
|
|
||||||
if( returnCode == 0 )
|
|
||||||
returnCode = run();
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WIN32) && defined(UNICODE)
|
|
||||||
int run( int argc, wchar_t const* const* const argv ) {
|
|
||||||
|
|
||||||
char **utf8Argv = new char *[ argc ];
|
|
||||||
|
|
||||||
for ( int i = 0; i < argc; ++i ) {
|
|
||||||
int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
|
|
||||||
|
|
||||||
utf8Argv[ i ] = new char[ bufSize ];
|
|
||||||
|
|
||||||
WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
int returnCode = applyCommandLine( argc, utf8Argv );
|
|
||||||
if( returnCode == 0 )
|
|
||||||
returnCode = run();
|
|
||||||
|
|
||||||
for ( int i = 0; i < argc; ++i )
|
|
||||||
delete [] utf8Argv[ i ];
|
|
||||||
|
|
||||||
delete [] utf8Argv;
|
|
||||||
|
|
||||||
return returnCode;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int run() {
|
|
||||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
|
|
||||||
Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
|
|
||||||
static_cast<void>(std::getchar());
|
|
||||||
}
|
|
||||||
int exitCode = runInternal();
|
|
||||||
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
|
|
||||||
Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
|
|
||||||
static_cast<void>(std::getchar());
|
|
||||||
}
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Clara::CommandLine<ConfigData> const& cli() const {
|
|
||||||
return m_cli;
|
|
||||||
}
|
|
||||||
std::vector<Clara::Parser::Token> const& unusedTokens() const {
|
|
||||||
return m_unusedTokens;
|
|
||||||
}
|
|
||||||
ConfigData& configData() {
|
|
||||||
return m_configData;
|
|
||||||
}
|
|
||||||
Config& config() {
|
|
||||||
if( !m_config )
|
|
||||||
m_config = new Config( m_configData );
|
|
||||||
return *m_config;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
|
|
||||||
int runInternal() {
|
|
||||||
if( m_configData.showHelp || m_configData.libIdentify )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
config(); // Force config to be constructed
|
|
||||||
|
|
||||||
seedRng( *m_config );
|
|
||||||
|
|
||||||
if( m_configData.filenamesAsTags )
|
|
||||||
applyFilenamesAsTags( *m_config );
|
|
||||||
|
|
||||||
// Handle list request
|
|
||||||
if( Option<std::size_t> listed = list( config() ) )
|
|
||||||
return static_cast<int>( *listed );
|
|
||||||
|
|
||||||
return static_cast<int>( runTests( m_config ).assertions.failed );
|
|
||||||
}
|
|
||||||
catch( std::exception& ex ) {
|
|
||||||
Catch::cerr() << ex.what() << std::endl;
|
|
||||||
return (std::numeric_limits<int>::max)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Clara::CommandLine<ConfigData> m_cli;
|
|
||||||
std::vector<Clara::Parser::Token> m_unusedTokens;
|
|
||||||
ConfigData m_configData;
|
|
||||||
Ptr<Config> m_config;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Session::alreadyInstantiated = false;
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
|
|
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 28/04/2011.
|
|
||||||
* 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_APPROX_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_tostring.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
|
||||||
#include <type_traits>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
namespace Detail {
|
|
||||||
|
|
||||||
class Approx {
|
|
||||||
public:
|
|
||||||
explicit Approx ( double value )
|
|
||||||
: m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
|
|
||||||
m_margin( 0.0 ),
|
|
||||||
m_scale( 1.0 ),
|
|
||||||
m_value( value )
|
|
||||||
{}
|
|
||||||
|
|
||||||
static Approx custom() {
|
|
||||||
return Approx( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS)
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
Approx operator()( T value ) {
|
|
||||||
Approx approx( static_cast<double>(value) );
|
|
||||||
approx.epsilon( m_epsilon );
|
|
||||||
approx.margin( m_margin );
|
|
||||||
approx.scale( m_scale );
|
|
||||||
return approx;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
explicit Approx( T value ): Approx(static_cast<double>(value))
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator == ( const T& lhs, Approx const& rhs ) {
|
|
||||||
// Thanks to Richard Harris for his help refining this formula
|
|
||||||
auto lhs_v = double(lhs);
|
|
||||||
bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value)));
|
|
||||||
if (relativeOK) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::fabs(lhs_v - rhs.m_value) <= rhs.m_margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator == ( Approx const& lhs, const T& rhs ) {
|
|
||||||
return operator==( rhs, lhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator != ( T lhs, Approx const& rhs ) {
|
|
||||||
return !operator==( lhs, rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator != ( Approx const& lhs, T rhs ) {
|
|
||||||
return !operator==( rhs, lhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator <= ( T lhs, Approx const& rhs ) {
|
|
||||||
return double(lhs) < rhs.m_value || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator <= ( Approx const& lhs, T rhs ) {
|
|
||||||
return lhs.m_value < double(rhs) || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator >= ( T lhs, Approx const& rhs ) {
|
|
||||||
return double(lhs) > rhs.m_value || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
friend bool operator >= ( Approx const& lhs, T rhs ) {
|
|
||||||
return lhs.m_value > double(rhs) || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
Approx& epsilon( T newEpsilon ) {
|
|
||||||
m_epsilon = double(newEpsilon);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
Approx& margin( T newMargin ) {
|
|
||||||
m_margin = double(newMargin);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
|
|
||||||
Approx& scale( T newScale ) {
|
|
||||||
m_scale = double(newScale);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
Approx operator()( double value ) {
|
|
||||||
Approx approx( value );
|
|
||||||
approx.epsilon( m_epsilon );
|
|
||||||
approx.margin( m_margin );
|
|
||||||
approx.scale( m_scale );
|
|
||||||
return approx;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
friend bool operator == ( double lhs, Approx const& rhs ) {
|
|
||||||
// Thanks to Richard Harris for his help refining this formula
|
|
||||||
bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) );
|
|
||||||
if (relativeOK) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return std::fabs(lhs - rhs.m_value) <= rhs.m_margin;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator == ( Approx const& lhs, double rhs ) {
|
|
||||||
return operator==( rhs, lhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator != ( double lhs, Approx const& rhs ) {
|
|
||||||
return !operator==( lhs, rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator != ( Approx const& lhs, double rhs ) {
|
|
||||||
return !operator==( rhs, lhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator <= ( double lhs, Approx const& rhs ) {
|
|
||||||
return lhs < rhs.m_value || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator <= ( Approx const& lhs, double rhs ) {
|
|
||||||
return lhs.m_value < rhs || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator >= ( double lhs, Approx const& rhs ) {
|
|
||||||
return lhs > rhs.m_value || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator >= ( Approx const& lhs, double rhs ) {
|
|
||||||
return lhs.m_value > rhs || lhs == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Approx& epsilon( double newEpsilon ) {
|
|
||||||
m_epsilon = newEpsilon;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Approx& margin( double newMargin ) {
|
|
||||||
m_margin = newMargin;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Approx& scale( double newScale ) {
|
|
||||||
m_scale = newScale;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::string toString() const {
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "Approx( " << Catch::toString( m_value ) << " )";
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
double m_epsilon;
|
|
||||||
double m_margin;
|
|
||||||
double m_scale;
|
|
||||||
double m_value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 8/8/12
|
|
||||||
* Copyright 2012 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_ASSERTIONRESULT_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_assertionresult.h"
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
|
|
||||||
AssertionInfo::AssertionInfo():macroName(""), capturedExpression(""), resultDisposition(ResultDisposition::Normal), secondArg(""){}
|
|
||||||
|
|
||||||
AssertionInfo::AssertionInfo( char const * _macroName,
|
|
||||||
SourceLineInfo const& _lineInfo,
|
|
||||||
char const * _capturedExpression,
|
|
||||||
ResultDisposition::Flags _resultDisposition,
|
|
||||||
char const * _secondArg)
|
|
||||||
: macroName( _macroName ),
|
|
||||||
lineInfo( _lineInfo ),
|
|
||||||
capturedExpression( _capturedExpression ),
|
|
||||||
resultDisposition( _resultDisposition ),
|
|
||||||
secondArg( _secondArg )
|
|
||||||
{}
|
|
||||||
|
|
||||||
AssertionResult::AssertionResult() {}
|
|
||||||
|
|
||||||
AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
|
|
||||||
: m_info( info ),
|
|
||||||
m_resultData( data )
|
|
||||||
{}
|
|
||||||
|
|
||||||
AssertionResult::~AssertionResult() {}
|
|
||||||
|
|
||||||
// Result was a success
|
|
||||||
bool AssertionResult::succeeded() const {
|
|
||||||
return Catch::isOk( m_resultData.resultType );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result was a success, or failure is suppressed
|
|
||||||
bool AssertionResult::isOk() const {
|
|
||||||
return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultWas::OfType AssertionResult::getResultType() const {
|
|
||||||
return m_resultData.resultType;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssertionResult::hasExpression() const {
|
|
||||||
return m_info.capturedExpression[0] != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssertionResult::hasMessage() const {
|
|
||||||
return !m_resultData.message.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string capturedExpressionWithSecondArgument( char const * capturedExpression, char const * secondArg ) {
|
|
||||||
return (secondArg[0] == 0 || secondArg[0] == '"' && secondArg[1] == '"')
|
|
||||||
? capturedExpression
|
|
||||||
: std::string(capturedExpression) + ", " + secondArg;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssertionResult::getExpression() const {
|
|
||||||
if( isFalseTest( m_info.resultDisposition ) )
|
|
||||||
return "!(" + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + ")";
|
|
||||||
else
|
|
||||||
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
|
|
||||||
}
|
|
||||||
std::string AssertionResult::getExpressionInMacro() const {
|
|
||||||
if( m_info.macroName[0] == 0 )
|
|
||||||
return capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg);
|
|
||||||
else
|
|
||||||
return std::string(m_info.macroName) + "( " + capturedExpressionWithSecondArgument(m_info.capturedExpression, m_info.secondArg) + " )";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssertionResult::hasExpandedExpression() const {
|
|
||||||
return hasExpression() && getExpandedExpression() != getExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssertionResult::getExpandedExpression() const {
|
|
||||||
return m_resultData.reconstructExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssertionResult::getMessage() const {
|
|
||||||
return m_resultData.message;
|
|
||||||
}
|
|
||||||
SourceLineInfo AssertionResult::getSourceInfo() const {
|
|
||||||
return m_info.lineInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssertionResult::getTestMacroName() const {
|
|
||||||
return m_info.macroName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssertionResult::discardDecomposedExpression() const {
|
|
||||||
m_resultData.decomposedExpression = CATCH_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssertionResult::expandDecomposedExpression() const {
|
|
||||||
m_resultData.reconstructExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
|
@ -1,240 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 02/11/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_COMMANDLINE_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_config.hpp"
|
|
||||||
#include "catch_common.h"
|
|
||||||
#include "catch_clara.h"
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
|
|
||||||
inline void abortAfterX( ConfigData& config, int x ) {
|
|
||||||
if( x < 1 )
|
|
||||||
throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
|
|
||||||
config.abortAfter = x;
|
|
||||||
}
|
|
||||||
inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
|
|
||||||
inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); }
|
|
||||||
inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); }
|
|
||||||
|
|
||||||
inline void addWarning( ConfigData& config, std::string const& _warning ) {
|
|
||||||
if( _warning == "NoAssertions" )
|
|
||||||
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
|
|
||||||
else
|
|
||||||
throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' );
|
|
||||||
}
|
|
||||||
inline void setOrder( ConfigData& config, std::string const& order ) {
|
|
||||||
if( startsWith( "declared", order ) )
|
|
||||||
config.runOrder = RunTests::InDeclarationOrder;
|
|
||||||
else if( startsWith( "lexical", order ) )
|
|
||||||
config.runOrder = RunTests::InLexicographicalOrder;
|
|
||||||
else if( startsWith( "random", order ) )
|
|
||||||
config.runOrder = RunTests::InRandomOrder;
|
|
||||||
else
|
|
||||||
throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
|
|
||||||
}
|
|
||||||
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
|
|
||||||
if( seed == "time" ) {
|
|
||||||
config.rngSeed = static_cast<unsigned int>( std::time(0) );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << seed;
|
|
||||||
ss >> config.rngSeed;
|
|
||||||
if( ss.fail() )
|
|
||||||
throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inline void setVerbosity( ConfigData& config, int level ) {
|
|
||||||
// !TBD: accept strings?
|
|
||||||
config.verbosity = static_cast<Verbosity::Level>( level );
|
|
||||||
}
|
|
||||||
inline void setShowDurations( ConfigData& config, bool _showDurations ) {
|
|
||||||
config.showDurations = _showDurations
|
|
||||||
? ShowDurations::Always
|
|
||||||
: ShowDurations::Never;
|
|
||||||
}
|
|
||||||
inline void setUseColour( ConfigData& config, std::string const& value ) {
|
|
||||||
std::string mode = toLower( value );
|
|
||||||
|
|
||||||
if( mode == "yes" )
|
|
||||||
config.useColour = UseColour::Yes;
|
|
||||||
else if( mode == "no" )
|
|
||||||
config.useColour = UseColour::No;
|
|
||||||
else if( mode == "auto" )
|
|
||||||
config.useColour = UseColour::Auto;
|
|
||||||
else
|
|
||||||
throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
|
|
||||||
}
|
|
||||||
inline void setWaitForKeypress( ConfigData& config, std::string const& keypress ) {
|
|
||||||
std::string keypressLc = toLower( keypress );
|
|
||||||
if( keypressLc == "start" )
|
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeStart;
|
|
||||||
else if( keypressLc == "exit" )
|
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeExit;
|
|
||||||
else if( keypressLc == "both" )
|
|
||||||
config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
|
|
||||||
else
|
|
||||||
throw std::runtime_error( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
inline void forceColour( ConfigData& config ) {
|
|
||||||
config.useColour = UseColour::Yes;
|
|
||||||
}
|
|
||||||
inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
|
|
||||||
std::ifstream f( _filename.c_str() );
|
|
||||||
if( !f.is_open() )
|
|
||||||
throw std::domain_error( "Unable to load input file: " + _filename );
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
while( std::getline( f, line ) ) {
|
|
||||||
line = trim(line);
|
|
||||||
if( !line.empty() && !startsWith( line, '#' ) ) {
|
|
||||||
if( !startsWith( line, '"' ) )
|
|
||||||
line = '"' + line + '"';
|
|
||||||
addTestOrTags( config, line + ',' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
|
|
||||||
|
|
||||||
using namespace Clara;
|
|
||||||
CommandLine<ConfigData> cli;
|
|
||||||
|
|
||||||
cli.bindProcessName( &ConfigData::processName );
|
|
||||||
|
|
||||||
cli["-?"]["-h"]["--help"]
|
|
||||||
.describe( "display usage information" )
|
|
||||||
.bind( &ConfigData::showHelp );
|
|
||||||
|
|
||||||
cli["-l"]["--list-tests"]
|
|
||||||
.describe( "list all/matching test cases" )
|
|
||||||
.bind( &ConfigData::listTests );
|
|
||||||
|
|
||||||
cli["-t"]["--list-tags"]
|
|
||||||
.describe( "list all/matching tags" )
|
|
||||||
.bind( &ConfigData::listTags );
|
|
||||||
|
|
||||||
cli["-s"]["--success"]
|
|
||||||
.describe( "include successful tests in output" )
|
|
||||||
.bind( &ConfigData::showSuccessfulTests );
|
|
||||||
|
|
||||||
cli["-b"]["--break"]
|
|
||||||
.describe( "break into debugger on failure" )
|
|
||||||
.bind( &ConfigData::shouldDebugBreak );
|
|
||||||
|
|
||||||
cli["-e"]["--nothrow"]
|
|
||||||
.describe( "skip exception tests" )
|
|
||||||
.bind( &ConfigData::noThrow );
|
|
||||||
|
|
||||||
cli["-i"]["--invisibles"]
|
|
||||||
.describe( "show invisibles (tabs, newlines)" )
|
|
||||||
.bind( &ConfigData::showInvisibles );
|
|
||||||
|
|
||||||
cli["-o"]["--out"]
|
|
||||||
.describe( "output filename" )
|
|
||||||
.bind( &ConfigData::outputFilename, "filename" );
|
|
||||||
|
|
||||||
cli["-r"]["--reporter"]
|
|
||||||
// .placeholder( "name[:filename]" )
|
|
||||||
.describe( "reporter to use (defaults to console)" )
|
|
||||||
.bind( &addReporterName, "name" );
|
|
||||||
|
|
||||||
cli["-n"]["--name"]
|
|
||||||
.describe( "suite name" )
|
|
||||||
.bind( &ConfigData::name, "name" );
|
|
||||||
|
|
||||||
cli["-a"]["--abort"]
|
|
||||||
.describe( "abort at first failure" )
|
|
||||||
.bind( &abortAfterFirst );
|
|
||||||
|
|
||||||
cli["-x"]["--abortx"]
|
|
||||||
.describe( "abort after x failures" )
|
|
||||||
.bind( &abortAfterX, "no. failures" );
|
|
||||||
|
|
||||||
cli["-w"]["--warn"]
|
|
||||||
.describe( "enable warnings" )
|
|
||||||
.bind( &addWarning, "warning name" );
|
|
||||||
|
|
||||||
// - needs updating if reinstated
|
|
||||||
// cli.into( &setVerbosity )
|
|
||||||
// .describe( "level of verbosity (0=no output)" )
|
|
||||||
// .shortOpt( "v")
|
|
||||||
// .longOpt( "verbosity" )
|
|
||||||
// .placeholder( "level" );
|
|
||||||
|
|
||||||
cli[_]
|
|
||||||
.describe( "which test or tests to use" )
|
|
||||||
.bind( &addTestOrTags, "test name, pattern or tags" );
|
|
||||||
|
|
||||||
cli["-d"]["--durations"]
|
|
||||||
.describe( "show test durations" )
|
|
||||||
.bind( &setShowDurations, "yes|no" );
|
|
||||||
|
|
||||||
cli["-f"]["--input-file"]
|
|
||||||
.describe( "load test names to run from a file" )
|
|
||||||
.bind( &loadTestNamesFromFile, "filename" );
|
|
||||||
|
|
||||||
cli["-#"]["--filenames-as-tags"]
|
|
||||||
.describe( "adds a tag for the filename" )
|
|
||||||
.bind( &ConfigData::filenamesAsTags );
|
|
||||||
|
|
||||||
cli["-c"]["--section"]
|
|
||||||
.describe( "specify section to run" )
|
|
||||||
.bind( &addSectionToRun, "section name" );
|
|
||||||
|
|
||||||
// Less common commands which don't have a short form
|
|
||||||
cli["--list-test-names-only"]
|
|
||||||
.describe( "list all/matching test cases names only" )
|
|
||||||
.bind( &ConfigData::listTestNamesOnly );
|
|
||||||
|
|
||||||
cli["--list-extra-info"]
|
|
||||||
.describe( "list all/matching test cases with more info" )
|
|
||||||
.bind( &ConfigData::listExtraInfo );
|
|
||||||
|
|
||||||
cli["--list-reporters"]
|
|
||||||
.describe( "list all reporters" )
|
|
||||||
.bind( &ConfigData::listReporters );
|
|
||||||
|
|
||||||
cli["--order"]
|
|
||||||
.describe( "test case order (defaults to decl)" )
|
|
||||||
.bind( &setOrder, "decl|lex|rand" );
|
|
||||||
|
|
||||||
cli["--rng-seed"]
|
|
||||||
.describe( "set a specific seed for random numbers" )
|
|
||||||
.bind( &setRngSeed, "'time'|number" );
|
|
||||||
|
|
||||||
cli["--force-colour"]
|
|
||||||
.describe( "force colourised output (deprecated)" )
|
|
||||||
.bind( &forceColour );
|
|
||||||
|
|
||||||
cli["--use-colour"]
|
|
||||||
.describe( "should output be colourised" )
|
|
||||||
.bind( &setUseColour, "yes|no" );
|
|
||||||
|
|
||||||
cli["--libidentify"]
|
|
||||||
.describe( "report name and version according to libidentify standard" )
|
|
||||||
.bind( &ConfigData::libIdentify );
|
|
||||||
|
|
||||||
cli["--wait-for-keypress"]
|
|
||||||
.describe( "waits for a keypress before exiting" )
|
|
||||||
.bind( &setWaitForKeypress, "start|exit|both" );
|
|
||||||
|
|
||||||
return cli;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
|
|
@ -1,147 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 04/03/2011.
|
|
||||||
* Copyright 2011 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_EVALUATE_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
|
|
||||||
#pragma warning(disable:4018) // more "signed/unsigned mismatch"
|
|
||||||
#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
enum Operator {
|
|
||||||
IsEqualTo,
|
|
||||||
IsNotEqualTo,
|
|
||||||
IsLessThan,
|
|
||||||
IsGreaterThan,
|
|
||||||
IsLessThanOrEqualTo,
|
|
||||||
IsGreaterThanOrEqualTo
|
|
||||||
};
|
|
||||||
|
|
||||||
template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } };
|
|
||||||
template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } };
|
|
||||||
template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } };
|
|
||||||
template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } };
|
|
||||||
template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } };
|
|
||||||
template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } };
|
|
||||||
template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T& removeConst(T const &t) { return const_cast<T&>(t); }
|
|
||||||
#ifdef CATCH_CONFIG_CPP11_NULLPTR
|
|
||||||
inline std::nullptr_t removeConst(std::nullptr_t) { return nullptr; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// So the compare overloads can be operator agnostic we convey the operator as a template
|
|
||||||
// enum, which is used to specialise an Evaluator for doing the comparison.
|
|
||||||
template<typename T1, typename T2, Operator Op>
|
|
||||||
struct Evaluator{};
|
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsEqualTo> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs) {
|
|
||||||
return bool(removeConst(lhs) == removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsNotEqualTo> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
||||||
return bool(removeConst(lhs) != removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsLessThan> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
||||||
return bool(removeConst(lhs) < removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsGreaterThan> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
||||||
return bool(removeConst(lhs) > removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
||||||
return bool(removeConst(lhs) >= removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
|
|
||||||
static bool evaluate( T1 const& lhs, T2 const& rhs ) {
|
|
||||||
return bool(removeConst(lhs) <= removeConst(rhs) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Special case for comparing a pointer to an int (deduced for p==0)
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<int const&, T* const&, IsEqualTo> {
|
|
||||||
static bool evaluate( int lhs, T* rhs) {
|
|
||||||
return reinterpret_cast<void const*>( lhs ) == rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<T* const&, int const&, IsEqualTo> {
|
|
||||||
static bool evaluate( T* lhs, int rhs) {
|
|
||||||
return lhs == reinterpret_cast<void const*>( rhs );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<int const&, T* const&, IsNotEqualTo> {
|
|
||||||
static bool evaluate( int lhs, T* rhs) {
|
|
||||||
return reinterpret_cast<void const*>( lhs ) != rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<T* const&, int const&, IsNotEqualTo> {
|
|
||||||
static bool evaluate( T* lhs, int rhs) {
|
|
||||||
return lhs != reinterpret_cast<void const*>( rhs );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<long const&, T* const&, IsEqualTo> {
|
|
||||||
static bool evaluate( long lhs, T* rhs) {
|
|
||||||
return reinterpret_cast<void const*>( lhs ) == rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<T* const&, long const&, IsEqualTo> {
|
|
||||||
static bool evaluate( T* lhs, long rhs) {
|
|
||||||
return lhs == reinterpret_cast<void const*>( rhs );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<long const&, T* const&, IsNotEqualTo> {
|
|
||||||
static bool evaluate( long lhs, T* rhs) {
|
|
||||||
return reinterpret_cast<void const*>( lhs ) != rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T>
|
|
||||||
struct Evaluator<T* const&, long const&, IsNotEqualTo> {
|
|
||||||
static bool evaluate( T* lhs, long rhs) {
|
|
||||||
return lhs != reinterpret_cast<void const*>( rhs );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end of namespace Internal
|
|
||||||
} // end of namespace Catch
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
|
|
@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 11/5/2012.
|
|
||||||
* Copyright 2012 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_EXPRESSION_LHS_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_result_builder.h"
|
|
||||||
#include "catch_evaluate.hpp"
|
|
||||||
#include "catch_tostring.h"
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
|
||||||
class BinaryExpression;
|
|
||||||
|
|
||||||
template<typename ArgT, typename MatcherT>
|
|
||||||
class MatchExpression;
|
|
||||||
|
|
||||||
// Wraps the LHS of an expression and overloads comparison operators
|
|
||||||
// for also capturing those and RHS (if any)
|
|
||||||
template<typename T>
|
|
||||||
class ExpressionLhs : public DecomposedExpression {
|
|
||||||
public:
|
|
||||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
|
|
||||||
|
|
||||||
ExpressionLhs& operator = ( const ExpressionLhs& );
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
|
|
||||||
operator == ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
|
|
||||||
operator != ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsLessThan, RhsT const&>
|
|
||||||
operator < ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsLessThan>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
|
|
||||||
operator > ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsGreaterThan>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
|
|
||||||
operator <= ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RhsT>
|
|
||||||
BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
|
|
||||||
operator >= ( RhsT const& rhs ) {
|
|
||||||
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
|
|
||||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
|
|
||||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
void endExpression() {
|
|
||||||
m_truthy = m_lhs ? true : false;
|
|
||||||
m_rb
|
|
||||||
.setResultType( m_truthy )
|
|
||||||
.endExpression( *this );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
|
||||||
dest = Catch::toString( m_lhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<Internal::Operator Op, typename RhsT>
|
|
||||||
BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
|
|
||||||
return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
template<Internal::Operator Op>
|
|
||||||
BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
|
|
||||||
return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ResultBuilder& m_rb;
|
|
||||||
T m_lhs;
|
|
||||||
bool m_truthy;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
|
||||||
class BinaryExpression : public DecomposedExpression {
|
|
||||||
public:
|
|
||||||
BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
|
|
||||||
: m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
|
|
||||||
|
|
||||||
BinaryExpression& operator = ( BinaryExpression& );
|
|
||||||
|
|
||||||
void endExpression() const {
|
|
||||||
m_rb
|
|
||||||
.setResultType( Internal::Evaluator<LhsT, RhsT, Op>::evaluate( m_lhs, m_rhs ) )
|
|
||||||
.endExpression( *this );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
|
||||||
std::string lhs = Catch::toString( m_lhs );
|
|
||||||
std::string rhs = Catch::toString( m_rhs );
|
|
||||||
char delim = lhs.size() + rhs.size() < 40 &&
|
|
||||||
lhs.find('\n') == std::string::npos &&
|
|
||||||
rhs.find('\n') == std::string::npos ? ' ' : '\n';
|
|
||||||
dest.reserve( 7 + lhs.size() + rhs.size() );
|
|
||||||
// 2 for spaces around operator
|
|
||||||
// 2 for operator
|
|
||||||
// 2 for parentheses (conditionally added later)
|
|
||||||
// 1 for negation (conditionally added later)
|
|
||||||
dest = lhs;
|
|
||||||
dest += delim;
|
|
||||||
dest += Internal::OperatorTraits<Op>::getName();
|
|
||||||
dest += delim;
|
|
||||||
dest += rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ResultBuilder& m_rb;
|
|
||||||
LhsT m_lhs;
|
|
||||||
RhsT m_rhs;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ArgT, typename MatcherT>
|
|
||||||
class MatchExpression : public DecomposedExpression {
|
|
||||||
public:
|
|
||||||
MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
|
|
||||||
: m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
|
|
||||||
|
|
||||||
virtual bool isBinaryExpression() const CATCH_OVERRIDE {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
|
||||||
std::string matcherAsString = m_matcher.toString();
|
|
||||||
dest = Catch::toString( m_arg );
|
|
||||||
dest += ' ';
|
|
||||||
if( matcherAsString == Detail::unprintableString )
|
|
||||||
dest += m_matcherString;
|
|
||||||
else
|
|
||||||
dest += matcherAsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ArgT m_arg;
|
|
||||||
MatcherT m_matcher;
|
|
||||||
char const* m_matcherString;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
|
|
@ -1,419 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 22/10/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_RUNNER_IMPL_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_interfaces_runner.h"
|
|
||||||
#include "catch_interfaces_reporter.h"
|
|
||||||
#include "catch_interfaces_exception.h"
|
|
||||||
#include "catch_config.hpp"
|
|
||||||
#include "catch_test_registry.hpp"
|
|
||||||
#include "catch_test_case_info.h"
|
|
||||||
#include "catch_capture.hpp"
|
|
||||||
#include "catch_totals.hpp"
|
|
||||||
#include "catch_test_spec.hpp"
|
|
||||||
#include "catch_test_case_tracker.hpp"
|
|
||||||
#include "catch_timer.h"
|
|
||||||
#include "catch_result_builder.h"
|
|
||||||
#include "catch_fatal_condition.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
class StreamRedirect {
|
|
||||||
|
|
||||||
public:
|
|
||||||
StreamRedirect( std::ostream& stream, std::string& targetString )
|
|
||||||
: m_stream( stream ),
|
|
||||||
m_prevBuf( stream.rdbuf() ),
|
|
||||||
m_targetString( targetString )
|
|
||||||
{
|
|
||||||
stream.rdbuf( m_oss.rdbuf() );
|
|
||||||
}
|
|
||||||
|
|
||||||
~StreamRedirect() {
|
|
||||||
m_targetString += m_oss.str();
|
|
||||||
m_stream.rdbuf( m_prevBuf );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::ostream& m_stream;
|
|
||||||
std::streambuf* m_prevBuf;
|
|
||||||
std::ostringstream m_oss;
|
|
||||||
std::string& m_targetString;
|
|
||||||
};
|
|
||||||
|
|
||||||
// StdErr has two constituent streams in C++, std::cerr and std::clog
|
|
||||||
// This means that we need to redirect 2 streams into 1 to keep proper
|
|
||||||
// order of writes and cannot use StreamRedirect on its own
|
|
||||||
class StdErrRedirect {
|
|
||||||
public:
|
|
||||||
StdErrRedirect(std::string& targetString)
|
|
||||||
:m_cerrBuf( cerr().rdbuf() ), m_clogBuf(clog().rdbuf()),
|
|
||||||
m_targetString(targetString){
|
|
||||||
cerr().rdbuf(m_oss.rdbuf());
|
|
||||||
clog().rdbuf(m_oss.rdbuf());
|
|
||||||
}
|
|
||||||
~StdErrRedirect() {
|
|
||||||
m_targetString += m_oss.str();
|
|
||||||
cerr().rdbuf(m_cerrBuf);
|
|
||||||
clog().rdbuf(m_clogBuf);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::streambuf* m_cerrBuf;
|
|
||||||
std::streambuf* m_clogBuf;
|
|
||||||
std::ostringstream m_oss;
|
|
||||||
std::string& m_targetString;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class RunContext : public IResultCapture, public IRunner {
|
|
||||||
|
|
||||||
RunContext( RunContext const& );
|
|
||||||
void operator =( RunContext const& );
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter )
|
|
||||||
: m_runInfo( _config->name() ),
|
|
||||||
m_context( getCurrentMutableContext() ),
|
|
||||||
m_activeTestCase( CATCH_NULL ),
|
|
||||||
m_config( _config ),
|
|
||||||
m_reporter( reporter ),
|
|
||||||
m_shouldReportUnexpected ( true )
|
|
||||||
{
|
|
||||||
m_context.setRunner( this );
|
|
||||||
m_context.setConfig( m_config );
|
|
||||||
m_context.setResultCapture( this );
|
|
||||||
m_reporter->testRunStarting( m_runInfo );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~RunContext() {
|
|
||||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
|
|
||||||
m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
|
|
||||||
}
|
|
||||||
void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
|
|
||||||
m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
Totals runTest( TestCase const& testCase ) {
|
|
||||||
Totals prevTotals = m_totals;
|
|
||||||
|
|
||||||
std::string redirectedCout;
|
|
||||||
std::string redirectedCerr;
|
|
||||||
|
|
||||||
TestCaseInfo testInfo = testCase.getTestCaseInfo();
|
|
||||||
|
|
||||||
m_reporter->testCaseStarting( testInfo );
|
|
||||||
|
|
||||||
m_activeTestCase = &testCase;
|
|
||||||
|
|
||||||
|
|
||||||
do {
|
|
||||||
ITracker& rootTracker = m_trackerContext.startRun();
|
|
||||||
assert( rootTracker.isSectionTracker() );
|
|
||||||
static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() );
|
|
||||||
do {
|
|
||||||
m_trackerContext.startCycle();
|
|
||||||
m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) );
|
|
||||||
runCurrentTest( redirectedCout, redirectedCerr );
|
|
||||||
}
|
|
||||||
while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() );
|
|
||||||
}
|
|
||||||
// !TBD: deprecated - this will be replaced by indexed trackers
|
|
||||||
while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
|
|
||||||
|
|
||||||
Totals deltaTotals = m_totals.delta( prevTotals );
|
|
||||||
if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) {
|
|
||||||
deltaTotals.assertions.failed++;
|
|
||||||
deltaTotals.testCases.passed--;
|
|
||||||
deltaTotals.testCases.failed++;
|
|
||||||
}
|
|
||||||
m_totals.testCases += deltaTotals.testCases;
|
|
||||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
|
||||||
deltaTotals,
|
|
||||||
redirectedCout,
|
|
||||||
redirectedCerr,
|
|
||||||
aborting() ) );
|
|
||||||
|
|
||||||
m_activeTestCase = CATCH_NULL;
|
|
||||||
m_testCaseTracker = CATCH_NULL;
|
|
||||||
|
|
||||||
return deltaTotals;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ptr<IConfig const> config() const {
|
|
||||||
return m_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private: // IResultCapture
|
|
||||||
|
|
||||||
|
|
||||||
virtual void assertionEnded( AssertionResult const& result ) {
|
|
||||||
if( result.getResultType() == ResultWas::Ok ) {
|
|
||||||
m_totals.assertions.passed++;
|
|
||||||
}
|
|
||||||
else if( !result.isOk() ) {
|
|
||||||
if( m_activeTestCase->getTestCaseInfo().okToFail() )
|
|
||||||
m_totals.assertions.failedButOk++;
|
|
||||||
else
|
|
||||||
m_totals.assertions.failed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have no use for the return value (whether messages should be cleared), because messages were made scoped
|
|
||||||
// and should be let to clear themselves out.
|
|
||||||
static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
|
|
||||||
|
|
||||||
// Reset working state
|
|
||||||
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
|
||||||
m_lastResult = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool lastAssertionPassed()
|
|
||||||
{
|
|
||||||
return m_totals.assertions.passed == (m_prevPassed + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void assertionPassed()
|
|
||||||
{
|
|
||||||
m_totals.assertions.passed++;
|
|
||||||
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}";
|
|
||||||
m_lastAssertionInfo.macroName = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void assertionRun()
|
|
||||||
{
|
|
||||||
m_prevPassed = m_totals.assertions.passed;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool sectionStarted (
|
|
||||||
SectionInfo const& sectionInfo,
|
|
||||||
Counts& assertions
|
|
||||||
)
|
|
||||||
{
|
|
||||||
ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) );
|
|
||||||
if( !sectionTracker.isOpen() )
|
|
||||||
return false;
|
|
||||||
m_activeSections.push_back( §ionTracker );
|
|
||||||
|
|
||||||
m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
|
|
||||||
|
|
||||||
m_reporter->sectionStarting( sectionInfo );
|
|
||||||
|
|
||||||
assertions = m_totals.assertions;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool testForMissingAssertions( Counts& assertions ) {
|
|
||||||
if( assertions.total() != 0 )
|
|
||||||
return false;
|
|
||||||
if( !m_config->warnAboutMissingAssertions() )
|
|
||||||
return false;
|
|
||||||
if( m_trackerContext.currentTracker().hasChildren() )
|
|
||||||
return false;
|
|
||||||
m_totals.assertions.failed++;
|
|
||||||
assertions.failed++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void sectionEnded( SectionEndInfo const& endInfo ) {
|
|
||||||
Counts assertions = m_totals.assertions - endInfo.prevAssertions;
|
|
||||||
bool missingAssertions = testForMissingAssertions( assertions );
|
|
||||||
|
|
||||||
if( !m_activeSections.empty() ) {
|
|
||||||
m_activeSections.back()->close();
|
|
||||||
m_activeSections.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) );
|
|
||||||
m_messages.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) {
|
|
||||||
if( m_unfinishedSections.empty() )
|
|
||||||
m_activeSections.back()->fail();
|
|
||||||
else
|
|
||||||
m_activeSections.back()->close();
|
|
||||||
m_activeSections.pop_back();
|
|
||||||
|
|
||||||
m_unfinishedSections.push_back( endInfo );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void pushScopedMessage( MessageInfo const& message ) {
|
|
||||||
m_messages.push_back( message );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void popScopedMessage( MessageInfo const& message ) {
|
|
||||||
m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string getCurrentTestName() const {
|
|
||||||
return m_activeTestCase
|
|
||||||
? m_activeTestCase->getTestCaseInfo().name
|
|
||||||
: std::string();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual const AssertionResult* getLastResult() const {
|
|
||||||
return &m_lastResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void exceptionEarlyReported() {
|
|
||||||
m_shouldReportUnexpected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void handleFatalErrorCondition( std::string const& message ) {
|
|
||||||
// Don't rebuild the result -- the stringification itself can cause more fatal errors
|
|
||||||
// Instead, fake a result data.
|
|
||||||
AssertionResultData tempResult;
|
|
||||||
tempResult.resultType = ResultWas::FatalErrorCondition;
|
|
||||||
tempResult.message = message;
|
|
||||||
AssertionResult result(m_lastAssertionInfo, tempResult);
|
|
||||||
|
|
||||||
getResultCapture().assertionEnded(result);
|
|
||||||
|
|
||||||
handleUnfinishedSections();
|
|
||||||
|
|
||||||
// Recreate section for test case (as we will lose the one that was in scope)
|
|
||||||
TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
|
||||||
SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
|
|
||||||
|
|
||||||
Counts assertions;
|
|
||||||
assertions.failed = 1;
|
|
||||||
SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false );
|
|
||||||
m_reporter->sectionEnded( testCaseSectionStats );
|
|
||||||
|
|
||||||
TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo();
|
|
||||||
|
|
||||||
Totals deltaTotals;
|
|
||||||
deltaTotals.testCases.failed = 1;
|
|
||||||
deltaTotals.assertions.failed = 1;
|
|
||||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
|
||||||
deltaTotals,
|
|
||||||
std::string(),
|
|
||||||
std::string(),
|
|
||||||
false ) );
|
|
||||||
m_totals.testCases.failed++;
|
|
||||||
testGroupEnded( std::string(), m_totals, 1, 1 );
|
|
||||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// !TBD We need to do this another way!
|
|
||||||
bool aborting() const {
|
|
||||||
return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
|
|
||||||
TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
|
|
||||||
SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
|
|
||||||
m_reporter->sectionStarting( testCaseSection );
|
|
||||||
Counts prevAssertions = m_totals.assertions;
|
|
||||||
double duration = 0;
|
|
||||||
m_shouldReportUnexpected = true;
|
|
||||||
try {
|
|
||||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
|
||||||
|
|
||||||
seedRng( *m_config );
|
|
||||||
|
|
||||||
Timer timer;
|
|
||||||
timer.start();
|
|
||||||
if( m_reporter->getPreferences().shouldRedirectStdOut ) {
|
|
||||||
StreamRedirect coutRedir( Catch::cout(), redirectedCout );
|
|
||||||
StdErrRedirect errRedir( redirectedCerr );
|
|
||||||
invokeActiveTestCase();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
invokeActiveTestCase();
|
|
||||||
}
|
|
||||||
duration = timer.getElapsedSeconds();
|
|
||||||
}
|
|
||||||
catch( TestFailureException& ) {
|
|
||||||
// This just means the test was aborted due to failure
|
|
||||||
}
|
|
||||||
catch(...) {
|
|
||||||
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
|
|
||||||
// are reported without translation at the point of origin.
|
|
||||||
if (m_shouldReportUnexpected) {
|
|
||||||
makeUnexpectedResultBuilder().useActiveException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_testCaseTracker->close();
|
|
||||||
handleUnfinishedSections();
|
|
||||||
m_messages.clear();
|
|
||||||
|
|
||||||
Counts assertions = m_totals.assertions - prevAssertions;
|
|
||||||
bool missingAssertions = testForMissingAssertions( assertions );
|
|
||||||
|
|
||||||
SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
|
|
||||||
m_reporter->sectionEnded( testCaseSectionStats );
|
|
||||||
}
|
|
||||||
|
|
||||||
void invokeActiveTestCase() {
|
|
||||||
FatalConditionHandler fatalConditionHandler; // Handle signals
|
|
||||||
m_activeTestCase->invoke();
|
|
||||||
fatalConditionHandler.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ResultBuilder makeUnexpectedResultBuilder() const {
|
|
||||||
return ResultBuilder( m_lastAssertionInfo.macroName,
|
|
||||||
m_lastAssertionInfo.lineInfo,
|
|
||||||
m_lastAssertionInfo.capturedExpression,
|
|
||||||
m_lastAssertionInfo.resultDisposition );
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleUnfinishedSections() {
|
|
||||||
// If sections ended prematurely due to an exception we stored their
|
|
||||||
// infos here so we can tear them down outside the unwind process.
|
|
||||||
for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
|
|
||||||
itEnd = m_unfinishedSections.rend();
|
|
||||||
it != itEnd;
|
|
||||||
++it )
|
|
||||||
sectionEnded( *it );
|
|
||||||
m_unfinishedSections.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
TestRunInfo m_runInfo;
|
|
||||||
IMutableContext& m_context;
|
|
||||||
TestCase const* m_activeTestCase;
|
|
||||||
ITracker* m_testCaseTracker;
|
|
||||||
ITracker* m_currentSectionTracker;
|
|
||||||
AssertionResult m_lastResult;
|
|
||||||
|
|
||||||
Ptr<IConfig const> m_config;
|
|
||||||
Totals m_totals;
|
|
||||||
Ptr<IStreamingReporter> m_reporter;
|
|
||||||
std::vector<MessageInfo> m_messages;
|
|
||||||
AssertionInfo m_lastAssertionInfo;
|
|
||||||
std::vector<SectionEndInfo> m_unfinishedSections;
|
|
||||||
std::vector<ITracker*> m_activeSections;
|
|
||||||
TrackerContext m_trackerContext;
|
|
||||||
size_t m_prevPassed;
|
|
||||||
bool m_shouldReportUnexpected;
|
|
||||||
};
|
|
||||||
|
|
||||||
IResultCapture& getResultCapture() {
|
|
||||||
if( IResultCapture* capture = getCurrentContext().getResultCapture() )
|
|
||||||
return *capture;
|
|
||||||
else
|
|
||||||
throw std::logic_error( "No result capture instance" );
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
|
|
@ -1,207 +0,0 @@
|
|||||||
/*
|
|
||||||
* Created by Phil on 7/1/2011
|
|
||||||
* 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_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
|
|
||||||
#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
|
|
||||||
|
|
||||||
#include "catch_test_registry.hpp"
|
|
||||||
#include "catch_test_case_info.h"
|
|
||||||
#include "catch_test_spec.hpp"
|
|
||||||
#include "catch_context.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <set>
|
|
||||||
#include <sstream>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Catch {
|
|
||||||
|
|
||||||
struct RandomNumberGenerator {
|
|
||||||
typedef unsigned int result_type;
|
|
||||||
|
|
||||||
result_type operator()( result_type n ) const { return std::rand() % n; }
|
|
||||||
|
|
||||||
#ifdef CATCH_CONFIG_CPP11_SHUFFLE
|
|
||||||
static constexpr result_type min() { return 0; }
|
|
||||||
static constexpr result_type max() { return 1000000; }
|
|
||||||
result_type operator()() const { return std::rand() % max(); }
|
|
||||||
#endif
|
|
||||||
template<typename V>
|
|
||||||
static void shuffle( V& vector ) {
|
|
||||||
RandomNumberGenerator rng;
|
|
||||||
#ifdef CATCH_CONFIG_CPP11_SHUFFLE
|
|
||||||
std::shuffle( vector.begin(), vector.end(), rng );
|
|
||||||
#else
|
|
||||||
std::random_shuffle( vector.begin(), vector.end(), rng );
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
|
|
||||||
|
|
||||||
std::vector<TestCase> sorted = unsortedTestCases;
|
|
||||||
|
|
||||||
switch( config.runOrder() ) {
|
|
||||||
case RunTests::InLexicographicalOrder:
|
|
||||||
std::sort( sorted.begin(), sorted.end() );
|
|
||||||
break;
|
|
||||||
case RunTests::InRandomOrder:
|
|
||||||
{
|
|
||||||
seedRng( config );
|
|
||||||
RandomNumberGenerator::shuffle( sorted );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case RunTests::InDeclarationOrder:
|
|
||||||
// already in declaration order
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return sorted;
|
|
||||||
}
|
|
||||||
bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
|
|
||||||
return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
|
|
||||||
}
|
|
||||||
|
|
||||||
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
|
|
||||||
std::set<TestCase> seenFunctions;
|
|
||||||
for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end();
|
|
||||||
it != itEnd;
|
|
||||||
++it ) {
|
|
||||||
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it );
|
|
||||||
if( !prev.second ) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
|
|
||||||
ss << Colour( Colour::Red )
|
|
||||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
|
||||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
|
|
||||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
|
||||||
|
|
||||||
throw std::runtime_error(ss.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
|
|
||||||
std::vector<TestCase> filtered;
|
|
||||||
filtered.reserve( testCases.size() );
|
|
||||||
for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
|
|
||||||
it != itEnd;
|
|
||||||
++it )
|
|
||||||
if( matchTest( *it, testSpec, config ) )
|
|
||||||
filtered.push_back( *it );
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
|
|
||||||
return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestRegistry : public ITestCaseRegistry {
|
|
||||||
public:
|
|
||||||
TestRegistry()
|
|
||||||
: m_currentSortOrder( RunTests::InDeclarationOrder ),
|
|
||||||
m_unnamedCount( 0 )
|
|
||||||
{}
|
|
||||||
virtual ~TestRegistry();
|
|
||||||
|
|
||||||
virtual void registerTest( TestCase const& testCase ) {
|
|
||||||
std::string name = testCase.getTestCaseInfo().name;
|
|
||||||
if( name.empty() ) {
|
|
||||||
std::ostringstream oss;
|
|
||||||
oss << "Anonymous test case " << ++m_unnamedCount;
|
|
||||||
return registerTest( testCase.withName( oss.str() ) );
|
|
||||||
}
|
|
||||||
m_functions.push_back( testCase );
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::vector<TestCase> const& getAllTests() const {
|
|
||||||
return m_functions;
|
|
||||||
}
|
|
||||||
virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const {
|
|
||||||
if( m_sortedFunctions.empty() )
|
|
||||||
enforceNoDuplicateTestCases( m_functions );
|
|
||||||
|
|
||||||
if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
|
|
||||||
m_sortedFunctions = sortTests( config, m_functions );
|
|
||||||
m_currentSortOrder = config.runOrder();
|
|
||||||
}
|
|
||||||
return m_sortedFunctions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<TestCase> m_functions;
|
|
||||||
mutable RunTests::InWhatOrder m_currentSortOrder;
|
|
||||||
mutable std::vector<TestCase> m_sortedFunctions;
|
|
||||||
size_t m_unnamedCount;
|
|
||||||
std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class FreeFunctionTestCase : public SharedImpl<ITestCase> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
|
|
||||||
|
|
||||||
virtual void invoke() const {
|
|
||||||
m_fun();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual ~FreeFunctionTestCase();
|
|
||||||
|
|
||||||
TestFunction m_fun;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
|
||||||
std::string className = classOrQualifiedMethodName;
|
|
||||||
if( startsWith( className, '&' ) )
|
|
||||||
{
|
|
||||||
std::size_t lastColons = className.rfind( "::" );
|
|
||||||
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
|
||||||
if( penultimateColons == std::string::npos )
|
|
||||||
penultimateColons = 1;
|
|
||||||
className = className.substr( penultimateColons, lastColons-penultimateColons );
|
|
||||||
}
|
|
||||||
return className;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerTestCase
|
|
||||||
( ITestCase* testCase,
|
|
||||||
char const* classOrQualifiedMethodName,
|
|
||||||
NameAndDesc const& nameAndDesc,
|
|
||||||
SourceLineInfo const& lineInfo ) {
|
|
||||||
|
|
||||||
getMutableRegistryHub().registerTest
|
|
||||||
( makeTestCase
|
|
||||||
( testCase,
|
|
||||||
extractClassName( classOrQualifiedMethodName ),
|
|
||||||
nameAndDesc.name,
|
|
||||||
nameAndDesc.description,
|
|
||||||
lineInfo ) );
|
|
||||||
}
|
|
||||||
void registerTestCaseFunction
|
|
||||||
( TestFunction function,
|
|
||||||
SourceLineInfo const& lineInfo,
|
|
||||||
NameAndDesc const& nameAndDesc ) {
|
|
||||||
registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
AutoReg::AutoReg
|
|
||||||
( TestFunction function,
|
|
||||||
SourceLineInfo const& lineInfo,
|
|
||||||
NameAndDesc const& nameAndDesc ) {
|
|
||||||
registerTestCaseFunction( function, lineInfo, nameAndDesc );
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoReg::~AutoReg() {}
|
|
||||||
|
|
||||||
} // end namespace Catch
|
|
||||||
|
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
|
|
Loading…
Reference in New Issue
Block a user