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)
6 // See http://www.boost.org/libs/test for the library home page.
9 //!@brief Collection comparison with enhanced reporting
10 // ***************************************************************************
12 #ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
13 #define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
16 #include <boost/test/tools/assertion.hpp>
18 #include <boost/test/utils/is_forward_iterable.hpp>
19 #include <boost/test/utils/is_cstring.hpp>
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>
27 #include <boost/test/detail/suppress_warnings.hpp>
29 //____________________________________________________________________________//
32 namespace test_tools {
35 // ************************************************************************** //
36 // ************* selectors for specialized comparizon routines ************** //
37 // ************************************************************************** //
40 struct specialized_compare : public mpl::false_ {};
43 struct is_c_array : public mpl::false_ {};
45 template<typename T, std::size_t N>
46 struct is_c_array<T [N]> : public mpl::true_ {};
48 template<typename T, std::size_t N>
49 struct is_c_array<T (&)[N]> : public mpl::true_ {};
51 #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
52 namespace boost { namespace test_tools { namespace assertion { \
54 struct specialized_compare<Col> : public mpl::true_ {}; \
58 // ************************************************************************** //
59 // ************** lexicographic_compare ************** //
60 // ************************************************************************** //
64 template <typename OP, bool can_be_equal, bool prefer_shorter,
65 typename Lhs, typename Rhs>
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 )
73 assertion_result ar( true );
75 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
76 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
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);
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 )
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
93 if( element_ar || !reverse_ar )
94 continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
96 // !(a<=b) and b<=a => b < a => return false
98 ar.message() << "\nFailure at position " << pos << ": "
99 << tt_detail::print_helper(*first1)
101 << tt_detail::print_helper(*first2)
102 << ". " << element_ar.message();
106 if( first1 != last1 ) {
107 if( prefer_shorter ) {
109 ar.message() << "\nFirst collection has extra trailing elements.";
112 else if( first2 != last2 ) {
113 if( !prefer_shorter ) {
115 ar.message() << "\nSecond collection has extra trailing elements.";
118 else if( !can_be_equal ) {
120 ar.message() << "\nCollections appear to be equal.";
126 template <typename OP, bool can_be_equal, bool prefer_shorter,
127 typename Lhs, typename Rhs>
129 typename boost::enable_if_c<
130 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
131 assertion_result>::type
132 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
134 typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
135 typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
137 return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
142 //____________________________________________________________________________//
144 // ************************************************************************** //
145 // ************** equality_compare ************** //
146 // ************************************************************************** //
148 template <typename OP, typename Lhs, typename Rhs>
150 typename boost::enable_if_c<
151 unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
152 && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
153 assertion_result>::type
154 element_compare( Lhs const& lhs, Rhs const& rhs )
156 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
157 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
159 assertion_result ar( true );
161 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
163 ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
167 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
168 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
171 for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
172 assertion_result const element_ar = OP::eval( *left, *right );
177 ar.message() << "\nMismatch at position " << pos << ": "
178 << tt_detail::print_helper(*left)
180 << tt_detail::print_helper(*right)
181 << ". " << element_ar.message();
187 // In case string comparison is branching here
188 template <typename OP, typename Lhs, typename Rhs>
190 typename boost::enable_if_c<
191 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
192 assertion_result>::type
193 element_compare( Lhs const& lhs, Rhs const& rhs )
195 typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
196 typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
198 return element_compare<OP>(lhs_char_type(lhs),
202 //____________________________________________________________________________//
204 // ************************************************************************** //
205 // ************** non_equality_compare ************** //
206 // ************************************************************************** //
208 template <typename OP, typename Lhs, typename Rhs>
209 inline assertion_result
210 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
212 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
213 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
215 assertion_result ar( true );
217 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
220 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
221 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
222 typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
224 for( ; left != end; ++left, ++right ) {
225 if( OP::eval( *left, *right ) )
230 ar.message() << "\nCollections appear to be equal";
235 //____________________________________________________________________________//
237 // ************************************************************************** //
238 // ************** cctraits ************** //
239 // ************************************************************************** //
240 // set of collection comparison traits per comparison OP
242 template<typename OP>
245 template<typename Lhs, typename Rhs>
246 struct cctraits<op::EQ<Lhs, Rhs> > {
247 typedef specialized_compare<Lhs> is_specialized;
250 template<typename Lhs, typename Rhs>
251 struct cctraits<op::NE<Lhs, Rhs> > {
252 typedef specialized_compare<Lhs> is_specialized;
255 template<typename Lhs, typename Rhs>
256 struct cctraits<op::LT<Lhs, Rhs> > {
257 static const bool can_be_equal = false;
258 static const bool prefer_short = true;
260 typedef specialized_compare<Lhs> is_specialized;
263 template<typename Lhs, typename Rhs>
264 struct cctraits<op::LE<Lhs, Rhs> > {
265 static const bool can_be_equal = true;
266 static const bool prefer_short = true;
268 typedef specialized_compare<Lhs> is_specialized;
271 template<typename Lhs, typename Rhs>
272 struct cctraits<op::GT<Lhs, Rhs> > {
273 static const bool can_be_equal = false;
274 static const bool prefer_short = false;
276 typedef specialized_compare<Lhs> is_specialized;
279 template<typename Lhs, typename Rhs>
280 struct cctraits<op::GE<Lhs, Rhs> > {
281 static const bool can_be_equal = true;
282 static const bool prefer_short = false;
284 typedef specialized_compare<Lhs> is_specialized;
287 // ************************************************************************** //
288 // ************** compare_collections ************** //
289 // ************************************************************************** //
290 // Overloaded set of functions dispatching to specific implementation of comparison
292 template <typename Lhs, typename Rhs, typename L, typename R>
293 inline assertion_result
294 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
296 return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
299 //____________________________________________________________________________//
301 template <typename Lhs, typename Rhs, typename L, typename R>
302 inline assertion_result
303 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
308 //____________________________________________________________________________//
310 template <typename Lhs, typename Rhs, typename L, typename R>
311 inline assertion_result
312 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
314 return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
317 //____________________________________________________________________________//
319 template <typename Lhs, typename Rhs, typename L, typename R>
320 inline assertion_result
321 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
326 //____________________________________________________________________________//
328 template <typename OP, typename Lhs, typename Rhs>
329 inline assertion_result
330 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
332 return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
335 //____________________________________________________________________________//
337 template <typename Lhs, typename Rhs, typename OP>
338 inline assertion_result
339 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
341 return lexicographic_compare<OP>( lhs, rhs );
344 //____________________________________________________________________________//
346 template <typename Lhs, typename Rhs, typename L, typename R>
347 inline assertion_result
348 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
353 //____________________________________________________________________________//
355 template <typename Lhs, typename Rhs, typename L, typename R>
356 inline assertion_result
357 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
362 //____________________________________________________________________________//
364 template <typename Lhs, typename Rhs, typename L, typename R>
365 inline assertion_result
366 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
371 //____________________________________________________________________________//
373 template <typename Lhs, typename Rhs, typename L, typename R>
374 inline assertion_result
375 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
380 //____________________________________________________________________________//
382 // ************************************************************************** //
383 // ********* specialization of comparison operators for collections ********* //
384 // ************************************************************************** //
386 #define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \
387 template<typename Lhs,typename Rhs> \
388 struct name<Lhs,Rhs,typename boost::enable_if_c< \
389 unit_test::is_forward_iterable<Lhs>::value \
390 && !unit_test::is_cstring_comparable<Lhs>::value \
391 && unit_test::is_forward_iterable<Rhs>::value \
392 && !unit_test::is_cstring_comparable<Rhs>::value>::type> { \
394 typedef assertion_result result_type; \
395 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
396 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
398 typedef name<Lhs, Rhs> OP; \
403 typename is_c_array<Lhs>::type, \
404 typename is_c_array<Rhs>::type \
408 mpl::if_c<is_same<typename decay<Lhs>::type, \
409 typename decay<Rhs>::type>::value, \
410 typename cctraits<OP>::is_specialized, \
412 >::type is_specialized; \
414 typedef name<typename t_Lhs_iterator_helper::value_type, \
415 typename t_Rhs_iterator_helper::value_type \
418 static assertion_result \
419 eval( Lhs const& lhs, Rhs const& rhs) \
421 return assertion::op::compare_collections( lhs, rhs, \
422 (boost::type<elem_op>*)0, \
423 is_specialized() ); \
426 template<typename PrevExprType> \
428 report( std::ostream&, \
429 PrevExprType const&, \
432 static char const* revert() \
433 { return " " #rev " "; } \
438 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
439 #undef DEFINE_COLLECTION_COMPARISON
441 //____________________________________________________________________________//
444 } // namespace assertion
445 } // namespace test_tools
448 #include <boost/test/detail/enable_warnings.hpp>
450 #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER