mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 13:26:10 +01:00
New Matchers implementation
- simpler - less templates and machinery - no cloning, copying or unnecessary heap allocations - better factored
This commit is contained in:
parent
5530303be7
commit
7fed25ad1f
@ -154,6 +154,7 @@ set(INTERNAL_HEADERS
|
|||||||
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.hpp
|
${HEADER_DIR}/internal/catch_legacy_reporter_adapter.hpp
|
||||||
${HEADER_DIR}/internal/catch_list.hpp
|
${HEADER_DIR}/internal/catch_list.hpp
|
||||||
${HEADER_DIR}/internal/catch_matchers.hpp
|
${HEADER_DIR}/internal/catch_matchers.hpp
|
||||||
|
${HEADER_DIR}/internal/catch_matchers_string.hpp
|
||||||
${HEADER_DIR}/internal/catch_message.h
|
${HEADER_DIR}/internal/catch_message.h
|
||||||
${HEADER_DIR}/internal/catch_message.hpp
|
${HEADER_DIR}/internal/catch_message.hpp
|
||||||
${HEADER_DIR}/internal/catch_notimplemented_exception.h
|
${HEADER_DIR}/internal/catch_notimplemented_exception.h
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "internal/catch_generators.hpp"
|
#include "internal/catch_generators.hpp"
|
||||||
#include "internal/catch_interfaces_exception.h"
|
#include "internal/catch_interfaces_exception.h"
|
||||||
#include "internal/catch_approx.hpp"
|
#include "internal/catch_approx.hpp"
|
||||||
#include "internal/catch_matchers.hpp"
|
#include "internal/catch_matchers_string.hpp"
|
||||||
#include "internal/catch_compiler_capabilities.h"
|
#include "internal/catch_compiler_capabilities.h"
|
||||||
#include "internal/catch_interfaces_tag_alias_registry.h"
|
#include "internal/catch_interfaces_tag_alias_registry.h"
|
||||||
|
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "catch_compiler_capabilities.h"
|
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
|
|
||||||
struct IConfig;
|
struct IConfig;
|
||||||
|
@ -91,11 +91,6 @@ namespace Catch {
|
|||||||
TestSpec::TagPattern::~TagPattern() {}
|
TestSpec::TagPattern::~TagPattern() {}
|
||||||
TestSpec::ExcludedPattern::~ExcludedPattern() {}
|
TestSpec::ExcludedPattern::~ExcludedPattern() {}
|
||||||
|
|
||||||
Matchers::Impl::StdString::Equals::~Equals() {}
|
|
||||||
Matchers::Impl::StdString::Contains::~Contains() {}
|
|
||||||
Matchers::Impl::StdString::StartsWith::~StartsWith() {}
|
|
||||||
Matchers::Impl::StdString::EndsWith::~EndsWith() {}
|
|
||||||
|
|
||||||
void Config::dummy() {}
|
void Config::dummy() {}
|
||||||
|
|
||||||
namespace TestCaseTracking {
|
namespace TestCaseTracking {
|
||||||
|
@ -8,313 +8,152 @@
|
|||||||
#ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
#ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
||||||
#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_common.h"
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
namespace Matchers {
|
namespace Matchers {
|
||||||
namespace Impl {
|
namespace Impl {
|
||||||
|
|
||||||
namespace Generic {
|
template<typename ArgT> struct MatchAllOf;
|
||||||
template<typename ExpressionT> class AllOf;
|
template<typename ArgT> struct MatchAnyOf;
|
||||||
template<typename ExpressionT> class AnyOf;
|
template<typename ArgT> struct MatchNotOf;
|
||||||
template<typename ExpressionT> class Not;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ExpressionT>
|
class MatcherUntypedBase {
|
||||||
struct Matcher : SharedImpl<IShared>
|
|
||||||
{
|
|
||||||
typedef ExpressionT ExpressionType;
|
|
||||||
|
|
||||||
virtual ~Matcher() {}
|
|
||||||
virtual Ptr<Matcher> clone() const = 0;
|
|
||||||
virtual bool match( ExpressionT const& expr ) const = 0;
|
|
||||||
virtual std::string toString() const = 0;
|
|
||||||
|
|
||||||
Generic::AllOf<ExpressionT> operator && ( Matcher<ExpressionT> const& other ) const;
|
|
||||||
Generic::AnyOf<ExpressionT> operator || ( Matcher<ExpressionT> const& other ) const;
|
|
||||||
Generic::Not<ExpressionT> operator ! () const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename DerivedT, typename ExpressionT>
|
|
||||||
struct MatcherImpl : Matcher<ExpressionT> {
|
|
||||||
|
|
||||||
virtual Ptr<Matcher<ExpressionT> > clone() const {
|
|
||||||
return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Generic {
|
|
||||||
template<typename ExpressionT>
|
|
||||||
class Not : public MatcherImpl<Not<ExpressionT>, ExpressionT> {
|
|
||||||
public:
|
public:
|
||||||
explicit Not( Matcher<ExpressionT> const& matcher ) : m_matcher(matcher.clone()) {}
|
std::string toString() const {
|
||||||
Not( Not const& other ) : m_matcher( other.m_matcher ) {}
|
if( m_cachedToString.empty() )
|
||||||
|
m_cachedToString = toStringUncached();
|
||||||
virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE {
|
return m_cachedToString;
|
||||||
return !m_matcher->match( expr );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string toString() const CATCH_OVERRIDE {
|
protected:
|
||||||
return "not " + m_matcher->toString();
|
virtual std::string toStringUncached() const = 0;
|
||||||
}
|
mutable std::string m_cachedToString;
|
||||||
private:
|
|
||||||
Ptr< Matcher<ExpressionT> > m_matcher;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ExpressionT>
|
template<typename ArgT>
|
||||||
class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
|
struct MatcherBase : MatcherUntypedBase {
|
||||||
public:
|
|
||||||
|
|
||||||
AllOf() {}
|
virtual bool match( ArgT const& arg ) const = 0;
|
||||||
AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
||||||
|
|
||||||
AllOf& add( Matcher<ExpressionT> const& matcher ) {
|
MatchAllOf<ArgT> operator && ( MatcherBase const& other ) const;
|
||||||
m_matchers.push_back( matcher.clone() );
|
MatchAnyOf<ArgT> operator || ( MatcherBase const& other ) const;
|
||||||
return *this;
|
MatchNotOf<ArgT> operator ! () const;
|
||||||
}
|
};
|
||||||
virtual bool match( ExpressionT const& expr ) const
|
|
||||||
{
|
template<typename ArgT>
|
||||||
for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
struct MatchAllOf : MatcherBase<ArgT> {
|
||||||
if( !m_matchers[i]->match( expr ) )
|
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||||
|
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||||
|
if (!m_matchers[i]->match(arg))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
virtual std::string toString() const {
|
virtual std::string toStringUncached() const CATCH_OVERRIDE {
|
||||||
std::ostringstream oss;
|
std::string description;
|
||||||
oss << "( ";
|
description.reserve( 4 + m_matchers.size()*32 );
|
||||||
|
description += "( ";
|
||||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||||
if( i != 0 )
|
if( i != 0 )
|
||||||
oss << " and ";
|
description += " and ";
|
||||||
oss << m_matchers[i]->toString();
|
description += m_matchers[i]->toString();
|
||||||
}
|
}
|
||||||
oss << " )";
|
description += " )";
|
||||||
return oss.str();
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
AllOf operator && ( Matcher<ExpressionT> const& other ) const {
|
MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
|
||||||
AllOf allOfExpr( *this );
|
m_matchers.push_back( &other );
|
||||||
allOfExpr.add( other );
|
|
||||||
return allOfExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ExpressionT>
|
|
||||||
class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
AnyOf() {}
|
|
||||||
AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
|
|
||||||
|
|
||||||
AnyOf& add( Matcher<ExpressionT> const& matcher ) {
|
|
||||||
m_matchers.push_back( matcher.clone() );
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
virtual bool match( ExpressionT const& expr ) const
|
|
||||||
{
|
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||||
for( std::size_t i = 0; i < m_matchers.size(); ++i )
|
};
|
||||||
if( m_matchers[i]->match( expr ) )
|
template<typename ArgT>
|
||||||
|
struct MatchAnyOf : MatcherBase<ArgT> {
|
||||||
|
|
||||||
|
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||||
|
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||||
|
if (m_matchers[i]->match(arg))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual std::string toString() const {
|
virtual std::string toStringUncached() const CATCH_OVERRIDE {
|
||||||
std::ostringstream oss;
|
std::string description;
|
||||||
oss << "( ";
|
description.reserve( 4 + m_matchers.size()*32 );
|
||||||
|
description += "( ";
|
||||||
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
|
||||||
if( i != 0 )
|
if( i != 0 )
|
||||||
oss << " or ";
|
description += " or ";
|
||||||
oss << m_matchers[i]->toString();
|
description += m_matchers[i]->toString();
|
||||||
}
|
}
|
||||||
oss << " )";
|
description += " )";
|
||||||
return oss.str();
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyOf operator || ( Matcher<ExpressionT> const& other ) const {
|
MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
|
||||||
AnyOf anyOfExpr( *this );
|
m_matchers.push_back( &other );
|
||||||
anyOfExpr.add( other );
|
return *this;
|
||||||
return anyOfExpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
std::vector<MatcherBase<ArgT> const*> m_matchers;
|
||||||
std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Generic
|
template<typename ArgT>
|
||||||
|
struct MatchNotOf : MatcherBase<ArgT> {
|
||||||
|
|
||||||
template<typename ExpressionT>
|
MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
|
||||||
Generic::AllOf<ExpressionT> Matcher<ExpressionT>::operator && ( Matcher<ExpressionT> const& other ) const {
|
|
||||||
Generic::AllOf<ExpressionT> allOfExpr;
|
|
||||||
allOfExpr.add( *this );
|
|
||||||
allOfExpr.add( other );
|
|
||||||
return allOfExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ExpressionT>
|
|
||||||
Generic::AnyOf<ExpressionT> Matcher<ExpressionT>::operator || ( Matcher<ExpressionT> const& other ) const {
|
|
||||||
Generic::AnyOf<ExpressionT> anyOfExpr;
|
|
||||||
anyOfExpr.add( *this );
|
|
||||||
anyOfExpr.add( other );
|
|
||||||
return anyOfExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ExpressionT>
|
|
||||||
Generic::Not<ExpressionT> Matcher<ExpressionT>::operator ! () const {
|
|
||||||
return Generic::Not<ExpressionT>( *this );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace StdString {
|
|
||||||
|
|
||||||
inline std::string makeString( std::string const& str ) { return str; }
|
|
||||||
inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
|
|
||||||
|
|
||||||
struct CasedString
|
|
||||||
{
|
|
||||||
CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
|
|
||||||
: m_caseSensitivity( caseSensitivity ),
|
|
||||||
m_str( adjustString( str ) )
|
|
||||||
{}
|
|
||||||
std::string adjustString( std::string const& str ) const {
|
|
||||||
return m_caseSensitivity == CaseSensitive::No
|
|
||||||
? toLower( str )
|
|
||||||
: str;
|
|
||||||
|
|
||||||
|
virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE {
|
||||||
|
return !m_underlyingMatcher.match( arg );
|
||||||
}
|
}
|
||||||
std::string toStringSuffix() const
|
|
||||||
{
|
virtual std::string toStringUncached() const CATCH_OVERRIDE {
|
||||||
return m_caseSensitivity == CaseSensitive::No
|
return "not " + m_underlyingMatcher.toString();
|
||||||
? " (case insensitive)"
|
|
||||||
: std::string();
|
|
||||||
}
|
}
|
||||||
CaseSensitive::Choice m_caseSensitivity;
|
MatcherBase<ArgT> const& m_underlyingMatcher;
|
||||||
std::string m_str;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Equals : MatcherImpl<Equals, std::string> {
|
template<typename ArgT>
|
||||||
Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
MatchAllOf<ArgT> MatcherBase<ArgT>::operator && ( MatcherBase const& other ) const {
|
||||||
: m_data( str, caseSensitivity )
|
return MatchAllOf<ArgT>() && *this && other;
|
||||||
{}
|
}
|
||||||
Equals( Equals const& other ) : m_data( other.m_data ){}
|
template<typename ArgT>
|
||||||
|
MatchAnyOf<ArgT> MatcherBase<ArgT>::operator || ( MatcherBase const& other ) const {
|
||||||
|
return MatchAnyOf<ArgT>() || *this || other;
|
||||||
|
}
|
||||||
|
template<typename ArgT>
|
||||||
|
MatchNotOf<ArgT> MatcherBase<ArgT>::operator ! () const {
|
||||||
|
return MatchNotOf<ArgT>( *this );
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~Equals();
|
|
||||||
|
|
||||||
virtual bool match( std::string const& expr ) const {
|
|
||||||
return m_data.m_str == m_data.adjustString( expr );;
|
|
||||||
}
|
|
||||||
virtual std::string toString() const {
|
|
||||||
return "equals: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
CasedString m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Contains : MatcherImpl<Contains, std::string> {
|
|
||||||
Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
||||||
: m_data( substr, caseSensitivity ){}
|
|
||||||
Contains( Contains const& other ) : m_data( other.m_data ){}
|
|
||||||
|
|
||||||
virtual ~Contains();
|
|
||||||
|
|
||||||
virtual bool match( std::string const& expr ) const {
|
|
||||||
return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos;
|
|
||||||
}
|
|
||||||
virtual std::string toString() const {
|
|
||||||
return "contains: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
CasedString m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StartsWith : MatcherImpl<StartsWith, std::string> {
|
|
||||||
StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
||||||
: m_data( substr, caseSensitivity ){}
|
|
||||||
|
|
||||||
StartsWith( StartsWith const& other ) : m_data( other.m_data ){}
|
|
||||||
|
|
||||||
virtual ~StartsWith();
|
|
||||||
|
|
||||||
virtual bool match( std::string const& expr ) const {
|
|
||||||
return startsWith( m_data.adjustString( expr ), m_data.m_str );
|
|
||||||
}
|
|
||||||
virtual std::string toString() const {
|
|
||||||
return "starts with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
CasedString m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EndsWith : MatcherImpl<EndsWith, std::string> {
|
|
||||||
EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes )
|
|
||||||
: m_data( substr, caseSensitivity ){}
|
|
||||||
EndsWith( EndsWith const& other ) : m_data( other.m_data ){}
|
|
||||||
|
|
||||||
virtual ~EndsWith();
|
|
||||||
|
|
||||||
virtual bool match( std::string const& expr ) const {
|
|
||||||
return endsWith( m_data.adjustString( expr ), m_data.m_str );
|
|
||||||
}
|
|
||||||
virtual std::string toString() const {
|
|
||||||
return "ends with: \"" + m_data.m_str + '"' + m_data.toStringSuffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
CasedString m_data;
|
|
||||||
};
|
|
||||||
} // namespace StdString
|
|
||||||
} // namespace Impl
|
} // namespace Impl
|
||||||
|
|
||||||
|
|
||||||
// The following functions create the actual matcher objects.
|
// The following functions create the actual matcher objects.
|
||||||
// This allows the types to be inferred
|
// This allows the types to be inferred
|
||||||
template<typename ExpressionT>
|
// - deprecated: prefer ||, && and !
|
||||||
inline Impl::Generic::Not<ExpressionT> Not( Impl::Matcher<ExpressionT> const& m ) {
|
template<typename T>
|
||||||
return Impl::Generic::Not<ExpressionT>( m );
|
inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) {
|
||||||
|
return Impl::MatchNotOf<T>( underlyingMatcher );
|
||||||
}
|
}
|
||||||
|
template<typename T>
|
||||||
template<typename ExpressionT>
|
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
|
||||||
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
return Impl::MatchAllOf<T>() && m1 && m2;
|
||||||
Impl::Matcher<ExpressionT> const& m2 ) {
|
|
||||||
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
|
|
||||||
}
|
}
|
||||||
template<typename ExpressionT>
|
template<typename T>
|
||||||
inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
|
inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
|
||||||
Impl::Matcher<ExpressionT> const& m2,
|
return Impl::MatchAllOf<T>() && m1 && m2 && m3;
|
||||||
Impl::Matcher<ExpressionT> const& m3 ) {
|
|
||||||
return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
||||||
}
|
}
|
||||||
template<typename ExpressionT>
|
template<typename T>
|
||||||
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) {
|
||||||
Impl::Matcher<ExpressionT> const& m2 ) {
|
return Impl::MatchAnyOf<T>() || m1 || m2;
|
||||||
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
|
|
||||||
}
|
}
|
||||||
template<typename ExpressionT>
|
template<typename T>
|
||||||
inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
|
inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) {
|
||||||
Impl::Matcher<ExpressionT> const& m2,
|
return Impl::MatchAnyOf<T>() || m1 || m2 || m3;
|
||||||
Impl::Matcher<ExpressionT> const& m3 ) {
|
|
||||||
return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
||||||
return Impl::StdString::Equals( str, caseSensitivity );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
||||||
return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
||||||
return Impl::StdString::Contains( substr, caseSensitivity );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
|
||||||
return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) {
|
|
||||||
return Impl::StdString::StartsWith( substr );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::StartsWith StartsWith( const char* substr ) {
|
|
||||||
return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) {
|
|
||||||
return Impl::StdString::EndsWith( substr );
|
|
||||||
}
|
|
||||||
inline Impl::StdString::EndsWith EndsWith( const char* substr ) {
|
|
||||||
return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Matchers
|
} // namespace Matchers
|
||||||
|
114
include/internal/catch_matchers_string.hpp
Normal file
114
include/internal/catch_matchers_string.hpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 08/02/2017.
|
||||||
|
* Copyright (c) 2017 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_MATCHERS_STRING_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_MATCHERS_STRING_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "catch_matchers.hpp"
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
namespace Matchers {
|
||||||
|
|
||||||
|
namespace StdString {
|
||||||
|
|
||||||
|
struct CasedString
|
||||||
|
{
|
||||||
|
CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
|
||||||
|
: m_caseSensitivity( caseSensitivity ),
|
||||||
|
m_str( adjustString( str ) )
|
||||||
|
{}
|
||||||
|
std::string adjustString( std::string const& str ) const {
|
||||||
|
return m_caseSensitivity == CaseSensitive::No
|
||||||
|
? toLower( str )
|
||||||
|
: str;
|
||||||
|
}
|
||||||
|
std::string caseSensitivitySuffix() const {
|
||||||
|
return m_caseSensitivity == CaseSensitive::No
|
||||||
|
? " (case insensitive)"
|
||||||
|
: std::string();
|
||||||
|
}
|
||||||
|
CaseSensitive::Choice m_caseSensitivity;
|
||||||
|
std::string m_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
// !TBD Move impl
|
||||||
|
struct StringMatcherBase : Impl::MatcherBase<std::string> {
|
||||||
|
StringMatcherBase( std::string operation, CasedString const& comparator )
|
||||||
|
: m_comparator( comparator ),
|
||||||
|
m_operation( operation ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string toStringUncached() const CATCH_OVERRIDE {
|
||||||
|
std::string description;
|
||||||
|
description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
|
||||||
|
m_comparator.caseSensitivitySuffix().size());
|
||||||
|
description += m_operation;
|
||||||
|
description += ": \"";
|
||||||
|
description += m_comparator.m_str;
|
||||||
|
description += "\"";
|
||||||
|
description += m_comparator.caseSensitivitySuffix();
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
CasedString m_comparator;
|
||||||
|
std::string m_operation;
|
||||||
|
};
|
||||||
|
|
||||||
|
// !TBD Move impl
|
||||||
|
struct EqualsMatcher : StringMatcherBase {
|
||||||
|
EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
|
||||||
|
|
||||||
|
virtual bool match( std::string const& source ) const CATCH_OVERRIDE {
|
||||||
|
return m_comparator.adjustString( source ) == m_comparator.m_str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct ContainsMatcher : StringMatcherBase {
|
||||||
|
ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
|
||||||
|
|
||||||
|
virtual bool match( std::string const& source ) const CATCH_OVERRIDE {
|
||||||
|
return contains( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct StartsWithMatcher : StringMatcherBase {
|
||||||
|
StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
|
||||||
|
|
||||||
|
virtual bool match( std::string const& source ) const CATCH_OVERRIDE {
|
||||||
|
return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct EndsWithMatcher : StringMatcherBase {
|
||||||
|
EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
|
||||||
|
|
||||||
|
virtual bool match( std::string const& source ) const CATCH_OVERRIDE {
|
||||||
|
return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace StdString
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// The following functions create the actual matcher objects.
|
||||||
|
// This allows the types to be inferred
|
||||||
|
|
||||||
|
inline StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||||
|
return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||||
|
}
|
||||||
|
inline StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||||
|
return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||||
|
}
|
||||||
|
inline StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||||
|
return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||||
|
}
|
||||||
|
inline StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) {
|
||||||
|
return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Matchers
|
||||||
|
} // namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_MATCHERS_STRING_HPP_INCLUDED
|
@ -64,7 +64,7 @@ namespace Catch {
|
|||||||
void captureResult( ResultWas::OfType resultType );
|
void captureResult( ResultWas::OfType resultType );
|
||||||
void captureExpression();
|
void captureExpression();
|
||||||
void captureExpectedException( std::string const& expectedMessage );
|
void captureExpectedException( std::string const& expectedMessage );
|
||||||
void captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher );
|
void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher );
|
||||||
void handleResult( AssertionResult const& result );
|
void handleResult( AssertionResult const& result );
|
||||||
void react();
|
void react();
|
||||||
bool shouldDebugBreak() const;
|
bool shouldDebugBreak() const;
|
||||||
@ -106,6 +106,7 @@ namespace Catch {
|
|||||||
endExpression( expr );
|
endExpression( expr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Catch
|
} // namespace Catch
|
||||||
|
|
||||||
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
#endif // TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
|
||||||
|
@ -60,12 +60,13 @@ namespace Catch {
|
|||||||
|
|
||||||
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::MatchAllOf<std::string>() );
|
||||||
else
|
else
|
||||||
captureExpectedException( Matchers::Equals( expectedMessage ) );
|
captureExpectedException( Matchers::Equals( expectedMessage ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher<std::string> const& matcher ) {
|
|
||||||
|
void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) {
|
||||||
|
|
||||||
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
assert( !isFalseTest( m_assertionInfo.resultDisposition ) );
|
||||||
AssertionResultData data = m_data;
|
AssertionResultData data = m_data;
|
||||||
|
Loading…
Reference in New Issue
Block a user