411 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			411 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | //  (C) Copyright Gennadiy Rozental 2001. | ||
|  | //  Distributed under the Boost Software License, Version 1.0. | ||
|  | //  (See accompanying file LICENSE_1_0.txt or copy at | ||
|  | //  http://www.boost.org/LICENSE_1_0.txt) | ||
|  | 
 | ||
|  | //  See http://www.boost.org/libs/test for the library home page. | ||
|  | // | ||
|  | //!@file | ||
|  | //!@brief Defines framework for automated assertion construction | ||
|  | // *************************************************************************** | ||
|  | 
 | ||
|  | #ifndef BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER | ||
|  | #define BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER | ||
|  | 
 | ||
|  | // Boost.Test | ||
|  | #include <boost/test/tools/assertion_result.hpp> | ||
|  | #include <boost/test/tools/detail/print_helper.hpp> | ||
|  | #include <boost/test/tools/detail/fwd.hpp> | ||
|  | 
 | ||
|  | // Boost | ||
|  | #include <boost/type.hpp> | ||
|  | #include <boost/type_traits/decay.hpp> | ||
|  | #include <boost/mpl/assert.hpp> | ||
|  | #include <boost/utility/declval.hpp> | ||
|  | #include <boost/type_traits/remove_reference.hpp> | ||
|  | #include <boost/type_traits/remove_const.hpp> | ||
|  | 
 | ||
|  | // STL | ||
|  | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | ||
|  | #include <utility> | ||
|  | #endif | ||
|  | 
 | ||
|  | #include <boost/test/detail/suppress_warnings.hpp> | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | namespace boost { | ||
|  | namespace test_tools { | ||
|  | namespace assertion { | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************             assertion::operators             ************** // | ||
|  | // ************************************************************************** // | ||
|  | // precedence 4: ->*, .* | ||
|  | // precedence 5: *, /, % | ||
|  | // precedence 6: +, - | ||
|  | // precedence 7: << , >> | ||
|  | // precedence 8: <, <=, > and >= | ||
|  | // precedence 9: == and != | ||
|  | // precedence 10: bitwise AND | ||
|  | // precedence 11: bitwise XOR | ||
|  | // precedence 12: bitwise OR | ||
|  | // precedence 13: logical AND | ||
|  | //  disabled | ||
|  | // precedence 14: logical OR | ||
|  | //  disabled | ||
|  | // precedence 15: ternary conditional | ||
|  | //  disabled | ||
|  | // precedence 16: = and OP= operators | ||
|  | // precedence 17: throw operator | ||
|  | //  not supported | ||
|  | // precedence 18: comma | ||
|  | //  not supported | ||
|  | 
 | ||
|  | namespace op { | ||
|  | 
 | ||
|  | #define BOOST_TEST_FOR_EACH_COMP_OP(action) \ | ||
|  |     action( < , LT, >= )                    \ | ||
|  |     action( <=, LE, >  )                    \ | ||
|  |     action( > , GT, <= )                    \ | ||
|  |     action( >=, GE, <  )                    \ | ||
|  |     action( ==, EQ, != )                    \ | ||
|  |     action( !=, NE, == )                    \ | ||
|  | /**/ | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_CXX11_DECLTYPE | ||
|  | 
 | ||
|  | #define BOOST_TEST_FOR_EACH_CONST_OP(action)\ | ||
|  |     action(->*, MEMP, ->* )                 \ | ||
|  |                                             \ | ||
|  |     action( * , MUL, * )                    \ | ||
|  |     action( / , DIV, / )                    \ | ||
|  |     action( % , MOD, % )                    \ | ||
|  |                                             \ | ||
|  |     action( + , ADD, + )                    \ | ||
|  |     action( - , SUB, - )                    \ | ||
|  |                                             \ | ||
|  |     action( <<, LSH, << )                   \ | ||
|  |     action( >>, RSH, >> )                   \ | ||
|  |                                             \ | ||
|  |     BOOST_TEST_FOR_EACH_COMP_OP(action)     \ | ||
|  |                                             \ | ||
|  |     action( & , BAND, & )                   \ | ||
|  |     action( ^ , XOR, ^ )                    \ | ||
|  |     action( | , BOR, | )                    \ | ||
|  | /**/ | ||
|  | 
 | ||
|  | #else | ||
|  | 
 | ||
|  | #define BOOST_TEST_FOR_EACH_CONST_OP(action)\ | ||
|  |     BOOST_TEST_FOR_EACH_COMP_OP(action)     \ | ||
|  | /**/ | ||
|  | 
 | ||
|  | #endif | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #define BOOST_TEST_FOR_EACH_MUT_OP(action)  \ | ||
|  |     action( = , SET , =  )                  \ | ||
|  |     action( +=, IADD, += )                  \ | ||
|  |     action( -=, ISUB, -= )                  \ | ||
|  |     action( *=, IMUL, *= )                  \ | ||
|  |     action( /=, IDIV, /= )                  \ | ||
|  |     action( %=, IMOD, %= )                  \ | ||
|  |     action(<<=, ILSH, <<=)                  \ | ||
|  |     action(>>=, IRSH, >>=)                  \ | ||
|  |     action( &=, IAND, &= )                  \ | ||
|  |     action( ^=, IXOR, ^= )                  \ | ||
|  |     action( |=, IOR , |= )                  \ | ||
|  | /**/ | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_CXX11_DECLTYPE | ||
|  | #   define DEDUCE_RESULT_TYPE( oper )                                   \ | ||
|  |     decltype(boost::declval<Lhs>() oper boost::declval<Rhs>() ) optype; \ | ||
|  |     typedef typename boost::remove_reference<optype>::type              \ | ||
|  | /**/ | ||
|  | #else | ||
|  | #   define DEDUCE_RESULT_TYPE( oper ) bool | ||
|  | #endif | ||
|  | 
 | ||
|  | #define DEFINE_CONST_OPER( oper, name, rev )        \ | ||
|  | template<typename Lhs, typename Rhs,                \ | ||
|  |          typename Enabler=void>                     \ | ||
|  | struct name {                                       \ | ||
|  |     typedef DEDUCE_RESULT_TYPE( oper ) result_type; \ | ||
|  |                                                     \ | ||
|  |     static result_type                              \ | ||
|  |     eval( Lhs const& lhs, Rhs const& rhs )          \ | ||
|  |     {                                               \ | ||
|  |         return lhs oper rhs;                        \ | ||
|  |     }                                               \ | ||
|  |                                                     \ | ||
|  |     template<typename PrevExprType>                 \ | ||
|  |     static void                                     \ | ||
|  |     report( std::ostream&       ostr,               \ | ||
|  |             PrevExprType const& lhs,                \ | ||
|  |             Rhs const&          rhs)                \ | ||
|  |     {                                               \ | ||
|  |         lhs.report( ostr );                         \ | ||
|  |         ostr << revert()                            \ | ||
|  |              << tt_detail::print_helper( rhs );     \ | ||
|  |     }                                               \ | ||
|  |                                                     \ | ||
|  |     static char const* revert()                     \ | ||
|  |     { return " " #rev " "; }                        \ | ||
|  | };                                                  \ | ||
|  | /**/ | ||
|  | 
 | ||
|  | BOOST_TEST_FOR_EACH_CONST_OP( DEFINE_CONST_OPER ) | ||
|  | 
 | ||
|  | #undef DEDUCE_RESULT_TYPE | ||
|  | #undef DEFINE_CONST_OPER | ||
|  | 
 | ||
|  | //____________________________________________________________________________// | ||
|  | 
 | ||
|  | } // namespace op | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************          assertion::expression_base          ************** // | ||
|  | // ************************************************************************** // | ||
|  | // Defines expression operators | ||
|  | 
 | ||
|  | template<typename Lhs, typename Rhs, typename OP> class binary_expr; | ||
|  | 
 | ||
|  | template<typename ExprType,typename ValType> | ||
|  | class expression_base { | ||
|  | public: | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | ||
|  |     template<typename T> | ||
|  |     struct RhsT : remove_const<typename remove_reference<T>::type> {}; | ||
|  |      | ||
|  | #define ADD_OP_SUPPORT( oper, name, _ )                         \ | ||
|  |     template<typename T>                                        \ | ||
|  |     binary_expr<ExprType,T,                                     \ | ||
|  |         op::name<ValType,typename RhsT<T>::type> >              \ | ||
|  |     operator oper( T&& rhs )                                    \ | ||
|  |     {                                                           \ | ||
|  |         return binary_expr<ExprType,T,                          \ | ||
|  |          op::name<ValType,typename RhsT<T>::type> >             \ | ||
|  |             ( std::forward<ExprType>(                           \ | ||
|  |                 *static_cast<ExprType*>(this) ),                \ | ||
|  |               std::forward<T>(rhs) );                           \ | ||
|  |     }                                                           \ | ||
|  | /**/ | ||
|  | #else | ||
|  | 
 | ||
|  | #define ADD_OP_SUPPORT( oper, name, _ )                         \ | ||
|  |     template<typename T>                                        \ | ||
|  |     binary_expr<ExprType,typename boost::decay<T const>::type,  \ | ||
|  |         op::name<ValType,typename boost::decay<T const>::type> >\ | ||
|  |     operator oper( T const& rhs ) const                         \ | ||
|  |     {                                                           \ | ||
|  |         typedef typename boost::decay<T const>::type Rhs;       \ | ||
|  |         return binary_expr<ExprType,Rhs,op::name<ValType,Rhs> > \ | ||
|  |             ( *static_cast<ExprType const*>(this),              \ | ||
|  |               rhs );                                            \ | ||
|  |     }                                                           \ | ||
|  | /**/ | ||
|  | #endif | ||
|  | 
 | ||
|  |     BOOST_TEST_FOR_EACH_CONST_OP( ADD_OP_SUPPORT ) | ||
|  |     #undef ADD_OP_SUPPORT | ||
|  | 
 | ||
|  | #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS | ||
|  |     // Disabled operators | ||
|  |     template<typename T> | ||
|  |     ExprType& | ||
|  |     operator ||( T const& /*rhs*/ ) | ||
|  |     { | ||
|  |         BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_OR_WITHIN_THIS_TESTING_TOOL, () ); | ||
|  | 
 | ||
|  |         return *static_cast<ExprType*>(this); | ||
|  |     } | ||
|  | 
 | ||
|  |     template<typename T> | ||
|  |     ExprType& | ||
|  |     operator &&( T const& /*rhs*/ ) | ||
|  |     { | ||
|  |         BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_AND_WITHIN_THIS_TESTING_TOOL, () ); | ||
|  | 
 | ||
|  |         return *static_cast<ExprType*>(this); | ||
|  |     } | ||
|  | 
 | ||
|  |     operator bool() | ||
|  |     { | ||
|  |         BOOST_MPL_ASSERT_MSG(false, CANT_USE_TERNARY_OPERATOR_WITHIN_THIS_TESTING_TOOL, () ); | ||
|  | 
 | ||
|  |         return false; | ||
|  |     } | ||
|  | #endif | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************            assertion::value_expr             ************** // | ||
|  | // ************************************************************************** // | ||
|  | // simple value expression | ||
|  | 
 | ||
|  | template<typename T> | ||
|  | class value_expr : public expression_base<value_expr<T>,typename remove_const<typename remove_reference<T>::type>::type> { | ||
|  | public: | ||
|  |     // Public types | ||
|  |     typedef T                   result_type; | ||
|  | 
 | ||
|  |     // Constructor | ||
|  | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | ||
|  |     value_expr( value_expr&& ve ) | ||
|  |     : m_value( std::forward<T>(ve.m_value) ) | ||
|  |     {} | ||
|  |     explicit                    value_expr( T&& val ) | ||
|  |     : m_value( std::forward<T>(val) ) | ||
|  |     {} | ||
|  | #else | ||
|  |     explicit                    value_expr( T const& val ) | ||
|  |     : m_value( val ) | ||
|  |     {} | ||
|  | #endif | ||
|  | 
 | ||
|  |     // Specific expression interface | ||
|  |     T const&                    value() const | ||
|  |     { | ||
|  |         return m_value; | ||
|  |     } | ||
|  |     void                        report( std::ostream& ostr ) const | ||
|  |     { | ||
|  |         ostr << tt_detail::print_helper( m_value ); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Mutating operators | ||
|  | #define ADD_OP_SUPPORT( OPER, ID, _ )   \ | ||
|  |     template<typename U>                \ | ||
|  |     value_expr<T>&                      \ | ||
|  |     operator OPER( U const& rhs )       \ | ||
|  |     {                                   \ | ||
|  |         m_value OPER rhs;               \ | ||
|  |                                         \ | ||
|  |         return *this;                   \ | ||
|  |     }                                   \ | ||
|  | /**/ | ||
|  | 
 | ||
|  |     BOOST_TEST_FOR_EACH_MUT_OP( ADD_OP_SUPPORT ) | ||
|  | #undef ADD_OP_SUPPORT | ||
|  | 
 | ||
|  |     // expression interface | ||
|  |     assertion_result            evaluate( bool no_message = false ) const | ||
|  |     { | ||
|  |         assertion_result res( value() ); | ||
|  |         if( no_message || res ) | ||
|  |             return res; | ||
|  | 
 | ||
|  |         format_message( res.message(), value() ); | ||
|  | 
 | ||
|  |         return tt_detail::format_assertion_result( "", res.message().str() ); | ||
|  |     } | ||
|  | 
 | ||
|  | private: | ||
|  |     template<typename U> | ||
|  |     static void format_message( wrap_stringstream& ostr, U const& v )   { ostr << "[(bool)" << v << " is false]"; } | ||
|  |     static void format_message( wrap_stringstream& /*ostr*/, bool /*v*/ )       {} | ||
|  |     static void format_message( wrap_stringstream& /*ostr*/, assertion_result const& /*v*/ ) {} | ||
|  | 
 | ||
|  |     // Data members | ||
|  |     T                           m_value; | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************            assertion::binary_expr            ************** // | ||
|  | // ************************************************************************** // | ||
|  | // binary expression | ||
|  | 
 | ||
|  | template<typename LExpr, typename Rhs, typename OP> | ||
|  | class binary_expr : public expression_base<binary_expr<LExpr,Rhs,OP>,typename OP::result_type> { | ||
|  | public: | ||
|  |     // Public types | ||
|  |     typedef typename OP::result_type result_type; | ||
|  | 
 | ||
|  |     // Constructor | ||
|  | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | ||
|  |     binary_expr( binary_expr&& be ) | ||
|  |     : m_lhs( std::forward<LExpr>(be.m_lhs) ) | ||
|  |     , m_rhs( std::forward<Rhs>(be.m_rhs) ) | ||
|  |     {} | ||
|  |     binary_expr( LExpr&& lhs, Rhs&& rhs ) | ||
|  |     : m_lhs( std::forward<LExpr>(lhs) ) | ||
|  |     , m_rhs( std::forward<Rhs>(rhs) ) | ||
|  |     {} | ||
|  | #else | ||
|  |     binary_expr( LExpr const& lhs, Rhs const& rhs ) | ||
|  |     : m_lhs( lhs ) | ||
|  |     , m_rhs( rhs ) | ||
|  |     {} | ||
|  | #endif | ||
|  | 
 | ||
|  |     // Specific expression interface | ||
|  |     result_type                 value() const | ||
|  |     { | ||
|  |         return OP::eval( m_lhs.value(), m_rhs ); | ||
|  |     } | ||
|  |     void                        report( std::ostream& ostr ) const | ||
|  |     { | ||
|  |         return OP::report( ostr, m_lhs, m_rhs ); | ||
|  |     } | ||
|  | 
 | ||
|  |     assertion_result            evaluate( bool no_message = false ) const | ||
|  |     { | ||
|  |         assertion_result const expr_res( value() ); | ||
|  |         if( no_message || expr_res ) | ||
|  |             return expr_res; | ||
|  | 
 | ||
|  |         wrap_stringstream buff; | ||
|  |         report( buff.stream() ); | ||
|  | 
 | ||
|  |         return tt_detail::format_assertion_result( buff.stream().str(), expr_res.message() ); | ||
|  |     } | ||
|  | 
 | ||
|  |     // To support custom manipulators | ||
|  |     LExpr const&                lhs() const     { return m_lhs; } | ||
|  |     Rhs const&                  rhs() const     { return m_rhs; } | ||
|  | private: | ||
|  |     // Data members | ||
|  |     LExpr                       m_lhs; | ||
|  |     Rhs                         m_rhs; | ||
|  | }; | ||
|  | 
 | ||
|  | // ************************************************************************** // | ||
|  | // **************               assertion::seed                ************** // | ||
|  | // ************************************************************************** // | ||
|  | // seed added ot the input expression to form an assertion expression | ||
|  | 
 | ||
|  | class seed { | ||
|  | public: | ||
|  |     // ->* is highest precedence left to right operator | ||
|  |     template<typename T> | ||
|  |     value_expr<T> | ||
|  | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | ||
|  |     operator->*( T&& v ) const | ||
|  |     { | ||
|  |         return value_expr<T>( std::forward<T>( v ) ); | ||
|  |     } | ||
|  | #else | ||
|  |     operator->*( T const& v )  const | ||
|  |     { | ||
|  |         return value_expr<T>( v ); | ||
|  |     } | ||
|  | #endif | ||
|  | }; | ||
|  | 
 | ||
|  | #undef BOOST_TEST_FOR_EACH_CONST_OP | ||
|  | 
 | ||
|  | } // namespace assertion | ||
|  | } // namespace test_tools | ||
|  | } // namespace boost | ||
|  | 
 | ||
|  | #include <boost/test/detail/enable_warnings.hpp> | ||
|  | 
 | ||
|  | #endif // BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER |