Added CATCH_ENFORCE (and updated CATCH_INTERNAL_ERROR to be stream based)

replaced all ad-hoc exceptions (where appropriate) with CATCH_ENFORCE or CATCH_INTERNAL_ERROR - no explicit ostringstreams.
This commit is contained in:
Phil Nash 2017-05-05 15:42:57 +01:00
parent 687437fcd1
commit 4c5af2089a
13 changed files with 65 additions and 97 deletions

View File

@ -23,12 +23,10 @@
namespace Catch {
IStreamingReporterPtr createReporter( std::string const& reporterName, IConfigPtr const& config ) {
if( auto reporter = getRegistryHub().getReporterRegistry().create( reporterName, config ) )
return reporter;
auto reporter = getRegistryHub().getReporterRegistry().create( reporterName, config );
CATCH_ENFORCE( reporter, "No reporter registered with name: '" << reporterName << "'" );
std::ostringstream oss;
oss << "No reporter registered with name: '" << reporterName << "'";
throw std::domain_error( oss.str() );
return reporter;
}
IStreamingReporterPtr makeReporter( std::shared_ptr<Config> const& config ) {
@ -105,11 +103,8 @@ namespace Catch {
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 );
}
if( alreadyInstantiated )
CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" );
alreadyInstantiated = true;
}
~Session() {

View File

@ -19,19 +19,16 @@ 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" );
CATCH_ENFORCE( x >=1, "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 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 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 addWarning( ConfigData& config, std::string const& warning ) {
CATCH_ENFORCE( warning == "NoAssertions", "Unrecognised warning: '" << warning << "'" );
config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
}
inline void setOrder( ConfigData& config, std::string const& order ) {
if( startsWith( "declared", order ) )
@ -41,7 +38,7 @@ namespace Catch {
else if( startsWith( "random", order ) )
config.runOrder = RunTests::InRandomOrder;
else
throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' );
CATCH_ENFORCE( false, "Unrecognised ordering: '" << order << '\'' );
}
inline void setRngSeed( ConfigData& config, std::string const& seed ) {
if( seed == "time" ) {
@ -51,8 +48,7 @@ namespace Catch {
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" );
CATCH_ENFORCE( !ss.fail(), "Argument to --rng-seed should be the word 'time' or a number" );
}
}
inline void setVerbosity( ConfigData& config, int level ) {
@ -74,15 +70,14 @@ namespace Catch {
else if( mode == "auto" )
config.useColour = UseColour::Auto;
else
throw std::runtime_error( "colour mode must be one of: auto, yes or no" );
CATCH_ENFORCE( false, "colour mode must be one of: auto, yes or no" );
}
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 );
CATCH_ENFORCE( f.is_open(), "Unable to load input file: '" << _filename << "'" );
std::string line;
while( std::getline( f, line ) ) {

View File

@ -23,6 +23,7 @@
#include <sstream>
#include <algorithm>
#include <exception>
namespace Catch {
@ -99,8 +100,6 @@ namespace Catch {
inline bool alwaysTrue() { return true; }
inline bool alwaysFalse() { return false; }
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
void seedRng( IConfig const& config );
unsigned int rngSeed();
@ -117,10 +116,29 @@ namespace Catch {
T const& operator + ( T const& value, StreamEndStop ) {
return value;
}
template<typename ExceptionT = std::domain_error>
class Error {
std::ostringstream m_oss;
public:
template<typename T>
auto operator <<( T const& value ) -> Error& {
m_oss << value;
return *this;
}
[[noreturn]]
void raise() {
throw ExceptionT( m_oss.str() );
}
};
}
#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
#define CATCH_INTERNAL_ERROR( msg ) do{ ( ::Catch::Error<std::logic_error>() << CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg ).raise(); } while(false)
#define CATCH_ERROR( msg ) ( ::Catch::Error<>() << msg ).raise()
#define CATCH_ENFORCE( condition, msg ) do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
#endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED

View File

@ -106,13 +106,6 @@ namespace Catch {
#endif
return os;
}
void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
std::ostringstream oss;
oss << locationInfo << ": Internal Catch error: '" << message << '\'';
if( alwaysTrue() )
throw std::logic_error( oss.str() );
}
}
#endif // TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED

View File

@ -118,7 +118,7 @@ namespace Catch {
if( m_data.outputFilename == "%debug" )
return new DebugOutStream();
else
throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename );
CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" );
}
else
return new FileStream( m_data.outputFilename );

View File

@ -73,7 +73,7 @@ namespace {
case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
case Colour::Bright: throw std::logic_error( "not a colour" );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
}
}
@ -134,7 +134,7 @@ namespace {
case Colour::BrightGreen: return setColour( "[1;32m" );
case Colour::BrightWhite: return setColour( "[1;37m" );
case Colour::Bright: throw std::logic_error( "not a colour" );
case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
}
}
static IColourImpl* instance() {

View File

@ -371,7 +371,7 @@ namespace Catch {
if( IResultCapture* capture = getCurrentContext().getResultCapture() )
return *capture;
else
throw std::logic_error( "No result capture instance" );
CATCH_INTERNAL_ERROR( "No result capture instance" );
}
} // end namespace Catch

View File

@ -59,11 +59,7 @@ namespace Catch {
FileStream::FileStream( std::string const& filename ) {
m_ofs.open( filename.c_str() );
if( m_ofs.fail() ) {
std::ostringstream oss;
oss << "Unable to open file: '" << filename << '\'';
throw std::domain_error( oss.str() );
}
CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" );
}
std::ostream& FileStream::stream() const {

View File

@ -40,24 +40,13 @@ namespace Catch {
void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
std::ostringstream oss;
oss << Colour( Colour::Red )
<< "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n"
<< Colour( Colour::FileName )
<< lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
std::ostringstream oss;
oss << Colour( Colour::Red )
<< "error: tag alias, \"" << alias << "\" already registered.\n"
<< "\tFirst seen at "
<< Colour( Colour::Red ) << find(alias)->lineInfo << '\n'
<< Colour( Colour::Red ) << "\tRedefined at "
<< Colour( Colour::FileName) << lineInfo << '\n';
throw std::domain_error( oss.str().c_str() );
}
CATCH_ENFORCE( startsWith( alias, "[@" ) && endsWith( alias, ']' ),
"error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
CATCH_ENFORCE( m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second,
"error: tag alias, '" << alias << "' already registered.\n"
<< "\tFirst seen at: " << find(alias)->lineInfo << "\n"
<< "\tRedefined at: " << lineInfo );
}
ITagAliasRegistry::~ITagAliasRegistry() {}

View File

@ -37,15 +37,10 @@ namespace Catch {
return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
}
inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
if( isReservedTag( tag ) ) {
std::ostringstream ss;
ss << Colour(Colour::Red)
<< "Tag name [" << tag << "] not allowed.\n"
CATCH_ENFORCE( !isReservedTag( tag ),
"Tag name: [" << tag << "] is not allowed.\n"
<< "Tag names starting with non alpha-numeric characters are reserved\n"
<< Colour(Colour::FileName)
<< _lineInfo << '\n';
throw std::runtime_error(ss.str());
}
<< _lineInfo );
}
TestCase makeTestCase( ITestCase* _testCase,

View File

@ -62,18 +62,12 @@ namespace Catch {
void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
std::set<TestCase> seenFunctions;
for( auto const function : functions ) {
std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( function );
if( !prev.second ) {
std::ostringstream ss;
ss << Colour( Colour::Red )
<< "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
<< "\tRedefined at " << function.getTestCaseInfo().lineInfo << std::endl;
throw std::runtime_error(ss.str());
}
for( auto const& function : functions ) {
auto prev = seenFunctions.insert( function );
CATCH_ENFORCE( prev.second,
"error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
<< "\tRedefined at " << function.getTestCaseInfo().lineInfo );
}
}

View File

@ -202,11 +202,6 @@ namespace TestCaseTracking {
m_ctx.currentTracker().close();
switch( m_runState ) {
case NotStarted:
case CompletedSuccessfully:
case Failed:
throw std::logic_error( "Illogical state" );
case NeedsAnotherRun:
break;;
@ -218,8 +213,13 @@ namespace TestCaseTracking {
m_runState = CompletedSuccessfully;
break;
case NotStarted:
case CompletedSuccessfully:
case Failed:
CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
default:
throw std::logic_error( "Unexpected state" );
CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
}
moveToParent();
m_ctx.completeCycle();

View File

@ -49,16 +49,9 @@ namespace Catch
return startsWith( adjustCase( str ), m_pattern );
case WildcardAtBothEnds:
return contains( adjustCase( str ), m_pattern );
default:
CATCH_INTERNAL_ERROR( "Unknown enum" );
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif
throw std::logic_error( "Unknown enum" );
#ifdef __clang__
#pragma clang diagnostic pop
#endif
}
private:
std::string adjustCase( std::string const& str ) const {