1 //  (C) Copyright Gennadiy Rozental 2011-2014.
2 //  Distributed under the Boost Software License, Version 1.0.
3 //  (See accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  See http://www.boost.org/libs/test for the library home page.
7 //
8 //!@file
9 //!@brief Defines framework for automated assertion construction
10 // ***************************************************************************
11 
12 #ifndef BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER
13 #define BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER
14 
15 // Boost.Test
16 #include <boost/test/tools/assertion_result.hpp>
17 #include <boost/test/tools/detail/print_helper.hpp>
18 #include <boost/test/tools/detail/fwd.hpp>
19 
20 // Boost
21 #include <boost/type.hpp>
22 #include <boost/type_traits/decay.hpp>
23 #include <boost/mpl/assert.hpp>
24 #include <boost/utility/declval.hpp>
25 #include <boost/type_traits/remove_reference.hpp>
26 
27 // STL
28 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
29 #include <utility>
30 #endif
31 
32 #include <boost/test/detail/suppress_warnings.hpp>
33 
34 //____________________________________________________________________________//
35 
36 namespace boost {
37 namespace test_tools {
38 namespace assertion {
39 
40 // ************************************************************************** //
41 // **************             assertion::operators             ************** //
42 // ************************************************************************** //
43 // precedence 4: ->*, .*
44 // precedence 5: *, /, %
45 // precedence 6: +, -
46 // precedence 7: << , >>
47 // precedence 8: <, <=, > and >=
48 // precedence 9: == and !=
49 // precedence 10: bitwise AND
50 // precedence 11: bitwise XOR
51 // precedence 12: bitwise OR
52 // precedence 13: logical AND
53 //  disabled
54 // precedence 14: logical OR
55 //  disabled
56 // precedence 15: ternary conditional
57 //  disabled
58 // precedence 16: = and OP= operators
59 // precedence 17: throw operator
60 //  not supported
61 // precedence 18: comma
62 //  not supported
63 
64 namespace op {
65 
66 #define BOOST_TEST_FOR_EACH_COMP_OP(action) \
67     action( < , LT, >= )                    \
68     action( <=, LE, >  )                    \
69     action( > , GT, <= )                    \
70     action( >=, GE, <  )                    \
71     action( ==, EQ, != )                    \
72     action( !=, NE, == )                    \
73 /**/
74 
75 //____________________________________________________________________________//
76 
77 #ifndef BOOST_NO_CXX11_DECLTYPE
78 
79 #define BOOST_TEST_FOR_EACH_CONST_OP(action)\
80     action(->*, MEMP, ->* )                 \
81                                             \
82     action( * , MUL, * )                    \
83     action( / , DIV, / )                    \
84     action( % , MOD, % )                    \
85                                             \
86     action( + , ADD, + )                    \
87     action( - , SUB, - )                    \
88                                             \
89     action( <<, LSH, << )                   \
90     action( >>, RSH, >> )                   \
91                                             \
92     BOOST_TEST_FOR_EACH_COMP_OP(action)     \
93                                             \
94     action( & , BAND, & )                   \
95     action( ^ , XOR, ^ )                    \
96     action( | , BOR, | )                    \
97 /**/
98 
99 #else
100 
101 #define BOOST_TEST_FOR_EACH_CONST_OP(action)\
102     BOOST_TEST_FOR_EACH_COMP_OP(action)     \
103 /**/
104 
105 #endif
106 
107 //____________________________________________________________________________//
108 
109 #define BOOST_TEST_FOR_EACH_MUT_OP(action)  \
110     action( = , SET , =  )                  \
111     action( +=, IADD, += )                  \
112     action( -=, ISUB, -= )                  \
113     action( *=, IMUL, *= )                  \
114     action( /=, IDIV, /= )                  \
115     action( %=, IMOD, %= )                  \
116     action(<<=, ILSH, <<=)                  \
117     action(>>=, IRSH, >>=)                  \
118     action( &=, IAND, &= )                  \
119     action( ^=, IXOR, ^= )                  \
120     action( |=, IOR , |= )                  \
121 /**/
122 
123 //____________________________________________________________________________//
124 
125 #ifndef BOOST_NO_CXX11_DECLTYPE
126 #   define DEDUCE_RESULT_TYPE( oper )                                   \
127     decltype(boost::declval<Lhs>() oper boost::declval<Rhs>() ) optype; \
128     typedef typename boost::remove_reference<optype>::type              \
129 /**/
130 #else
131 #   define DEDUCE_RESULT_TYPE( oper ) bool
132 #endif
133 
134 #define DEFINE_CONST_OPER( oper, name, rev )        \
135 template<typename Lhs, typename Rhs,                \
136          typename Enabler=void>                     \
137 struct name {                                       \
138     typedef DEDUCE_RESULT_TYPE( oper ) result_type; \
139                                                     \
140     static result_type                              \
141     eval( Lhs const& lhs, Rhs const& rhs )          \
142     {                                               \
143         return lhs oper rhs;                        \
144     }                                               \
145                                                     \
146     template<typename PrevExprType>                 \
147     static void                                     \
148     report( std::ostream&       ostr,               \
149             PrevExprType const& lhs,                \
150             Rhs const&          rhs)                \
151     {                                               \
152         lhs.report( ostr );                         \
153         ostr << revert()                            \
154              << tt_detail::print_helper( rhs );     \
155     }                                               \
156                                                     \
157     static char const* revert()                     \
158     { return " " #rev " "; }                        \
159 };                                                  \
160 /**/
161 
162 BOOST_TEST_FOR_EACH_CONST_OP( DEFINE_CONST_OPER )
163 
164 #undef DEDUCE_RESULT_TYPE
165 #undef DEFINE_CONST_OPER
166 
167 //____________________________________________________________________________//
168 
169 } // namespace op
170 
171 // ************************************************************************** //
172 // **************          assertion::expression_base          ************** //
173 // ************************************************************************** //
174 // Defines expression operators
175 
176 template<typename Lhs, typename Rhs, typename OP> class binary_expr;
177 
178 template<typename ExprType,typename ValType>
179 class expression_base {
180 public:
181 
182 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
183 
184 #define ADD_OP_SUPPORT( oper, name, _ )                         \
185     template<typename T>                                        \
186     binary_expr<ExprType,T,                                     \
187         op::name<ValType,typename remove_reference<T>::type> >  \
188     operator oper( T&& rhs )                                    \
189     {                                                           \
190         return binary_expr<ExprType,T,                          \
191          op::name<ValType,typename remove_reference<T>::type> > \
192             ( std::forward<ExprType>(                           \
193                 *static_cast<ExprType*>(this) ),                \
194               std::forward<T>(rhs) );                           \
195     }                                                           \
196 /**/
197 #else
198 
199 #define ADD_OP_SUPPORT( oper, name, _ )                         \
200     template<typename T>                                        \
201     binary_expr<ExprType,typename boost::decay<T const>::type,  \
202         op::name<ValType,typename boost::decay<T const>::type> > \
203     operator oper( T const& rhs ) const                         \
204     {                                                           \
205         typedef typename boost::decay<T const>::type Rhs;       \
206         return binary_expr<ExprType,Rhs,op::name<ValType,Rhs> > \
207             ( *static_cast<ExprType const*>(this),              \
208               rhs );                                            \
209     }                                                           \
210 /**/
211 #endif
212 
213     BOOST_TEST_FOR_EACH_CONST_OP( ADD_OP_SUPPORT )
214     #undef ADD_OP_SUPPORT
215 
216 #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
217     // Disabled operators
218     template<typename T>
219     ExprType&
220     operator ||( T const& /*rhs*/ )
221     {
222         BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_OR_WITHIN_THIS_TESTING_TOOL, () );
223 
224         return *static_cast<ExprType*>(this);
225     }
226 
227     template<typename T>
228     ExprType&
operator &&(T const &)229     operator &&( T const& /*rhs*/ )
230     {
231         BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_AND_WITHIN_THIS_TESTING_TOOL, () );
232 
233         return *static_cast<ExprType*>(this);
234     }
235 
operator bool()236     operator bool()
237     {
238         BOOST_MPL_ASSERT_MSG(false, CANT_USE_TERNARY_OPERATOR_WITHIN_THIS_TESTING_TOOL, () );
239 
240         return false;
241     }
242 #endif
243 };
244 
245 // ************************************************************************** //
246 // **************            assertion::value_expr             ************** //
247 // ************************************************************************** //
248 // simple value expression
249 
250 template<typename T>
251 class value_expr : public expression_base<value_expr<T>,typename remove_reference<T>::type> {
252 public:
253     // Public types
254     typedef T                   result_type;
255 
256     // Constructor
257 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
value_expr(value_expr && ve)258     value_expr( value_expr&& ve )
259     : m_value( std::forward<T>(ve.m_value) )
260     {}
value_expr(T && val)261     explicit                    value_expr( T&& val )
262     : m_value( std::forward<T>(val) )
263     {}
264 #else
value_expr(T const & val)265     explicit                    value_expr( T const& val )
266     : m_value( val )
267     {}
268 #endif
269 
270     // Specific expression interface
value() const271     T const&                    value() const
272     {
273         return m_value;
274     }
report(std::ostream & ostr) const275     void                        report( std::ostream& ostr ) const
276     {
277         ostr << tt_detail::print_helper( m_value );
278     }
279 
280     // Mutating operators
281 #define ADD_OP_SUPPORT( OPER, ID, _ )   \
282     template<typename U>                \
283     value_expr<T>&                      \
284     operator OPER( U const& rhs )       \
285     {                                   \
286         m_value OPER rhs;               \
287                                         \
288         return *this;                   \
289     }                                   \
290 /**/
291 
BOOST_TEST_FOR_EACH_MUT_OP(ADD_OP_SUPPORT)292     BOOST_TEST_FOR_EACH_MUT_OP( ADD_OP_SUPPORT )
293 #undef ADD_OP_SUPPORT
294 
295     // expression interface
296     assertion_result            evaluate( bool no_message = false ) const
297     {
298         assertion_result res( value() );
299         if( no_message || res )
300             return res;
301 
302         format_message( res.message(), value() );
303 
304         return tt_detail::format_assertion_result( "", res.message().str() );
305     }
306 
307 private:
308     template<typename U>
format_message(wrap_stringstream & ostr,U const & v)309     static void format_message( wrap_stringstream& ostr, U const& v )   { ostr << "[(bool)" << v << " is false]"; }
format_message(wrap_stringstream &,bool)310     static void format_message( wrap_stringstream& /*ostr*/, bool /*v*/ )       {}
format_message(wrap_stringstream &,assertion_result const &)311     static void format_message( wrap_stringstream& /*ostr*/, assertion_result const& /*v*/ ) {}
312 
313     // Data members
314     T                           m_value;
315 };
316 
317 // ************************************************************************** //
318 // **************            assertion::binary_expr            ************** //
319 // ************************************************************************** //
320 // binary expression
321 
322 template<typename LExpr, typename Rhs, typename OP>
323 class binary_expr : public expression_base<binary_expr<LExpr,Rhs,OP>,typename OP::result_type> {
324 public:
325     // Public types
326     typedef typename OP::result_type result_type;
327 
328     // Constructor
329 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
binary_expr(binary_expr && be)330     binary_expr( binary_expr&& be )
331     : m_lhs( std::forward<LExpr>(be.m_lhs) )
332     , m_rhs( std::forward<Rhs>(be.m_rhs) )
333     {}
binary_expr(LExpr && lhs,Rhs && rhs)334     binary_expr( LExpr&& lhs, Rhs&& rhs )
335     : m_lhs( std::forward<LExpr>(lhs) )
336     , m_rhs( std::forward<Rhs>(rhs) )
337     {}
338 #else
binary_expr(LExpr const & lhs,Rhs const & rhs)339     binary_expr( LExpr const& lhs, Rhs const& rhs )
340     : m_lhs( lhs )
341     , m_rhs( rhs )
342     {}
343 #endif
344 
345     // Specific expression interface
value() const346     result_type                 value() const
347     {
348         return OP::eval( m_lhs.value(), m_rhs );
349     }
report(std::ostream & ostr) const350     void                        report( std::ostream& ostr ) const
351     {
352         return OP::report( ostr, m_lhs, m_rhs );
353     }
354 
evaluate(bool no_message=false) const355     assertion_result            evaluate( bool no_message = false ) const
356     {
357         assertion_result const expr_res( value() );
358         if( no_message || expr_res )
359             return expr_res;
360 
361         wrap_stringstream buff;
362         report( buff.stream() );
363 
364         return tt_detail::format_assertion_result( buff.stream().str(), expr_res.message() );
365     }
366 
367     // To support custom manipulators
lhs() const368     LExpr const&                lhs() const     { return m_lhs; }
rhs() const369     Rhs const&                  rhs() const     { return m_rhs; }
370 private:
371     // Data members
372     LExpr                       m_lhs;
373     Rhs                         m_rhs;
374 };
375 
376 // ************************************************************************** //
377 // **************               assertion::seed                ************** //
378 // ************************************************************************** //
379 // seed added ot the input expression to form an assertion expression
380 
381 class seed {
382 public:
383     // ->* is highest precedence left to right operator
384     template<typename T>
385     value_expr<T>
386 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
operator ->*(T && v) const387     operator->*( T&& v ) const
388     {
389         return value_expr<T>( std::forward<T>( v ) );
390     }
391 #else
392     operator->*( T const& v )  const
393     {
394         return value_expr<T>( v );
395     }
396 #endif
397 };
398 
399 #undef BOOST_TEST_FOR_EACH_CONST_OP
400 
401 } // namespace assertion
402 } // namespace test_tools
403 } // namespace boost
404 
405 #include <boost/test/detail/enable_warnings.hpp>
406 
407 #endif // BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER
408