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         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 T>
47         struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
48 
49 
50             MatchAllOf<T> operator && ( MatcherBase const& other ) const;
51             MatchAnyOf<T> operator || ( MatcherBase const& other ) const;
52             MatchNotOf<T> operator ! () const;
53         };
54 
55         template<typename ArgT>
56         struct MatchAllOf : MatcherBase<ArgT> {
57             bool match( ArgT const& arg ) const override {
58                 for( auto matcher : m_matchers ) {
59                     if (!matcher->match(arg))
60                         return false;
61                 }
62                 return true;
63             }
64             std::string describe() const override {
65                 std::string description;
66                 description.reserve( 4 + m_matchers.size()*32 );
67                 description += "( ";
68                 bool first = true;
69                 for( auto matcher : m_matchers ) {
70                     if( first )
71                         first = false;
72                     else
73                         description += " and ";
74                     description += matcher->toString();
75                 }
76                 description += " )";
77                 return description;
78             }
79 
80             MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
81                 m_matchers.push_back( &other );
82                 return *this;
83             }
84 
85             std::vector<MatcherBase<ArgT> const*> m_matchers;
86         };
87         template<typename ArgT>
88         struct MatchAnyOf : MatcherBase<ArgT> {
89 
90             bool match( ArgT const& arg ) const override {
91                 for( auto matcher : m_matchers ) {
92                     if (matcher->match(arg))
93                         return true;
94                 }
95                 return false;
96             }
97             std::string describe() const override {
98                 std::string description;
99                 description.reserve( 4 + m_matchers.size()*32 );
100                 description += "( ";
101                 bool first = true;
102                 for( auto matcher : m_matchers ) {
103                     if( first )
104                         first = false;
105                     else
106                         description += " or ";
107                     description += matcher->toString();
108                 }
109                 description += " )";
110                 return description;
111             }
112 
113             MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
114                 m_matchers.push_back( &other );
115                 return *this;
116             }
117 
118             std::vector<MatcherBase<ArgT> const*> m_matchers;
119         };
120 
121         template<typename ArgT>
122         struct MatchNotOf : MatcherBase<ArgT> {
123 
124             MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
125 
126             bool match( ArgT const& arg ) const override {
127                 return !m_underlyingMatcher.match( arg );
128             }
129 
130             std::string describe() const override {
131                 return "not " + m_underlyingMatcher.toString();
132             }
133             MatcherBase<ArgT> const& m_underlyingMatcher;
134         };
135 
136         template<typename T>
137         MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {
138             return MatchAllOf<T>() && *this && other;
139         }
140         template<typename T>
141         MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {
142             return MatchAnyOf<T>() || *this || other;
143         }
144         template<typename T>
145         MatchNotOf<T> MatcherBase<T>::operator ! () const {
146             return MatchNotOf<T>( *this );
147         }
148 
149     } // namespace Impl
150 
151 } // namespace Matchers
152 
153 using namespace Matchers;
154 using Matchers::Impl::MatcherBase;
155 
156 } // namespace Catch
157 
158 #endif // TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
159