1 /*
2  *  Created by Phil on 11/5/2012.
3  *  Copyright 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_EXPRESSION_LHS_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
10 
11 #include "catch_result_builder.h"
12 #include "catch_evaluate.hpp"
13 #include "catch_tostring.h"
14 
15 namespace Catch {
16 
17 template<typename LhsT, Internal::Operator Op, typename RhsT>
18 class BinaryExpression;
19 
20 template<typename ArgT, typename MatcherT>
21 class MatchExpression;
22 
23 // Wraps the LHS of an expression and overloads comparison operators
24 // for also capturing those and RHS (if any)
25 template<typename T>
26 class ExpressionLhs : public DecomposedExpression {
27 public:
ExpressionLhs(ResultBuilder & rb,T lhs)28     ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {}
29 
30     ExpressionLhs& operator = ( const ExpressionLhs& );
31 
32     template<typename RhsT>
33     BinaryExpression<T, Internal::IsEqualTo, RhsT const&>
operator ==(RhsT const & rhs)34     operator == ( RhsT const& rhs ) {
35         return captureExpression<Internal::IsEqualTo>( rhs );
36     }
37 
38     template<typename RhsT>
39     BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&>
operator !=(RhsT const & rhs)40     operator != ( RhsT const& rhs ) {
41         return captureExpression<Internal::IsNotEqualTo>( rhs );
42     }
43 
44     template<typename RhsT>
45     BinaryExpression<T, Internal::IsLessThan, RhsT const&>
operator <(RhsT const & rhs)46     operator < ( RhsT const& rhs ) {
47         return captureExpression<Internal::IsLessThan>( rhs );
48     }
49 
50     template<typename RhsT>
51     BinaryExpression<T, Internal::IsGreaterThan, RhsT const&>
operator >(RhsT const & rhs)52     operator > ( RhsT const& rhs ) {
53         return captureExpression<Internal::IsGreaterThan>( rhs );
54     }
55 
56     template<typename RhsT>
57     BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&>
operator <=(RhsT const & rhs)58     operator <= ( RhsT const& rhs ) {
59         return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
60     }
61 
62     template<typename RhsT>
63     BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&>
operator >=(RhsT const & rhs)64     operator >= ( RhsT const& rhs ) {
65         return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
66     }
67 
operator ==(bool rhs)68     BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) {
69         return captureExpression<Internal::IsEqualTo>( rhs );
70     }
71 
operator !=(bool rhs)72     BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) {
73         return captureExpression<Internal::IsNotEqualTo>( rhs );
74     }
75 
endExpression()76     void endExpression() {
77         m_truthy = m_lhs ? true : false;
78         m_rb
79             .setResultType( m_truthy )
80             .endExpression( *this );
81     }
82 
reconstructExpression(std::string & dest) const83     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
84         dest = Catch::toString( m_lhs );
85     }
86 
87 private:
88     template<Internal::Operator Op, typename RhsT>
captureExpression(RhsT & rhs) const89     BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const {
90         return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs );
91     }
92 
93     template<Internal::Operator Op>
captureExpression(bool rhs) const94     BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const {
95         return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs );
96     }
97 
98 private:
99     ResultBuilder& m_rb;
100     T m_lhs;
101     bool m_truthy;
102 };
103 
104 template<typename LhsT, Internal::Operator Op, typename RhsT>
105 class BinaryExpression : public DecomposedExpression {
106 public:
BinaryExpression(ResultBuilder & rb,LhsT lhs,RhsT rhs)107     BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs )
108         : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {}
109 
110     BinaryExpression& operator = ( BinaryExpression& );
111 
endExpression() const112     void endExpression() const {
113         m_rb
114             .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) )
115             .endExpression( *this );
116     }
117 
isBinaryExpression() const118     virtual bool isBinaryExpression() const CATCH_OVERRIDE {
119         return true;
120     }
121 
reconstructExpression(std::string & dest) const122     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
123         std::string lhs = Catch::toString( m_lhs );
124         std::string rhs = Catch::toString( m_rhs );
125         char delim = lhs.size() + rhs.size() < 40 &&
126                      lhs.find('\n') == std::string::npos &&
127                      rhs.find('\n') == std::string::npos ? ' ' : '\n';
128         dest.reserve( 7 + lhs.size() + rhs.size() );
129                    // 2 for spaces around operator
130                    // 2 for operator
131                    // 2 for parentheses (conditionally added later)
132                    // 1 for negation (conditionally added later)
133         dest = lhs;
134         dest += delim;
135         dest += Internal::OperatorTraits<Op>::getName();
136         dest += delim;
137         dest += rhs;
138     }
139 
140 private:
141     ResultBuilder& m_rb;
142     LhsT m_lhs;
143     RhsT m_rhs;
144 };
145 
146 template<typename ArgT, typename MatcherT>
147 class MatchExpression : public DecomposedExpression {
148 public:
MatchExpression(ArgT arg,MatcherT matcher,char const * matcherString)149     MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString )
150         : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {}
151 
isBinaryExpression() const152     virtual bool isBinaryExpression() const CATCH_OVERRIDE {
153         return true;
154     }
155 
reconstructExpression(std::string & dest) const156     virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE {
157         std::string matcherAsString = m_matcher.toString();
158         dest = Catch::toString( m_arg );
159         dest += ' ';
160         if( matcherAsString == Detail::unprintableString )
161             dest += m_matcherString;
162         else
163             dest += matcherAsString;
164     }
165 
166 private:
167     ArgT m_arg;
168     MatcherT m_matcher;
169     char const* m_matcherString;
170 };
171 
172 } // end namespace Catch
173 
174 #endif // TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
175