LCOV - code coverage report
Current view: top level - opt/homebrew/include/boost/test/tools - collection_comparison_op.hpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 3 3 100.0 %
Date: 2026-06-25 07:23:43 Functions: 2 3 66.7 %

          Line data    Source code
       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 Collection comparison with enhanced reporting
      10             : // ***************************************************************************
      11             : 
      12             : #ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
      13             : #define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
      14             : 
      15             : // Boost.Test
      16             : #include <boost/test/tools/assertion.hpp>
      17             : 
      18             : #include <boost/test/utils/is_forward_iterable.hpp>
      19             : #include <boost/test/utils/is_cstring.hpp>
      20             : 
      21             : // Boost
      22             : #include <boost/mpl/bool.hpp>
      23             : #include <boost/mpl/if.hpp>
      24             : #include <boost/utility/enable_if.hpp>
      25             : #include <boost/type_traits/decay.hpp>
      26             : 
      27             : #include <boost/test/detail/suppress_warnings.hpp>
      28             : 
      29             : //____________________________________________________________________________//
      30             : 
      31             : namespace boost {
      32             : namespace test_tools {
      33             : namespace assertion {
      34             : 
      35             : // ************************************************************************** //
      36             : // ************* selectors for specialized comparizon routines ************** //
      37             : // ************************************************************************** //
      38             : 
      39             : template<typename T>
      40             : struct specialized_compare : public mpl::false_ {};
      41             : 
      42             : template <typename T>
      43             : struct is_c_array : public mpl::false_ {};
      44             : 
      45             : template<typename T, std::size_t N>
      46             : struct is_c_array<T [N]> : public mpl::true_ {};
      47             : 
      48             : template<typename T, std::size_t N>
      49             : struct is_c_array<T (&)[N]> : public mpl::true_ {};
      50             : 
      51             : #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col)          \
      52             : namespace boost { namespace test_tools { namespace assertion {  \
      53             : template<>                                                      \
      54             : struct specialized_compare<Col> : public mpl::true_ {};         \
      55             : }}}                                                             \
      56             : /**/
      57             : 
      58             : // ************************************************************************** //
      59             : // **************            lexicographic_compare             ************** //
      60             : // ************************************************************************** //
      61             : 
      62             : namespace op {
      63             : 
      64             : template <typename OP, bool can_be_equal, bool prefer_shorter,
      65             :           typename Lhs, typename Rhs>
      66             : inline
      67             : typename boost::enable_if_c<
      68             :        unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
      69             :     && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
      70             :     assertion_result>::type
      71             : lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
      72             : {
      73             :     assertion_result ar( true );
      74             : 
      75             :     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
      76             :     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
      77             : 
      78             :     typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs);
      79             :     typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs);
      80             :     typename t_Lhs_iterator::const_iterator last1  = t_Lhs_iterator::end(lhs);
      81             :     typename t_Rhs_iterator::const_iterator last2  = t_Rhs_iterator::end(rhs);
      82             :     std::size_t                             pos    = 0;
      83             : 
      84             :     for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
      85             :         assertion_result const& element_ar = OP::eval(*first1, *first2);
      86             :         if( !can_be_equal && element_ar )
      87             :             return ar; // a < b
      88             : 
      89             :         assertion_result const& reverse_ar = OP::eval(*first2, *first1);
      90             :         if( element_ar && !reverse_ar )
      91             :             return ar; // a<=b and !(b<=a) => a < b => return true
      92             : 
      93             :         if( element_ar || !reverse_ar ) {
      94             :             continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
      95             :         }
      96             : 
      97             :         // !(a<=b) and b<=a => b < a => return false
      98             :         ar = false;
      99             :         ar.message() << "\nFailure at position " << pos << ":";
     100             :         ar.message() << "\n  - condition [" << tt_detail::print_helper(*first1) << OP::forward() << tt_detail::print_helper(*first2) << "] is false";
     101             :         if(!element_ar.has_empty_message())
     102             :             ar.message() << ": " << element_ar.message();
     103             :         ar.message() << "\n  - inverse condition [" << tt_detail::print_helper(*first2) << OP::forward() << tt_detail::print_helper(*first1) << "] is true";
     104             :         if(!reverse_ar.has_empty_message())
     105             :             ar.message() << ": " << reverse_ar.message();
     106             :         return ar;
     107             :     }
     108             : 
     109             :     if( first1 != last1 ) {
     110             :         if( prefer_shorter ) {
     111             :             ar = false;
     112             :             ar.message() << "\nFirst collection has extra trailing elements.";
     113             :         }
     114             :     }
     115             :     else if( first2 != last2 ) {
     116             :         if( !prefer_shorter ) {
     117             :             ar = false;
     118             :             ar.message() << "\nSecond collection has extra trailing elements.";
     119             :         }
     120             :     }
     121             :     else if( !can_be_equal ) {
     122             :         ar = false;
     123             :         ar.message() << "\nCollections appear to be equal.";
     124             :     }
     125             : 
     126             :     return ar;
     127             : }
     128             : 
     129             : template <typename OP, bool can_be_equal, bool prefer_shorter,
     130             :           typename Lhs, typename Rhs>
     131             : inline
     132             : typename boost::enable_if_c<
     133             :     (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
     134             :     assertion_result>::type
     135             : lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
     136             : {
     137             :     typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
     138             :     typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
     139             : 
     140             :     return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
     141             :         lhs_char_type(lhs),
     142             :         rhs_char_type(rhs));
     143             : }
     144             : 
     145             : //____________________________________________________________________________//
     146             : 
     147             : // ************************************************************************** //
     148             : // **************               equality_compare               ************** //
     149             : // ************************************************************************** //
     150             : 
     151             : template <typename OP, typename Lhs, typename Rhs>
     152             : inline
     153             : typename boost::enable_if_c<
     154             :        unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
     155             :     && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
     156             :     assertion_result>::type
     157             : element_compare( Lhs const& lhs, Rhs const& rhs )
     158             : {
     159             :     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
     160             :     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
     161             : 
     162             :     assertion_result ar( true );
     163             : 
     164             :     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
     165             :         ar = false;
     166             :         ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
     167             :         return ar;
     168             :     }
     169             : 
     170             :     typename t_Lhs_iterator::const_iterator left  = t_Lhs_iterator::begin(lhs);
     171             :     typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
     172             :     std::size_t                             pos   = 0;
     173             : 
     174             :     for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
     175             :         assertion_result const element_ar = OP::eval( *left, *right );
     176             :         if( element_ar )
     177             :             continue;
     178             : 
     179             :         ar = false;
     180             :         ar.message() << "\n  - mismatch at position " << pos << ": ["
     181             :                      << tt_detail::print_helper(*left)
     182             :                      << OP::forward()
     183             :                      << tt_detail::print_helper(*right)
     184             :                      << "] is false";
     185             :         if(!element_ar.has_empty_message())
     186             :             ar.message() << ": " << element_ar.message();
     187             :     }
     188             : 
     189             :     return ar;
     190             : }
     191             : 
     192             : // In case string comparison is branching here
     193             : template <typename OP, typename Lhs, typename Rhs>
     194             : inline
     195             : typename boost::enable_if_c<
     196             :     (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
     197             :     assertion_result>::type
     198             : element_compare( Lhs const& lhs, Rhs const& rhs )
     199             : {
     200             :     typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
     201             :     typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
     202             : 
     203             :     return element_compare<OP>(lhs_char_type(lhs),
     204             :                                rhs_char_type(rhs));
     205             : }
     206             : 
     207             : //____________________________________________________________________________//
     208             : 
     209             : // ************************************************************************** //
     210             : // **************             non_equality_compare             ************** //
     211             : // ************************************************************************** //
     212             : 
     213             : template <typename OP, typename Lhs, typename Rhs>
     214             : inline assertion_result
     215             : non_equality_compare( Lhs const& lhs, Rhs const& rhs )
     216             : {
     217             :     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
     218             :     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
     219             : 
     220             :     assertion_result ar( true );
     221             : 
     222             :     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
     223             :         return ar;
     224             : 
     225             :     typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
     226             :     typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
     227             :     typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
     228             : 
     229             :     for( ; left != end; ++left, ++right ) {
     230             :         if( OP::eval( *left, *right ) )
     231             :             return ar;
     232             :     }
     233             : 
     234             :     ar = false;
     235             :     ar.message() << "\nCollections appear to be equal";
     236             : 
     237             :     return ar;
     238             : }
     239             : 
     240             : //____________________________________________________________________________//
     241             : 
     242             : // ************************************************************************** //
     243             : // **************                   cctraits                   ************** //
     244             : // ************************************************************************** //
     245             : // set of collection comparison traits per comparison OP
     246             : 
     247             : template<typename OP>
     248             : struct cctraits;
     249             : 
     250             : template<typename Lhs, typename Rhs>
     251             : struct cctraits<op::EQ<Lhs, Rhs> > {
     252             :     typedef specialized_compare<Lhs> is_specialized;
     253             : };
     254             : 
     255             : template<typename Lhs, typename Rhs>
     256             : struct cctraits<op::NE<Lhs, Rhs> > {
     257             :     typedef specialized_compare<Lhs> is_specialized;
     258             : };
     259             : 
     260             : template<typename Lhs, typename Rhs>
     261             : struct cctraits<op::LT<Lhs, Rhs> > {
     262             :     static const bool can_be_equal = false;
     263             :     static const bool prefer_short = true;
     264             : 
     265             :     typedef specialized_compare<Lhs> is_specialized;
     266             : };
     267             : 
     268             : template<typename Lhs, typename Rhs>
     269             : struct cctraits<op::LE<Lhs, Rhs> > {
     270             :     static const bool can_be_equal = true;
     271             :     static const bool prefer_short = true;
     272             : 
     273             :     typedef specialized_compare<Lhs> is_specialized;
     274             : };
     275             : 
     276             : template<typename Lhs, typename Rhs>
     277             : struct cctraits<op::GT<Lhs, Rhs> > {
     278             :     static const bool can_be_equal = false;
     279             :     static const bool prefer_short = false;
     280             : 
     281             :     typedef specialized_compare<Lhs> is_specialized;
     282             : };
     283             : 
     284             : template<typename Lhs, typename Rhs>
     285             : struct cctraits<op::GE<Lhs, Rhs> > {
     286             :     static const bool can_be_equal = true;
     287             :     static const bool prefer_short = false;
     288             : 
     289             :     typedef specialized_compare<Lhs> is_specialized;
     290             : };
     291             : 
     292             : // ************************************************************************** //
     293             : // **************              compare_collections             ************** //
     294             : // ************************************************************************** //
     295             : // Overloaded set of functions dispatching to specific implementation of comparison
     296             : 
     297             : template <typename Lhs, typename Rhs, typename L, typename R>
     298             : inline assertion_result
     299             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
     300             : {
     301             :     return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
     302             : }
     303             : 
     304             : //____________________________________________________________________________//
     305             : 
     306             : template <typename Lhs, typename Rhs, typename L, typename R>
     307             : inline assertion_result
     308           8 : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
     309             : {
     310           8 :     return lhs == rhs;
     311             : }
     312             : 
     313             : //____________________________________________________________________________//
     314             : 
     315             : template <typename Lhs, typename Rhs, typename L, typename R>
     316             : inline assertion_result
     317             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
     318             : {
     319             :     return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
     320             : }
     321             : 
     322             : //____________________________________________________________________________//
     323             : 
     324             : template <typename Lhs, typename Rhs, typename L, typename R>
     325             : inline assertion_result
     326             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
     327             : {
     328             :     return lhs != rhs;
     329             : }
     330             : 
     331             : //____________________________________________________________________________//
     332             : 
     333             : template <typename OP, typename Lhs, typename Rhs>
     334             : inline assertion_result
     335             : lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
     336             : {
     337             :     return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
     338             : }
     339             : 
     340             : //____________________________________________________________________________//
     341             : 
     342             : template <typename Lhs, typename Rhs, typename OP>
     343             : inline assertion_result
     344             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
     345             : {
     346             :     return lexicographic_compare<OP>( lhs, rhs );
     347             : }
     348             : 
     349             : //____________________________________________________________________________//
     350             : 
     351             : template <typename Lhs, typename Rhs, typename L, typename R>
     352             : inline assertion_result
     353             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
     354             : {
     355             :     return lhs < rhs;
     356             : }
     357             : 
     358             : //____________________________________________________________________________//
     359             : 
     360             : template <typename Lhs, typename Rhs, typename L, typename R>
     361             : inline assertion_result
     362             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
     363             : {
     364             :     return lhs <= rhs;
     365             : }
     366             : 
     367             : //____________________________________________________________________________//
     368             : 
     369             : template <typename Lhs, typename Rhs, typename L, typename R>
     370             : inline assertion_result
     371             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
     372             : {
     373             :     return lhs > rhs;
     374             : }
     375             : 
     376             : //____________________________________________________________________________//
     377             : 
     378             : template <typename Lhs, typename Rhs, typename L, typename R>
     379             : inline assertion_result
     380             : compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
     381             : {
     382             :     return lhs >= rhs;
     383             : }
     384             : 
     385             : //____________________________________________________________________________//
     386             : 
     387             : // ************************************************************************** //
     388             : // ********* specialization of comparison operators for collections ********* //
     389             : // ************************************************************************** //
     390             : 
     391             : #define DEFINE_COLLECTION_COMPARISON( oper, name, rev, name_inverse ) \
     392             : template<typename Lhs,typename Rhs>                                 \
     393             : struct name<Lhs,Rhs,typename boost::enable_if_c<                    \
     394             :     unit_test::is_forward_iterable<Lhs>::value                      \
     395             :     &&   !unit_test::is_cstring_comparable<Lhs>::value              \
     396             :     && unit_test::is_forward_iterable<Rhs>::value                   \
     397             :     &&   !unit_test::is_cstring_comparable<Rhs>::value>::type> {    \
     398             : public:                                                             \
     399             :     typedef assertion_result result_type;                           \
     400             :     typedef name_inverse<Lhs, Rhs> inverse;                         \
     401             :     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
     402             :     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
     403             :                                                                     \
     404             :     typedef name<Lhs, Rhs> OP;                                      \
     405             :                                                                     \
     406             :     typedef typename                                                \
     407             :         mpl::if_c<                                                  \
     408             :           mpl::or_<                                                 \
     409             :               typename is_c_array<Lhs>::type,                       \
     410             :               typename is_c_array<Rhs>::type                        \
     411             :           >::value,                                                 \
     412             :           mpl::true_,                                               \
     413             :           typename                                                  \
     414             :               mpl::if_c<is_same<typename decay<Lhs>::type,          \
     415             :                                 typename decay<Rhs>::type>::value,  \
     416             :                         typename cctraits<OP>::is_specialized,      \
     417             :                         mpl::false_>::type                          \
     418             :           >::type is_specialized;                                   \
     419             :                                                                     \
     420             :     typedef name<typename t_Lhs_iterator_helper::value_type,        \
     421             :                  typename t_Rhs_iterator_helper::value_type         \
     422             :                  > elem_op;                                         \
     423             :                                                                     \
     424             :     static assertion_result                                         \
     425             :     eval( Lhs const& lhs, Rhs const& rhs)                           \
     426             :     {                                                               \
     427             :         return assertion::op::compare_collections( lhs, rhs,        \
     428             :             (boost::type<elem_op>*)0,                               \
     429             :             is_specialized() );                                     \
     430             :     }                                                               \
     431             :                                                                     \
     432             :     template<typename PrevExprType>                                 \
     433             :     static void                                                     \
     434             :     report( std::ostream&,                                          \
     435             :             PrevExprType const&,                                    \
     436             :             Rhs const& ) {}                                         \
     437             :                                                                     \
     438             :     static char const* forward()                                    \
     439             :     { return " " #oper " "; }                                       \
     440             :     static char const* revert()                                     \
     441             :     { return " " #rev " "; }                                        \
     442             :                                                                     \
     443             : };                                                                  \
     444             : /**/
     445             : 
     446           8 : BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
     447             : #undef DEFINE_COLLECTION_COMPARISON
     448             : 
     449             : //____________________________________________________________________________//
     450             : 
     451             : } // namespace op
     452             : } // namespace assertion
     453             : } // namespace test_tools
     454             : } // namespace boost
     455             : 
     456             : #include <boost/test/detail/enable_warnings.hpp>
     457             : 
     458             : #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER

Generated by: LCOV version 1.16