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 #include <string> 14 #include <vector> 15 16 namespace Catch { 17 namespace Matchers { 18 namespace Impl { 19 20 template<typename ArgT> struct MatchAllOf; 21 template<typename ArgT> struct MatchAnyOf; 22 template<typename ArgT> struct MatchNotOf; 23 24 class MatcherUntypedBase { 25 public: 26 MatcherUntypedBase() = default; 27 MatcherUntypedBase ( MatcherUntypedBase const& ) = default; 28 MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; 29 std::string toString() const; 30 31 protected: 32 virtual ~MatcherUntypedBase(); 33 virtual std::string describe() const = 0; 34 mutable std::string m_cachedToString; 35 }; 36 37 #ifdef __clang__ 38 # pragma clang diagnostic push 39 # pragma clang diagnostic ignored "-Wnon-virtual-dtor" 40 #endif 41 42 template<typename ObjectT> 43 struct MatcherMethod { 44 virtual bool match( ObjectT const& arg ) const = 0; 45 }; 46 47 #if defined(__OBJC__) 48 // Hack to fix Catch GH issue #1661. Could use id for generic Object support. 49 // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation 50 template<> 51 struct MatcherMethod<NSString*> { 52 virtual bool match( NSString* arg ) const = 0; 53 }; 54 #endif 55 56 #ifdef __clang__ 57 # pragma clang diagnostic pop 58 #endif 59 60 template<typename T> 61 struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { 62 63 64 MatchAllOf<T> operator && ( MatcherBase const& other ) const; 65 MatchAnyOf<T> operator || ( MatcherBase const& other ) const; 66 MatchNotOf<T> operator ! () const; 67 }; 68 69 template<typename ArgT> 70 struct MatchAllOf : MatcherBase<ArgT> { 71 bool match( ArgT const& arg ) const override { 72 for( auto matcher : m_matchers ) { 73 if (!matcher->match(arg)) 74 return false; 75 } 76 return true; 77 } 78 std::string describe() const override { 79 std::string description; 80 description.reserve( 4 + m_matchers.size()*32 ); 81 description += "( "; 82 bool first = true; 83 for( auto matcher : m_matchers ) { 84 if( first ) 85 first = false; 86 else 87 description += " and "; 88 description += matcher->toString(); 89 } 90 description += " )"; 91 return description; 92 } 93 94 MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { 95 auto copy(*this); 96 copy.m_matchers.push_back( &other ); 97 return copy; 98 } 99 100 std::vector<MatcherBase<ArgT> const*> m_matchers; 101 }; 102 template<typename ArgT> 103 struct MatchAnyOf : MatcherBase<ArgT> { 104 105 bool match( ArgT const& arg ) const override { 106 for( auto matcher : m_matchers ) { 107 if (matcher->match(arg)) 108 return true; 109 } 110 return false; 111 } 112 std::string describe() const override { 113 std::string description; 114 description.reserve( 4 + m_matchers.size()*32 ); 115 description += "( "; 116 bool first = true; 117 for( auto matcher : m_matchers ) { 118 if( first ) 119 first = false; 120 else 121 description += " or "; 122 description += matcher->toString(); 123 } 124 description += " )"; 125 return description; 126 } 127 128 MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { 129 auto copy(*this); 130 copy.m_matchers.push_back( &other ); 131 return copy; 132 } 133 134 std::vector<MatcherBase<ArgT> const*> m_matchers; 135 }; 136 137 template<typename ArgT> 138 struct MatchNotOf : MatcherBase<ArgT> { 139 140 MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} 141 142 bool match( ArgT const& arg ) const override { 143 return !m_underlyingMatcher.match( arg ); 144 } 145 146 std::string describe() const override { 147 return "not " + m_underlyingMatcher.toString(); 148 } 149 MatcherBase<ArgT> const& m_underlyingMatcher; 150 }; 151 152 template<typename T> 153 MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { 154 return MatchAllOf<T>() && *this && other; 155 } 156 template<typename T> 157 MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { 158 return MatchAnyOf<T>() || *this || other; 159 } 160 template<typename T> 161 MatchNotOf<T> MatcherBase<T>::operator ! () const { 162 return MatchNotOf<T>( *this ); 163 } 164 165 } // namespace Impl 166 167 } // namespace Matchers 168 169 using namespace Matchers; 170 using Matchers::Impl::MatcherBase; 171 172 } // namespace Catch 173 174 #endif // TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED 175