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