// (C) Copyright Gennadiy Rozental 2011-2014. // 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 #include #include // Boost #include #include #include #include #include // STL #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #include #endif #include //____________________________________________________________________________// 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() oper boost::declval() ) optype; \ typedef typename boost::remove_reference::type \ /**/ #else # define DEDUCE_RESULT_TYPE( oper ) bool #endif #define DEFINE_CONST_OPER( oper, name, rev ) \ template \ struct name { \ typedef DEDUCE_RESULT_TYPE( oper ) result_type; \ \ static result_type \ eval( Lhs const& lhs, Rhs const& rhs ) \ { \ return lhs oper rhs; \ } \ \ template \ 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 class binary_expr; template class expression_base { public: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #define ADD_OP_SUPPORT( oper, name, _ ) \ template \ binary_expr::type> > \ operator oper( T&& rhs ) \ { \ return binary_expr::type> > \ ( std::forward( \ *static_cast(this) ), \ std::forward(rhs) ); \ } \ /**/ #else #define ADD_OP_SUPPORT( oper, name, _ ) \ template \ binary_expr::type, \ op::name::type> > \ operator oper( T const& rhs ) const \ { \ typedef typename boost::decay::type Rhs; \ return binary_expr > \ ( *static_cast(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 ExprType& operator ||( T const& /*rhs*/ ) { BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_OR_WITHIN_THIS_TESTING_TOOL, () ); return *static_cast(this); } template ExprType& operator &&( T const& /*rhs*/ ) { BOOST_MPL_ASSERT_MSG(false, CANT_USE_LOGICAL_OPERATOR_AND_WITHIN_THIS_TESTING_TOOL, () ); return *static_cast(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 class value_expr : public expression_base,typename remove_reference::type> { public: // Public types typedef T result_type; // Constructor #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES value_expr( value_expr&& ve ) : m_value( std::forward(ve.m_value) ) {} explicit value_expr( T&& val ) : m_value( std::forward(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 \ value_expr& \ 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 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 class binary_expr : public expression_base,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(be.m_lhs) ) , m_rhs( std::forward(be.m_rhs) ) {} binary_expr( LExpr&& lhs, Rhs&& rhs ) : m_lhs( std::forward(lhs) ) , m_rhs( std::forward(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 value_expr #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES operator->*( T&& v ) const { return value_expr( std::forward( v ) ); } #else operator->*( T const& v ) const { return value_expr( v ); } #endif }; #undef BOOST_TEST_FOR_EACH_CONST_OP } // namespace assertion } // namespace test_tools } // namespace boost #include #endif // BOOST_TEST_TOOLS_ASSERTION_HPP_100911GER