123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- // (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 Collection comparison with enhanced reporting
- // ***************************************************************************
- #ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
- #define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
- // Boost.Test
- #include <boost/test/tools/assertion.hpp>
- #include <boost/test/utils/is_forward_iterable.hpp>
- #include <boost/test/utils/is_cstring.hpp>
- // Boost
- #include <boost/mpl/bool.hpp>
- #include <boost/mpl/if.hpp>
- #include <boost/utility/enable_if.hpp>
- #include <boost/type_traits/decay.hpp>
- #include <boost/test/detail/suppress_warnings.hpp>
- //____________________________________________________________________________//
- namespace boost {
- namespace test_tools {
- namespace assertion {
- // ************************************************************************** //
- // ************* selectors for specialized comparizon routines ************** //
- // ************************************************************************** //
- template<typename T>
- struct specialized_compare : public mpl::false_ {};
- template <typename T>
- struct is_c_array : public mpl::false_ {};
- template<typename T, std::size_t N>
- struct is_c_array<T [N]> : public mpl::true_ {};
- template<typename T, std::size_t N>
- struct is_c_array<T (&)[N]> : public mpl::true_ {};
- #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
- namespace boost { namespace test_tools { namespace assertion { \
- template<> \
- struct specialized_compare<Col> : public mpl::true_ {}; \
- }}} \
- /**/
- // ************************************************************************** //
- // ************** lexicographic_compare ************** //
- // ************************************************************************** //
- namespace op {
- template <typename OP, bool can_be_equal, bool prefer_shorter,
- typename Lhs, typename Rhs>
- inline
- typename boost::enable_if_c<
- unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
- && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
- assertion_result>::type
- lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
- {
- assertion_result ar( true );
- typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
- typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
- typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs);
- typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs);
- typename t_Lhs_iterator::const_iterator last1 = t_Lhs_iterator::end(lhs);
- typename t_Rhs_iterator::const_iterator last2 = t_Rhs_iterator::end(rhs);
- std::size_t pos = 0;
- for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
- assertion_result const& element_ar = OP::eval(*first1, *first2);
- if( !can_be_equal && element_ar )
- return ar; // a < b
- assertion_result const& reverse_ar = OP::eval(*first2, *first1);
- if( element_ar && !reverse_ar )
- return ar; // a<=b and !(b<=a) => a < b => return true
- if( element_ar || !reverse_ar ) {
- continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
- }
- // !(a<=b) and b<=a => b < a => return false
- ar = false;
- ar.message() << "\nFailure at position " << pos << ":";
- ar.message() << "\n - condition [" << tt_detail::print_helper(*first1) << OP::forward() << tt_detail::print_helper(*first2) << "] is false";
- if(!element_ar.has_empty_message())
- ar.message() << ": " << element_ar.message();
- ar.message() << "\n - inverse condition [" << tt_detail::print_helper(*first2) << OP::forward() << tt_detail::print_helper(*first1) << "] is true";
- if(!reverse_ar.has_empty_message())
- ar.message() << ": " << reverse_ar.message();
- return ar;
- }
- if( first1 != last1 ) {
- if( prefer_shorter ) {
- ar = false;
- ar.message() << "\nFirst collection has extra trailing elements.";
- }
- }
- else if( first2 != last2 ) {
- if( !prefer_shorter ) {
- ar = false;
- ar.message() << "\nSecond collection has extra trailing elements.";
- }
- }
- else if( !can_be_equal ) {
- ar = false;
- ar.message() << "\nCollections appear to be equal.";
- }
- return ar;
- }
- template <typename OP, bool can_be_equal, bool prefer_shorter,
- typename Lhs, typename Rhs>
- inline
- typename boost::enable_if_c<
- (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
- assertion_result>::type
- lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
- {
- typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
- typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
- return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
- lhs_char_type(lhs),
- rhs_char_type(rhs));
- }
- //____________________________________________________________________________//
- // ************************************************************************** //
- // ************** equality_compare ************** //
- // ************************************************************************** //
- template <typename OP, typename Lhs, typename Rhs>
- inline
- typename boost::enable_if_c<
- unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
- && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
- assertion_result>::type
- element_compare( Lhs const& lhs, Rhs const& rhs )
- {
- typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
- typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
- assertion_result ar( true );
- if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
- ar = false;
- ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
- return ar;
- }
- typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
- typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
- std::size_t pos = 0;
- for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
- assertion_result const element_ar = OP::eval( *left, *right );
- if( element_ar )
- continue;
- ar = false;
- ar.message() << "\n - mismatch at position " << pos << ": ["
- << tt_detail::print_helper(*left)
- << OP::forward()
- << tt_detail::print_helper(*right)
- << "] is false";
- if(!element_ar.has_empty_message())
- ar.message() << ": " << element_ar.message();
- }
- return ar;
- }
- // In case string comparison is branching here
- template <typename OP, typename Lhs, typename Rhs>
- inline
- typename boost::enable_if_c<
- (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
- assertion_result>::type
- element_compare( Lhs const& lhs, Rhs const& rhs )
- {
- typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
- typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
- return element_compare<OP>(lhs_char_type(lhs),
- rhs_char_type(rhs));
- }
- //____________________________________________________________________________//
- // ************************************************************************** //
- // ************** non_equality_compare ************** //
- // ************************************************************************** //
- template <typename OP, typename Lhs, typename Rhs>
- inline assertion_result
- non_equality_compare( Lhs const& lhs, Rhs const& rhs )
- {
- typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
- typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
- assertion_result ar( true );
- if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
- return ar;
- typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
- typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
- typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
- for( ; left != end; ++left, ++right ) {
- if( OP::eval( *left, *right ) )
- return ar;
- }
- ar = false;
- ar.message() << "\nCollections appear to be equal";
- return ar;
- }
- //____________________________________________________________________________//
- // ************************************************************************** //
- // ************** cctraits ************** //
- // ************************************************************************** //
- // set of collection comparison traits per comparison OP
- template<typename OP>
- struct cctraits;
- template<typename Lhs, typename Rhs>
- struct cctraits<op::EQ<Lhs, Rhs> > {
- typedef specialized_compare<Lhs> is_specialized;
- };
- template<typename Lhs, typename Rhs>
- struct cctraits<op::NE<Lhs, Rhs> > {
- typedef specialized_compare<Lhs> is_specialized;
- };
- template<typename Lhs, typename Rhs>
- struct cctraits<op::LT<Lhs, Rhs> > {
- static const bool can_be_equal = false;
- static const bool prefer_short = true;
- typedef specialized_compare<Lhs> is_specialized;
- };
- template<typename Lhs, typename Rhs>
- struct cctraits<op::LE<Lhs, Rhs> > {
- static const bool can_be_equal = true;
- static const bool prefer_short = true;
- typedef specialized_compare<Lhs> is_specialized;
- };
- template<typename Lhs, typename Rhs>
- struct cctraits<op::GT<Lhs, Rhs> > {
- static const bool can_be_equal = false;
- static const bool prefer_short = false;
- typedef specialized_compare<Lhs> is_specialized;
- };
- template<typename Lhs, typename Rhs>
- struct cctraits<op::GE<Lhs, Rhs> > {
- static const bool can_be_equal = true;
- static const bool prefer_short = false;
- typedef specialized_compare<Lhs> is_specialized;
- };
- // ************************************************************************** //
- // ************** compare_collections ************** //
- // ************************************************************************** //
- // Overloaded set of functions dispatching to specific implementation of comparison
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
- {
- return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
- {
- return lhs == rhs;
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
- {
- return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
- {
- return lhs != rhs;
- }
- //____________________________________________________________________________//
- template <typename OP, typename Lhs, typename Rhs>
- inline assertion_result
- lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
- {
- return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename OP>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
- {
- return lexicographic_compare<OP>( lhs, rhs );
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
- {
- return lhs < rhs;
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
- {
- return lhs <= rhs;
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
- {
- return lhs > rhs;
- }
- //____________________________________________________________________________//
- template <typename Lhs, typename Rhs, typename L, typename R>
- inline assertion_result
- compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
- {
- return lhs >= rhs;
- }
- //____________________________________________________________________________//
- // ************************************************************************** //
- // ********* specialization of comparison operators for collections ********* //
- // ************************************************************************** //
- #define DEFINE_COLLECTION_COMPARISON( oper, name, rev, name_inverse ) \
- template<typename Lhs,typename Rhs> \
- struct name<Lhs,Rhs,typename boost::enable_if_c< \
- unit_test::is_forward_iterable<Lhs>::value \
- && !unit_test::is_cstring_comparable<Lhs>::value \
- && unit_test::is_forward_iterable<Rhs>::value \
- && !unit_test::is_cstring_comparable<Rhs>::value>::type> { \
- public: \
- typedef assertion_result result_type; \
- typedef name_inverse<Lhs, Rhs> inverse; \
- typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
- typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
- \
- typedef name<Lhs, Rhs> OP; \
- \
- typedef typename \
- mpl::if_c< \
- mpl::or_< \
- typename is_c_array<Lhs>::type, \
- typename is_c_array<Rhs>::type \
- >::value, \
- mpl::true_, \
- typename \
- mpl::if_c<is_same<typename decay<Lhs>::type, \
- typename decay<Rhs>::type>::value, \
- typename cctraits<OP>::is_specialized, \
- mpl::false_>::type \
- >::type is_specialized; \
- \
- typedef name<typename t_Lhs_iterator_helper::value_type, \
- typename t_Rhs_iterator_helper::value_type \
- > elem_op; \
- \
- static assertion_result \
- eval( Lhs const& lhs, Rhs const& rhs) \
- { \
- return assertion::op::compare_collections( lhs, rhs, \
- (boost::type<elem_op>*)0, \
- is_specialized() ); \
- } \
- \
- template<typename PrevExprType> \
- static void \
- report( std::ostream&, \
- PrevExprType const&, \
- Rhs const& ) {} \
- \
- static char const* forward() \
- { return " " #oper " "; } \
- static char const* revert() \
- { return " " #rev " "; } \
- \
- }; \
- /**/
- BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
- #undef DEFINE_COLLECTION_COMPARISON
- //____________________________________________________________________________//
- } // namespace op
- } // namespace assertion
- } // namespace test_tools
- } // namespace boost
- #include <boost/test/detail/enable_warnings.hpp>
- #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
|