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