1 /* 2 * Created by Phil Nash on 04/03/2012. 3 * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 #ifndef TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED 9 #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED 10 11 #include "catch_common.h" 12 13 namespace Catch { 14 namespace Matchers { 15 namespace Impl { 16 17 template<typename ArgT> struct MatchAllOf; 18 template<typename ArgT> struct MatchAnyOf; 19 template<typename ArgT> struct MatchNotOf; 20 21 class MatcherUntypedBase { 22 public: toString() const23 std::string toString() const { 24 if( m_cachedToString.empty() ) 25 m_cachedToString = describe(); 26 return m_cachedToString; 27 } 28 29 protected: 30 virtual ~MatcherUntypedBase(); 31 virtual std::string describe() const = 0; 32 mutable std::string m_cachedToString; 33 private: 34 MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); 35 }; 36 37 template<typename ObjectT> 38 struct MatcherMethod { 39 virtual bool match( ObjectT const& arg ) const = 0; 40 }; 41 template<typename PtrT> 42 struct MatcherMethod<PtrT*> { 43 virtual bool match( PtrT* arg ) const = 0; 44 }; 45 46 template<typename ObjectT, typename ComparatorT = ObjectT> 47 struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> { 48 49 50 MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const; 51 MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const; 52 MatchNotOf<ComparatorT> operator ! () const; 53 }; 54 55 template<typename ArgT> 56 struct MatchAllOf : MatcherBase<ArgT> { matchCatch::Matchers::Impl::MatchAllOf57 virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { 58 for( std::size_t i = 0; i < m_matchers.size(); ++i ) { 59 if (!m_matchers[i]->match(arg)) 60 return false; 61 } 62 return true; 63 } describeCatch::Matchers::Impl::MatchAllOf64 virtual std::string describe() const CATCH_OVERRIDE { 65 std::string description; 66 description.reserve( 4 + m_matchers.size()*32 ); 67 description += "( "; 68 for( std::size_t i = 0; i < m_matchers.size(); ++i ) { 69 if( i != 0 ) 70 description += " and "; 71 description += m_matchers[i]->toString(); 72 } 73 description += " )"; 74 return description; 75 } 76 operator &&Catch::Matchers::Impl::MatchAllOf77 MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { 78 m_matchers.push_back( &other ); 79 return *this; 80 } 81 82 std::vector<MatcherBase<ArgT> const*> m_matchers; 83 }; 84 template<typename ArgT> 85 struct MatchAnyOf : MatcherBase<ArgT> { 86 matchCatch::Matchers::Impl::MatchAnyOf87 virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { 88 for( std::size_t i = 0; i < m_matchers.size(); ++i ) { 89 if (m_matchers[i]->match(arg)) 90 return true; 91 } 92 return false; 93 } describeCatch::Matchers::Impl::MatchAnyOf94 virtual std::string describe() const CATCH_OVERRIDE { 95 std::string description; 96 description.reserve( 4 + m_matchers.size()*32 ); 97 description += "( "; 98 for( std::size_t i = 0; i < m_matchers.size(); ++i ) { 99 if( i != 0 ) 100 description += " or "; 101 description += m_matchers[i]->toString(); 102 } 103 description += " )"; 104 return description; 105 } 106 operator ||Catch::Matchers::Impl::MatchAnyOf107 MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { 108 m_matchers.push_back( &other ); 109 return *this; 110 } 111 112 std::vector<MatcherBase<ArgT> const*> m_matchers; 113 }; 114 115 template<typename ArgT> 116 struct MatchNotOf : MatcherBase<ArgT> { 117 MatchNotOfCatch::Matchers::Impl::MatchNotOf118 MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} 119 matchCatch::Matchers::Impl::MatchNotOf120 virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { 121 return !m_underlyingMatcher.match( arg ); 122 } 123 describeCatch::Matchers::Impl::MatchNotOf124 virtual std::string describe() const CATCH_OVERRIDE { 125 return "not " + m_underlyingMatcher.toString(); 126 } 127 MatcherBase<ArgT> const& m_underlyingMatcher; 128 }; 129 130 template<typename ObjectT, typename ComparatorT> operator &&(MatcherBase const & other) const131 MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const { 132 return MatchAllOf<ComparatorT>() && *this && other; 133 } 134 template<typename ObjectT, typename ComparatorT> operator ||(MatcherBase const & other) const135 MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const { 136 return MatchAnyOf<ComparatorT>() || *this || other; 137 } 138 template<typename ObjectT, typename ComparatorT> operator !() const139 MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const { 140 return MatchNotOf<ComparatorT>( *this ); 141 } 142 143 } // namespace Impl 144 145 146 // The following functions create the actual matcher objects. 147 // This allows the types to be inferred 148 // - deprecated: prefer ||, && and ! 149 template<typename T> Not(Impl::MatcherBase<T> const & underlyingMatcher)150 Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) { 151 return Impl::MatchNotOf<T>( underlyingMatcher ); 152 } 153 template<typename T> AllOf(Impl::MatcherBase<T> const & m1,Impl::MatcherBase<T> const & m2)154 Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { 155 return Impl::MatchAllOf<T>() && m1 && m2; 156 } 157 template<typename T> AllOf(Impl::MatcherBase<T> const & m1,Impl::MatcherBase<T> const & m2,Impl::MatcherBase<T> const & m3)158 Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { 159 return Impl::MatchAllOf<T>() && m1 && m2 && m3; 160 } 161 template<typename T> AnyOf(Impl::MatcherBase<T> const & m1,Impl::MatcherBase<T> const & m2)162 Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { 163 return Impl::MatchAnyOf<T>() || m1 || m2; 164 } 165 template<typename T> AnyOf(Impl::MatcherBase<T> const & m1,Impl::MatcherBase<T> const & m2,Impl::MatcherBase<T> const & m3)166 Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { 167 return Impl::MatchAnyOf<T>() || m1 || m2 || m3; 168 } 169 170 } // namespace Matchers 171 172 using namespace Matchers; 173 using Matchers::Impl::MatcherBase; 174 175 } // namespace Catch 176 177 #endif // TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED 178