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