mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 07:16:10 +01:00
Merge branch 'dev-performance'
This commit is contained in:
commit
4ce11d63a6
@ -7,6 +7,7 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
|||||||
# define some folders
|
# define some folders
|
||||||
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
set(CATCH_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
set(SELF_TEST_DIR ${CATCH_DIR}/projects/SelfTest)
|
||||||
|
set(BENCHMARK_DIR ${CATCH_DIR}/projects/Benchmark)
|
||||||
set(HEADER_DIR ${CATCH_DIR}/include)
|
set(HEADER_DIR ${CATCH_DIR}/include)
|
||||||
|
|
||||||
if(USE_CPP11)
|
if(USE_CPP11)
|
||||||
@ -221,13 +222,20 @@ set(HEADERS
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
set(BENCH_SOURCES
|
||||||
|
${BENCHMARK_DIR}/BenchMain.cpp
|
||||||
|
${BENCHMARK_DIR}/StringificationBench.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# Provide some groupings for IDEs
|
# Provide some groupings for IDEs
|
||||||
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
|
||||||
SOURCE_GROUP("Surrogates" FILES ${IMPL_SOURCES})
|
SOURCE_GROUP("Surrogates" FILES ${IMPL_SOURCES})
|
||||||
|
SOURCE_GROUP("Benchmarks" FILES ${BENCH_SOURCES})
|
||||||
|
|
||||||
# configure the executable
|
# configure the executable
|
||||||
include_directories(${HEADER_DIR})
|
include_directories(${HEADER_DIR})
|
||||||
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${HEADERS})
|
add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${HEADERS})
|
||||||
|
add_executable(Benchmark ${BENCH_SOURCES} ${HEADERS})
|
||||||
|
|
||||||
# configure unit tests via CTest
|
# configure unit tests via CTest
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
@ -13,6 +13,27 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
|
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
||||||
|
|
||||||
|
struct DecomposedExpression
|
||||||
|
{
|
||||||
|
virtual ~DecomposedExpression() {}
|
||||||
|
virtual bool isBinaryExpression() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void reconstructExpression( std::string& dest ) const = 0;
|
||||||
|
|
||||||
|
// Only simple binary comparisons can be decomposed.
|
||||||
|
// If more complex check is required then wrap sub-expressions in parentheses.
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& );
|
||||||
|
template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& );
|
||||||
|
};
|
||||||
|
|
||||||
struct AssertionInfo
|
struct AssertionInfo
|
||||||
{
|
{
|
||||||
AssertionInfo() {}
|
AssertionInfo() {}
|
||||||
@ -29,11 +50,41 @@ namespace Catch {
|
|||||||
|
|
||||||
struct AssertionResultData
|
struct AssertionResultData
|
||||||
{
|
{
|
||||||
AssertionResultData() : resultType( ResultWas::Unknown ) {}
|
AssertionResultData() : decomposedExpression( CATCH_NULL )
|
||||||
|
, resultType( ResultWas::Unknown )
|
||||||
|
, negated( false )
|
||||||
|
, parenthesized( false ) {}
|
||||||
|
|
||||||
std::string reconstructedExpression;
|
void negate( bool parenthesize ) {
|
||||||
|
negated = !negated;
|
||||||
|
parenthesized = parenthesize;
|
||||||
|
if( resultType == ResultWas::Ok )
|
||||||
|
resultType = ResultWas::ExpressionFailed;
|
||||||
|
else if( resultType == ResultWas::ExpressionFailed )
|
||||||
|
resultType = ResultWas::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& reconstructExpression() const {
|
||||||
|
if( decomposedExpression != CATCH_NULL ) {
|
||||||
|
decomposedExpression->reconstructExpression( reconstructedExpression );
|
||||||
|
if( parenthesized ) {
|
||||||
|
reconstructedExpression.insert( 0, 1, '(' );
|
||||||
|
reconstructedExpression.append( 1, ')' );
|
||||||
|
}
|
||||||
|
if( negated ) {
|
||||||
|
reconstructedExpression.insert( 0, 1, '!' );
|
||||||
|
}
|
||||||
|
decomposedExpression = CATCH_NULL;
|
||||||
|
}
|
||||||
|
return reconstructedExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutable DecomposedExpression const* decomposedExpression;
|
||||||
|
mutable std::string reconstructedExpression;
|
||||||
std::string message;
|
std::string message;
|
||||||
ResultWas::OfType resultType;
|
ResultWas::OfType resultType;
|
||||||
|
bool negated;
|
||||||
|
bool parenthesized;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssertionResult {
|
class AssertionResult {
|
||||||
@ -60,6 +111,8 @@ namespace Catch {
|
|||||||
std::string getMessage() const;
|
std::string getMessage() const;
|
||||||
SourceLineInfo getSourceInfo() const;
|
SourceLineInfo getSourceInfo() const;
|
||||||
std::string getTestMacroName() const;
|
std::string getTestMacroName() const;
|
||||||
|
void discardDecomposedExpression() const;
|
||||||
|
void expandDecomposedExpression() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AssertionInfo m_info;
|
AssertionInfo m_info;
|
||||||
|
@ -72,7 +72,7 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string AssertionResult::getExpandedExpression() const {
|
std::string AssertionResult::getExpandedExpression() const {
|
||||||
return m_resultData.reconstructedExpression;
|
return m_resultData.reconstructExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AssertionResult::getMessage() const {
|
std::string AssertionResult::getMessage() const {
|
||||||
@ -86,6 +86,14 @@ namespace Catch {
|
|||||||
return m_info.macroName;
|
return m_info.macroName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssertionResult::discardDecomposedExpression() const {
|
||||||
|
m_resultData.decomposedExpression = CATCH_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertionResult::expandDecomposedExpression() const {
|
||||||
|
m_resultData.reconstructExpression();
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
|
||||||
|
@ -132,13 +132,7 @@
|
|||||||
do { \
|
do { \
|
||||||
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \
|
||||||
try { \
|
try { \
|
||||||
std::string matcherAsString = (matcher).toString(); \
|
__catchResult.captureMatch( arg, matcher, #matcher ); \
|
||||||
__catchResult \
|
|
||||||
.setLhs( Catch::toString( arg ) ) \
|
|
||||||
.setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \
|
|
||||||
.setOp( "matches" ) \
|
|
||||||
.setResultType( (matcher).match( arg ) ); \
|
|
||||||
__catchResult.captureExpression(); \
|
|
||||||
} catch( ... ) { \
|
} catch( ... ) { \
|
||||||
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
__catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
|
||||||
} \
|
} \
|
||||||
|
@ -86,10 +86,10 @@ namespace Catch {
|
|||||||
std::string line;
|
std::string line;
|
||||||
while( std::getline( f, line ) ) {
|
while( std::getline( f, line ) ) {
|
||||||
line = trim(line);
|
line = trim(line);
|
||||||
if( !line.empty() && !startsWith( line, "#" ) ) {
|
if( !line.empty() && !startsWith( line, '#' ) ) {
|
||||||
if( !startsWith( line, "\"" ) )
|
if( !startsWith( line, '"' ) )
|
||||||
line = "\"" + line + "\"";
|
line = "\"" + line + "\"";
|
||||||
addTestOrTags( config, line + "," );
|
addTestOrTags( config, line + ',' );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,10 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool startsWith( std::string const& s, std::string const& prefix );
|
bool startsWith( std::string const& s, std::string const& prefix );
|
||||||
|
bool startsWith( std::string const& s, char prefix );
|
||||||
bool endsWith( std::string const& s, std::string const& suffix );
|
bool endsWith( std::string const& s, std::string const& suffix );
|
||||||
|
bool endsWith( std::string const& s, char suffix );
|
||||||
|
bool contains( std::string const& s, std::string const& infix );
|
||||||
bool contains( std::string const& s, std::string const& infix );
|
bool contains( std::string const& s, std::string const& infix );
|
||||||
void toLowerInPlace( std::string& s );
|
void toLowerInPlace( std::string& s );
|
||||||
std::string toLower( std::string const& s );
|
std::string toLower( std::string const& s );
|
||||||
|
@ -13,14 +13,23 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
bool startsWith( std::string const& s, std::string const& prefix ) {
|
bool startsWith( std::string const& s, std::string const& prefix ) {
|
||||||
return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
|
return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
|
||||||
|
}
|
||||||
|
bool startsWith( std::string const& s, char prefix ) {
|
||||||
|
return !s.empty() && s[0] == prefix;
|
||||||
}
|
}
|
||||||
bool endsWith( std::string const& s, std::string const& suffix ) {
|
bool endsWith( std::string const& s, std::string const& suffix ) {
|
||||||
return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
|
return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
|
||||||
|
}
|
||||||
|
bool endsWith( std::string const& s, char suffix ) {
|
||||||
|
return !s.empty() && s[s.size()-1] == suffix;
|
||||||
}
|
}
|
||||||
bool contains( std::string const& s, std::string const& infix ) {
|
bool contains( std::string const& s, std::string const& infix ) {
|
||||||
return s.find( infix ) != std::string::npos;
|
return s.find( infix ) != std::string::npos;
|
||||||
}
|
}
|
||||||
|
bool contains( std::string const& s, char infix ) {
|
||||||
|
return s.find(infix);
|
||||||
|
}
|
||||||
char toLowerCh(char c) {
|
char toLowerCh(char c) {
|
||||||
return static_cast<char>( ::tolower( c ) );
|
return static_cast<char>( ::tolower( c ) );
|
||||||
}
|
}
|
||||||
@ -37,7 +46,7 @@ namespace Catch {
|
|||||||
std::string::size_type start = str.find_first_not_of( whitespaceChars );
|
std::string::size_type start = str.find_first_not_of( whitespaceChars );
|
||||||
std::string::size_type end = str.find_last_not_of( whitespaceChars );
|
std::string::size_type end = str.find_last_not_of( whitespaceChars );
|
||||||
|
|
||||||
return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
|
return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
|
||||||
@ -95,9 +104,9 @@ namespace Catch {
|
|||||||
|
|
||||||
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
|
||||||
#ifndef __GNUG__
|
#ifndef __GNUG__
|
||||||
os << info.file << "(" << info.line << ")";
|
os << info.file << '(' << info.line << ')';
|
||||||
#else
|
#else
|
||||||
os << info.file << ":" << info.line;
|
os << info.file << ':' << info.line;
|
||||||
#endif
|
#endif
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
@ -14,90 +14,155 @@
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
// Wraps the LHS of an expression and captures the operator and RHS (if any) -
|
template<typename LhsT, Internal::Operator Op, typename RhsT>
|
||||||
// wrapping them all in a ResultBuilder object
|
class BinaryExpression;
|
||||||
template<typename T>
|
|
||||||
class ExpressionLhs {
|
|
||||||
ExpressionLhs& operator = ( ExpressionLhs const& );
|
|
||||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
||||||
ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
|
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:
|
public:
|
||||||
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
|
ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
|
||||||
# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS
|
|
||||||
ExpressionLhs( ExpressionLhs const& ) = default;
|
|
||||||
ExpressionLhs( ExpressionLhs && ) = default;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator == ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
|
||||||
|
operator == ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator != ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
|
||||||
|
operator != ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator < ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsLessThan, RhsT const&>
|
||||||
|
operator < ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsLessThan>( rhs );
|
return captureExpression<Internal::IsLessThan>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator > ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
|
||||||
|
operator > ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsGreaterThan>( rhs );
|
return captureExpression<Internal::IsGreaterThan>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator <= ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
|
||||||
|
operator <= ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT>
|
template<typename RhsT>
|
||||||
ResultBuilder& operator >= ( RhsT const& rhs ) {
|
BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
|
||||||
|
operator >= ( RhsT const& rhs ) const {
|
||||||
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultBuilder& operator == ( bool rhs ) {
|
BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) const {
|
||||||
return captureExpression<Internal::IsEqualTo>( rhs );
|
return captureExpression<Internal::IsEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultBuilder& operator != ( bool rhs ) {
|
BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) const {
|
||||||
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
return captureExpression<Internal::IsNotEqualTo>( rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
void endExpression() {
|
void endExpression() {
|
||||||
bool value = m_lhs ? true : false;
|
m_truthy = m_lhs ? true : false;
|
||||||
m_rb
|
m_rb
|
||||||
.setLhs( Catch::toString( value ) )
|
.setResultType( m_truthy )
|
||||||
.setResultType( value )
|
.endExpression( *this );
|
||||||
.endExpression();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only simple binary expressions are allowed on the LHS.
|
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
|
||||||
// If more complex compositions are required then place the sub expression in parentheses
|
dest = Catch::toString( m_truthy );
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
|
}
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<Internal::Operator Op, typename RhsT>
|
template<Internal::Operator Op, typename RhsT>
|
||||||
ResultBuilder& captureExpression( RhsT const& rhs ) {
|
BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
|
||||||
return m_rb
|
return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
|
||||||
.setResultType( Internal::compare<Op>( m_lhs, rhs ) )
|
}
|
||||||
.setLhs( Catch::toString( m_lhs ) )
|
|
||||||
.setRhs( Catch::toString( rhs ) )
|
template<Internal::Operator Op>
|
||||||
.setOp( Internal::OperatorTraits<Op>::getName() );
|
BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
|
||||||
|
return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ResultBuilder& m_rb;
|
ResultBuilder& m_rb;
|
||||||
T m_lhs;
|
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 ) {}
|
||||||
|
|
||||||
|
void endExpression() const {
|
||||||
|
m_rb
|
||||||
|
.setResultType( Internal::compare<Op>( 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
|
} // end namespace Catch
|
||||||
|
@ -51,9 +51,9 @@ namespace Catch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !config.testSpec().hasFilters() )
|
if( !config.testSpec().hasFilters() )
|
||||||
Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
|
Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl;
|
||||||
else
|
else
|
||||||
Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
|
Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl;
|
||||||
return matchedTests;
|
return matchedTests;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ namespace Catch {
|
|||||||
++it ) {
|
++it ) {
|
||||||
matchedTests++;
|
matchedTests++;
|
||||||
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
|
||||||
if( startsWith( testCaseInfo.name, "#" ) )
|
if( startsWith( testCaseInfo.name, '#' ) )
|
||||||
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
Catch::cout() << "\"" << testCaseInfo.name << "\"" << std::endl;
|
||||||
else
|
else
|
||||||
Catch::cout() << testCaseInfo.name << std::endl;
|
Catch::cout() << testCaseInfo.name << std::endl;
|
||||||
|
@ -184,7 +184,7 @@ namespace Matchers {
|
|||||||
{
|
{
|
||||||
return m_caseSensitivity == CaseSensitive::No
|
return m_caseSensitivity == CaseSensitive::No
|
||||||
? " (case insensitive)"
|
? " (case insensitive)"
|
||||||
: "";
|
: std::string();
|
||||||
}
|
}
|
||||||
CaseSensitive::Choice m_caseSensitivity;
|
CaseSensitive::Choice m_caseSensitivity;
|
||||||
std::string m_str;
|
std::string m_str;
|
||||||
|
@ -74,7 +74,7 @@ namespace Catch {
|
|||||||
return new T( config );
|
return new T( config );
|
||||||
}
|
}
|
||||||
virtual std::string getDescription() const {
|
virtual std::string getDescription() const {
|
||||||
return "";
|
return std::string();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,22 +19,20 @@ namespace Catch {
|
|||||||
|
|
||||||
template<typename T> class ExpressionLhs;
|
template<typename T> class ExpressionLhs;
|
||||||
|
|
||||||
struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
|
|
||||||
|
|
||||||
struct CopyableStream {
|
struct CopyableStream {
|
||||||
CopyableStream() {}
|
CopyableStream() {}
|
||||||
CopyableStream( CopyableStream const& other ) {
|
CopyableStream( CopyableStream const& other ) {
|
||||||
oss << other.oss.str();
|
oss << other.oss.str();
|
||||||
}
|
}
|
||||||
CopyableStream& operator=( CopyableStream const& other ) {
|
CopyableStream& operator=( CopyableStream const& other ) {
|
||||||
oss.str("");
|
oss.str(std::string());
|
||||||
oss << other.oss.str();
|
oss << other.oss.str();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResultBuilder {
|
class ResultBuilder : public DecomposedExpression {
|
||||||
public:
|
public:
|
||||||
ResultBuilder( char const* macroName,
|
ResultBuilder( char const* macroName,
|
||||||
SourceLineInfo const& lineInfo,
|
SourceLineInfo const& lineInfo,
|
||||||
@ -52,19 +50,15 @@ namespace Catch {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
|
|
||||||
template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
|
|
||||||
|
|
||||||
ResultBuilder& setResultType( ResultWas::OfType result );
|
ResultBuilder& setResultType( ResultWas::OfType result );
|
||||||
ResultBuilder& setResultType( bool result );
|
ResultBuilder& setResultType( bool result );
|
||||||
ResultBuilder& setLhs( std::string const& lhs );
|
|
||||||
ResultBuilder& setRhs( std::string const& rhs );
|
|
||||||
ResultBuilder& setOp( std::string const& op );
|
|
||||||
|
|
||||||
void endExpression();
|
void endExpression( DecomposedExpression const& expr );
|
||||||
|
|
||||||
|
virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE;
|
||||||
|
|
||||||
std::string reconstructExpression() const;
|
|
||||||
AssertionResult build() const;
|
AssertionResult build() const;
|
||||||
|
AssertionResult build( DecomposedExpression const& expr ) const;
|
||||||
|
|
||||||
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
|
||||||
void captureResult( ResultWas::OfType resultType );
|
void captureResult( ResultWas::OfType resultType );
|
||||||
@ -76,14 +70,12 @@ namespace Catch {
|
|||||||
bool shouldDebugBreak() const;
|
bool shouldDebugBreak() const;
|
||||||
bool allowThrows() const;
|
bool allowThrows() const;
|
||||||
|
|
||||||
|
template<typename ArgT, typename MatcherT>
|
||||||
|
void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AssertionInfo m_assertionInfo;
|
AssertionInfo m_assertionInfo;
|
||||||
AssertionResultData m_data;
|
AssertionResultData m_data;
|
||||||
struct ExprComponents {
|
|
||||||
ExprComponents() : testFalse( false ) {}
|
|
||||||
bool testFalse;
|
|
||||||
std::string lhs, rhs, op;
|
|
||||||
} m_exprComponents;
|
|
||||||
CopyableStream m_stream;
|
CopyableStream m_stream;
|
||||||
|
|
||||||
bool m_shouldDebugBreak;
|
bool m_shouldDebugBreak;
|
||||||
@ -106,6 +98,14 @@ namespace Catch {
|
|||||||
return ExpressionLhs<bool>( *this, value );
|
return ExpressionLhs<bool>( *this, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ArgT, typename MatcherT>
|
||||||
|
inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher,
|
||||||
|
char const* matcherString ) {
|
||||||
|
MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString );
|
||||||
|
setResultType( matcher.match( arg ) );
|
||||||
|
endExpression( expr );
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||||
|
@ -41,22 +41,10 @@ namespace Catch {
|
|||||||
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
|
|
||||||
m_exprComponents.lhs = lhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
|
|
||||||
m_exprComponents.rhs = rhs;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
|
|
||||||
m_exprComponents.op = op;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResultBuilder::endExpression() {
|
void ResultBuilder::endExpression( DecomposedExpression const& expr ) {
|
||||||
m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
|
AssertionResult result = build( expr );
|
||||||
captureExpression();
|
handleResult( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
|
||||||
@ -69,6 +57,7 @@ namespace Catch {
|
|||||||
setResultType( resultType );
|
setResultType( resultType );
|
||||||
captureExpression();
|
captureExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) {
|
||||||
if( expectedMessage.empty() )
|
if( expectedMessage.empty() )
|
||||||
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
|
captureExpectedException( Matchers::Impl::Generic::AllOf<std::string>() );
|
||||||
@ -78,7 +67,7 @@ namespace Catch {
|
|||||||
|
|
||||||
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
||||||
|
|
||||||
assert( m_exprComponents.testFalse == false );
|
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
||||||
AssertionResultData data = m_data;
|
AssertionResultData data = m_data;
|
||||||
data.resultType = ResultWas::Ok;
|
data.resultType = ResultWas::Ok;
|
||||||
data.reconstructedExpression = m_assertionInfo.capturedExpression;
|
data.reconstructedExpression = m_assertionInfo.capturedExpression;
|
||||||
@ -96,6 +85,7 @@ namespace Catch {
|
|||||||
AssertionResult result = build();
|
AssertionResult result = build();
|
||||||
handleResult( result );
|
handleResult( result );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultBuilder::handleResult( AssertionResult const& result )
|
void ResultBuilder::handleResult( AssertionResult const& result )
|
||||||
{
|
{
|
||||||
getResultCapture().assertionEnded( result );
|
getResultCapture().assertionEnded( result );
|
||||||
@ -107,6 +97,7 @@ namespace Catch {
|
|||||||
m_shouldThrow = true;
|
m_shouldThrow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultBuilder::react() {
|
void ResultBuilder::react() {
|
||||||
if( m_shouldThrow )
|
if( m_shouldThrow )
|
||||||
throw Catch::TestFailureException();
|
throw Catch::TestFailureException();
|
||||||
@ -117,43 +108,32 @@ namespace Catch {
|
|||||||
|
|
||||||
AssertionResult ResultBuilder::build() const
|
AssertionResult ResultBuilder::build() const
|
||||||
{
|
{
|
||||||
assert( m_data.resultType != ResultWas::Unknown );
|
return build( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAVEAT: The returned AssertionResult stores a pointer to the argument expr,
|
||||||
|
// a temporary DecomposedExpression, which in turn holds references to
|
||||||
|
// operands, possibly temporary as well.
|
||||||
|
// It should immediately be passed to handleResult; if the expression
|
||||||
|
// needs to be reported, its string expansion must be composed before
|
||||||
|
// the temporaries are destroyed.
|
||||||
|
AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const
|
||||||
|
{
|
||||||
|
assert( m_data.resultType != ResultWas::Unknown );
|
||||||
AssertionResultData data = m_data;
|
AssertionResultData data = m_data;
|
||||||
|
|
||||||
// Flip bool results if testFalse is set
|
// Flip bool results if FalseTest flag is set
|
||||||
if( m_exprComponents.testFalse ) {
|
if( isFalseTest( m_assertionInfo.resultDisposition ) ) {
|
||||||
if( data.resultType == ResultWas::Ok )
|
data.negate( expr.isBinaryExpression() );
|
||||||
data.resultType = ResultWas::ExpressionFailed;
|
|
||||||
else if( data.resultType == ResultWas::ExpressionFailed )
|
|
||||||
data.resultType = ResultWas::Ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.message = m_stream.oss.str();
|
data.message = m_stream.oss.str();
|
||||||
data.reconstructedExpression = reconstructExpression();
|
data.decomposedExpression = &expr; // for lazy reconstruction
|
||||||
if( m_exprComponents.testFalse ) {
|
|
||||||
if( m_exprComponents.op == "" )
|
|
||||||
data.reconstructedExpression = "!" + data.reconstructedExpression;
|
|
||||||
else
|
|
||||||
data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
|
|
||||||
}
|
|
||||||
return AssertionResult( m_assertionInfo, data );
|
return AssertionResult( m_assertionInfo, data );
|
||||||
}
|
}
|
||||||
std::string ResultBuilder::reconstructExpression() const {
|
|
||||||
if( m_exprComponents.op == "" )
|
void ResultBuilder::reconstructExpression( std::string& dest ) const {
|
||||||
return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.lhs;
|
dest = m_assertionInfo.capturedExpression;
|
||||||
else if( m_exprComponents.op == "matches" )
|
|
||||||
return m_exprComponents.lhs + " " + m_exprComponents.rhs;
|
|
||||||
else if( m_exprComponents.op != "!" ) {
|
|
||||||
if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
|
|
||||||
m_exprComponents.lhs.find("\n") == std::string::npos &&
|
|
||||||
m_exprComponents.rhs.find("\n") == std::string::npos )
|
|
||||||
return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
|
|
||||||
else
|
|
||||||
return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end namespace Catch
|
} // end namespace Catch
|
||||||
|
@ -147,7 +147,7 @@ namespace Catch {
|
|||||||
m_messages.clear();
|
m_messages.clear();
|
||||||
|
|
||||||
// Reset working state
|
// Reset working state
|
||||||
m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
|
||||||
m_lastResult = result;
|
m_lastResult = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ namespace Catch {
|
|||||||
virtual std::string getCurrentTestName() const {
|
virtual std::string getCurrentTestName() const {
|
||||||
return m_activeTestCase
|
return m_activeTestCase
|
||||||
? m_activeTestCase->getTestCaseInfo().name
|
? m_activeTestCase->getTestCaseInfo().name
|
||||||
: "";
|
: std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const AssertionResult* getLastResult() const {
|
virtual const AssertionResult* getLastResult() const {
|
||||||
@ -245,11 +245,11 @@ namespace Catch {
|
|||||||
deltaTotals.testCases.failed = 1;
|
deltaTotals.testCases.failed = 1;
|
||||||
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
m_reporter->testCaseEnded( TestCaseStats( testInfo,
|
||||||
deltaTotals,
|
deltaTotals,
|
||||||
"",
|
std::string(),
|
||||||
"",
|
std::string(),
|
||||||
false ) );
|
false ) );
|
||||||
m_totals.testCases.failed++;
|
m_totals.testCases.failed++;
|
||||||
testGroupEnded( "", m_totals, 1, 1 );
|
testGroupEnded( std::string(), m_totals, 1, 1 );
|
||||||
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ namespace Catch {
|
|||||||
Counts prevAssertions = m_totals.assertions;
|
Counts prevAssertions = m_totals.assertions;
|
||||||
double duration = 0;
|
double duration = 0;
|
||||||
try {
|
try {
|
||||||
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
|
m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal );
|
||||||
|
|
||||||
seedRng( *m_config );
|
seedRng( *m_config );
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ namespace Catch {
|
|||||||
|
|
||||||
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
|
||||||
|
|
||||||
if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
|
if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
|
oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
|
||||||
throw std::domain_error( oss.str().c_str() );
|
throw std::domain_error( oss.str().c_str() );
|
||||||
@ -51,7 +51,7 @@ namespace Catch {
|
|||||||
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
|
if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
|
oss << "error: tag alias, \"" << alias << "\" already registered.\n"
|
||||||
<< "\tFirst seen at " << find(alias)->lineInfo << "\n"
|
<< "\tFirst seen at " << find(alias)->lineInfo << '\n'
|
||||||
<< "\tRedefined at " << lineInfo;
|
<< "\tRedefined at " << lineInfo;
|
||||||
throw std::domain_error( oss.str().c_str() );
|
throw std::domain_error( oss.str().c_str() );
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
|
||||||
if( startsWith( tag, "." ) ||
|
if( startsWith( tag, '.' ) ||
|
||||||
tag == "hide" ||
|
tag == "hide" ||
|
||||||
tag == "!hide" )
|
tag == "!hide" )
|
||||||
return TestCaseInfo::IsHidden;
|
return TestCaseInfo::IsHidden;
|
||||||
|
@ -78,7 +78,7 @@ namespace Catch {
|
|||||||
|
|
||||||
ss << Colour( Colour::Red )
|
ss << Colour( Colour::Red )
|
||||||
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
<< "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n"
|
||||||
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
|
<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n'
|
||||||
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
<< "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl;
|
||||||
|
|
||||||
throw std::runtime_error(ss.str());
|
throw std::runtime_error(ss.str());
|
||||||
@ -110,7 +110,7 @@ namespace Catch {
|
|||||||
|
|
||||||
virtual void registerTest( TestCase const& testCase ) {
|
virtual void registerTest( TestCase const& testCase ) {
|
||||||
std::string name = testCase.getTestCaseInfo().name;
|
std::string name = testCase.getTestCaseInfo().name;
|
||||||
if( name == "" ) {
|
if( name.empty() ) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Anonymous test case " << ++m_unnamedCount;
|
oss << "Anonymous test case " << ++m_unnamedCount;
|
||||||
return registerTest( testCase.withName( oss.str() ) );
|
return registerTest( testCase.withName( oss.str() ) );
|
||||||
@ -159,7 +159,7 @@ namespace Catch {
|
|||||||
|
|
||||||
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
|
||||||
std::string className = classOrQualifiedMethodName;
|
std::string className = classOrQualifiedMethodName;
|
||||||
if( startsWith( className, "&" ) )
|
if( startsWith( className, '&' ) )
|
||||||
{
|
{
|
||||||
std::size_t lastColons = className.rfind( "::" );
|
std::size_t lastColons = className.rfind( "::" );
|
||||||
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
|
||||||
|
@ -102,7 +102,7 @@ std::string toString( int value ) {
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << value;
|
oss << value;
|
||||||
if( value > Detail::hexThreshold )
|
if( value > Detail::hexThreshold )
|
||||||
oss << " (0x" << std::hex << value << ")";
|
oss << " (0x" << std::hex << value << ')';
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ std::string toString( unsigned long value ) {
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << value;
|
oss << value;
|
||||||
if( value > Detail::hexThreshold )
|
if( value > Detail::hexThreshold )
|
||||||
oss << " (0x" << std::hex << value << ")";
|
oss << " (0x" << std::hex << value << ')';
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,14 +164,14 @@ std::string toString( long long value ) {
|
|||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << value;
|
oss << value;
|
||||||
if( value > Detail::hexThreshold )
|
if( value > Detail::hexThreshold )
|
||||||
oss << " (0x" << std::hex << value << ")";
|
oss << " (0x" << std::hex << value << ')';
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
std::string toString( unsigned long long value ) {
|
std::string toString( unsigned long long value ) {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << value;
|
oss << value;
|
||||||
if( value > Detail::hexThreshold )
|
if( value > Detail::hexThreshold )
|
||||||
oss << " (0x" << std::hex << value << ")";
|
oss << " (0x" << std::hex << value << ')';
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,11 +27,11 @@ namespace Catch
|
|||||||
m_wildcard( NoWildcard ),
|
m_wildcard( NoWildcard ),
|
||||||
m_pattern( adjustCase( pattern ) )
|
m_pattern( adjustCase( pattern ) )
|
||||||
{
|
{
|
||||||
if( startsWith( m_pattern, "*" ) ) {
|
if( startsWith( m_pattern, '*' ) ) {
|
||||||
m_pattern = m_pattern.substr( 1 );
|
m_pattern = m_pattern.substr( 1 );
|
||||||
m_wildcard = WildcardAtStart;
|
m_wildcard = WildcardAtStart;
|
||||||
}
|
}
|
||||||
if( endsWith( m_pattern, "*" ) ) {
|
if( endsWith( m_pattern, '*' ) ) {
|
||||||
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
|
||||||
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ namespace Catch {
|
|||||||
|
|
||||||
XmlWriter& writeBlankLine() {
|
XmlWriter& writeBlankLine() {
|
||||||
ensureTagClosed();
|
ensureTagClosed();
|
||||||
stream() << "\n";
|
stream() << '\n';
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +170,12 @@ namespace Catch {
|
|||||||
assert( !m_sectionStack.empty() );
|
assert( !m_sectionStack.empty() );
|
||||||
SectionNode& sectionNode = *m_sectionStack.back();
|
SectionNode& sectionNode = *m_sectionStack.back();
|
||||||
sectionNode.assertions.push_back( assertionStats );
|
sectionNode.assertions.push_back( assertionStats );
|
||||||
|
// AssertionResult holds a pointer to a temporary DecomposedExpression,
|
||||||
|
// which getExpandedExpression() calls to build the expression string.
|
||||||
|
// Our section stack copy of the assertionResult will likely outlive the
|
||||||
|
// temporary, so it must be expanded or discarded now to avoid calling
|
||||||
|
// a destroyed object later.
|
||||||
|
prepareExpandedExpression( sectionNode.assertions.back().assertionResult );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE {
|
||||||
@ -204,6 +210,13 @@ namespace Catch {
|
|||||||
|
|
||||||
virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
|
virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {}
|
||||||
|
|
||||||
|
virtual void prepareExpandedExpression( AssertionResult& result ) const {
|
||||||
|
if( result.isOk() )
|
||||||
|
result.discardDecomposedExpression();
|
||||||
|
else
|
||||||
|
result.expandDecomposedExpression();
|
||||||
|
}
|
||||||
|
|
||||||
Ptr<IConfig const> m_config;
|
Ptr<IConfig const> m_config;
|
||||||
std::ostream& stream;
|
std::ostream& stream;
|
||||||
std::vector<AssertionStats> m_assertions;
|
std::vector<AssertionStats> m_assertions;
|
||||||
|
9
projects/Benchmark/BenchMain.cpp
Normal file
9
projects/Benchmark/BenchMain.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 16/01/2017.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include "catch.hpp"
|
46
projects/Benchmark/StringificationBench.cpp
Normal file
46
projects/Benchmark/StringificationBench.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Created by Martin on 16/01/2017.
|
||||||
|
*
|
||||||
|
* 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)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
TEST_CASE("Successful tests -- REQUIRE", "[Success]") {
|
||||||
|
const size_t sz = 1 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<size_t> vec; vec.reserve(sz);
|
||||||
|
for (size_t i = 0; i < sz; ++i){
|
||||||
|
vec.push_back(i);
|
||||||
|
REQUIRE(vec.back() == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
TEST_CASE("Successful tests -- CHECK", "[Success]") {
|
||||||
|
const size_t sz = 1 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<size_t> vec; vec.reserve(sz);
|
||||||
|
for (size_t i = 0; i < sz; ++i){
|
||||||
|
vec.push_back(i);
|
||||||
|
CHECK(vec.back() == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
TEST_CASE("Unsuccessful tests -- CHECK", "[Failure]") {
|
||||||
|
const size_t sz = 1024 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<size_t> vec; vec.reserve(sz);
|
||||||
|
for (size_t i = 0; i < sz; ++i){
|
||||||
|
vec.push_back(i);
|
||||||
|
CHECK(vec.size() == i);
|
||||||
|
}
|
||||||
|
}
|
4
projects/Benchmark/readme.txt
Normal file
4
projects/Benchmark/readme.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
This is very much a work in progress.
|
||||||
|
The past results are standardized to a developer's machine,
|
||||||
|
the benchmarking script is basic and there are only 3 benchmarks,
|
||||||
|
but this should get better in time. For now, at least there is something to go by.
|
@ -0,0 +1,3 @@
|
|||||||
|
Successful tests -- CHECK: median: 3.38116 (s), stddev: 0.11567366292001534 (s)
|
||||||
|
Successful tests -- REQUIRE: median: 3.479955 (s), stddev: 0.16295972890734556 (s)
|
||||||
|
Unsuccessful tests -- CHECK: median: 1.966895 (s), stddev: 0.06323488524716572 (s)
|
@ -0,0 +1,3 @@
|
|||||||
|
Successful tests -- CHECK: median: 1.30312 (s), stddev: 0.08759818557862176 (s)
|
||||||
|
Successful tests -- REQUIRE: median: 1.341535 (s), stddev: 0.1479193390143576 (s)
|
||||||
|
Unsuccessful tests -- CHECK: median: 1.967755 (s), stddev: 0.07921104121269959 (s)
|
@ -0,0 +1,3 @@
|
|||||||
|
Successful tests -- CHECK: median: 1.2982 (s), stddev: 0.019540648829214084 (s)
|
||||||
|
Successful tests -- REQUIRE: median: 1.30102 (s), stddev: 0.014758430547392974 (s)
|
||||||
|
Unsuccessful tests -- CHECK: median: 15.520199999999999 (s), stddev: 0.09536359426485094 (s)
|
56
scripts/benchmarkRunner.py
Normal file
56
scripts/benchmarkRunner.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import subprocess, os, sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from collections import defaultdict
|
||||||
|
from statistics import median, stdev
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def get_commit_hash():
|
||||||
|
res = subprocess.run('git rev-parse HEAD'.split(), check=True, stdout=subprocess.PIPE, universal_newlines=True)
|
||||||
|
return res.stdout.strip()
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print('Usage: {} benchmark-binary'.format(sys.argv[0]))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
num_runs = 10
|
||||||
|
data = defaultdict(list)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_file(file):
|
||||||
|
|
||||||
|
def recursive_search(node):
|
||||||
|
if node.tag == 'TestCase':
|
||||||
|
results = node.find('OverallResult')
|
||||||
|
time = results.get('durationInSeconds')
|
||||||
|
data[node.get('name')].append(float(time))
|
||||||
|
elif node.tag in ('Group', 'Catch'):
|
||||||
|
for child in node:
|
||||||
|
recursive_search(child)
|
||||||
|
|
||||||
|
tree = ET.parse(file)
|
||||||
|
recursive_search(tree.getroot())
|
||||||
|
|
||||||
|
def run_benchmarks(binary):
|
||||||
|
call = [binary] + '-d yes -r xml -o'.split()
|
||||||
|
for i in range(num_runs):
|
||||||
|
file = 'temp{}.xml'.format(i)
|
||||||
|
print('Run number {}'.format(i))
|
||||||
|
subprocess.run(call + [file])
|
||||||
|
parse_file(file)
|
||||||
|
# Remove file right after parsing, because benchmark output can be big
|
||||||
|
os.remove(file)
|
||||||
|
|
||||||
|
|
||||||
|
# Run benchmarks
|
||||||
|
run_benchmarks(sys.argv[1])
|
||||||
|
|
||||||
|
result_file = '{:%Y-%m-%dT%H-%M-%S}-{}.result'.format(datetime.now(), get_commit_hash())
|
||||||
|
|
||||||
|
|
||||||
|
print('Writing results to {}'.format(result_file))
|
||||||
|
with open(result_file, 'w') as file:
|
||||||
|
for k in sorted(data):
|
||||||
|
file.write('{}: median: {} (s), stddev: {} (s)\n'.format(k, median(data[k]), stdev(data[k])))
|
Loading…
Reference in New Issue
Block a user