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