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