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/utility/enable_if.hpp>
24 #include <boost/type_traits/decay.hpp>
26 #include <boost/test/detail/suppress_warnings.hpp>
28 //____________________________________________________________________________//
31 namespace test_tools {
34 // ************************************************************************** //
35 // ************* selectors for specialized comparizon routines ************** //
36 // ************************************************************************** //
39 struct specialized_compare : public mpl::false_ {};
42 struct is_c_array : public mpl::false_ {};
44 template<typename T, std::size_t N>
45 struct is_c_array<T [N]> : public mpl::true_ {};
47 template<typename T, std::size_t N>
48 struct is_c_array<T (&)[N]> : public mpl::true_ {};
50 #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
51 namespace boost { namespace test_tools { namespace assertion { \
53 struct specialized_compare<Col> : public mpl::true_ {}; \
57 // ************************************************************************** //
58 // ************** lexicographic_compare ************** //
59 // ************************************************************************** //
63 template <typename OP, bool can_be_equal, bool prefer_shorter,
64 typename Lhs, typename Rhs>
66 typename boost::enable_if_c<
67 unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
68 && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
69 assertion_result>::type
70 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
72 assertion_result ar( true );
74 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
75 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
77 typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs);
78 typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs);
79 typename t_Lhs_iterator::const_iterator last1 = t_Lhs_iterator::end(lhs);
80 typename t_Rhs_iterator::const_iterator last2 = t_Rhs_iterator::end(rhs);
83 for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
84 assertion_result const& element_ar = OP::eval(*first1, *first2);
85 if( !can_be_equal && element_ar )
88 assertion_result const& reverse_ar = OP::eval(*first2, *first1);
89 if( element_ar && !reverse_ar )
90 return ar; // a<=b and !(b<=a) => a < b => return true
92 if( element_ar || !reverse_ar )
93 continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
95 // !(a<=b) and b<=a => b < a => return false
97 ar.message() << "\nFailure at position " << pos << ": "
98 << tt_detail::print_helper(*first1)
100 << tt_detail::print_helper(*first2)
101 << ". " << element_ar.message();
105 if( first1 != last1 ) {
106 if( prefer_shorter ) {
108 ar.message() << "\nFirst collection has extra trailing elements.";
111 else if( first2 != last2 ) {
112 if( !prefer_shorter ) {
114 ar.message() << "\nSecond collection has extra trailing elements.";
117 else if( !can_be_equal ) {
119 ar.message() << "\nCollections appear to be equal.";
125 template <typename OP, bool can_be_equal, bool prefer_shorter,
126 typename Lhs, typename Rhs>
128 typename boost::enable_if_c<
129 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
130 assertion_result>::type
131 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
133 typedef typename unit_test::deduce_cstring<Lhs>::type lhs_char_type;
134 typedef typename unit_test::deduce_cstring<Rhs>::type rhs_char_type;
136 return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
141 //____________________________________________________________________________//
143 // ************************************************************************** //
144 // ************** equality_compare ************** //
145 // ************************************************************************** //
147 template <typename OP, typename Lhs, typename Rhs>
149 typename boost::enable_if_c<
150 unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
151 && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
152 assertion_result>::type
153 element_compare( Lhs const& lhs, Rhs const& rhs )
155 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
156 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
158 assertion_result ar( true );
160 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
162 ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
166 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
167 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
170 for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
171 assertion_result const element_ar = OP::eval( *left, *right );
176 ar.message() << "\nMismatch at position " << pos << ": "
177 << tt_detail::print_helper(*left)
179 << tt_detail::print_helper(*right)
180 << ". " << element_ar.message();
186 // In case string comparison is branching here
187 template <typename OP, typename Lhs, typename Rhs>
189 typename boost::enable_if_c<
190 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
191 assertion_result>::type
192 element_compare( Lhs const& lhs, Rhs const& rhs )
194 typedef typename unit_test::deduce_cstring<Lhs>::type lhs_char_type;
195 typedef typename unit_test::deduce_cstring<Rhs>::type rhs_char_type;
197 return element_compare<OP>(lhs_char_type(lhs),
201 //____________________________________________________________________________//
203 // ************************************************************************** //
204 // ************** non_equality_compare ************** //
205 // ************************************************************************** //
207 template <typename OP, typename Lhs, typename Rhs>
208 inline assertion_result
209 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
211 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
212 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
214 assertion_result ar( true );
216 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
219 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
220 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
221 typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
223 for( ; left != end; ++left, ++right ) {
224 if( OP::eval( *left, *right ) )
229 ar.message() << "\nCollections appear to be equal";
234 //____________________________________________________________________________//
236 // ************************************************************************** //
237 // ************** cctraits ************** //
238 // ************************************************************************** //
239 // set of collection comparison traits per comparison OP
241 template<typename OP>
244 template<typename Lhs, typename Rhs>
245 struct cctraits<op::EQ<Lhs, Rhs> > {
246 typedef specialized_compare<Lhs> is_specialized;
249 template<typename Lhs, typename Rhs>
250 struct cctraits<op::NE<Lhs, Rhs> > {
251 typedef specialized_compare<Lhs> is_specialized;
254 template<typename Lhs, typename Rhs>
255 struct cctraits<op::LT<Lhs, Rhs> > {
256 static const bool can_be_equal = false;
257 static const bool prefer_short = true;
259 typedef specialized_compare<Lhs> is_specialized;
262 template<typename Lhs, typename Rhs>
263 struct cctraits<op::LE<Lhs, Rhs> > {
264 static const bool can_be_equal = true;
265 static const bool prefer_short = true;
267 typedef specialized_compare<Lhs> is_specialized;
270 template<typename Lhs, typename Rhs>
271 struct cctraits<op::GT<Lhs, Rhs> > {
272 static const bool can_be_equal = false;
273 static const bool prefer_short = false;
275 typedef specialized_compare<Lhs> is_specialized;
278 template<typename Lhs, typename Rhs>
279 struct cctraits<op::GE<Lhs, Rhs> > {
280 static const bool can_be_equal = true;
281 static const bool prefer_short = false;
283 typedef specialized_compare<Lhs> is_specialized;
286 // ************************************************************************** //
287 // ************** compare_collections ************** //
288 // ************************************************************************** //
289 // Overloaded set of functions dispatching to specific implementation of comparison
291 template <typename Lhs, typename Rhs, typename L, typename R>
292 inline assertion_result
293 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
295 return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
298 //____________________________________________________________________________//
300 template <typename Lhs, typename Rhs, typename L, typename R>
301 inline assertion_result
302 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
307 //____________________________________________________________________________//
309 template <typename Lhs, typename Rhs, typename L, typename R>
310 inline assertion_result
311 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
313 return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
316 //____________________________________________________________________________//
318 template <typename Lhs, typename Rhs, typename L, typename R>
319 inline assertion_result
320 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
325 //____________________________________________________________________________//
327 template <typename OP, typename Lhs, typename Rhs>
328 inline assertion_result
329 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
331 return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
334 //____________________________________________________________________________//
336 template <typename Lhs, typename Rhs, typename OP>
337 inline assertion_result
338 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
340 return lexicographic_compare<OP>( lhs, rhs );
343 //____________________________________________________________________________//
345 template <typename Lhs, typename Rhs, typename L, typename R>
346 inline assertion_result
347 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
352 //____________________________________________________________________________//
354 template <typename Lhs, typename Rhs, typename L, typename R>
355 inline assertion_result
356 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
361 //____________________________________________________________________________//
363 template <typename Lhs, typename Rhs, typename L, typename R>
364 inline assertion_result
365 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
370 //____________________________________________________________________________//
372 template <typename Lhs, typename Rhs, typename L, typename R>
373 inline assertion_result
374 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
379 //____________________________________________________________________________//
381 // ************************************************************************** //
382 // ********* specialization of comparison operators for collections ********* //
383 // ************************************************************************** //
385 #define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \
386 template<typename Lhs,typename Rhs> \
387 struct name<Lhs,Rhs,typename boost::enable_if_c< \
388 unit_test::is_forward_iterable<Lhs>::value \
389 && !unit_test::is_cstring_comparable<Lhs>::value \
390 && unit_test::is_forward_iterable<Rhs>::value \
391 && !unit_test::is_cstring_comparable<Rhs>::value>::type> { \
393 typedef assertion_result result_type; \
394 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
395 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
397 typedef name<Lhs, Rhs> OP; \
402 typename is_c_array<Lhs>::type, \
403 typename is_c_array<Rhs>::type \
407 mpl::if_c<is_same<typename decay<Lhs>::type, \
408 typename decay<Rhs>::type>::value, \
409 typename cctraits<OP>::is_specialized, \
411 >::type is_specialized; \
413 typedef name<typename t_Lhs_iterator_helper::value_type, \
414 typename t_Rhs_iterator_helper::value_type \
417 static assertion_result \
418 eval( Lhs const& lhs, Rhs const& rhs) \
420 return assertion::op::compare_collections( lhs, rhs, \
421 (boost::type<elem_op>*)0, \
422 is_specialized() ); \
425 template<typename PrevExprType> \
427 report( std::ostream&, \
428 PrevExprType const&, \
431 static char const* revert() \
432 { return " " #rev " "; } \
437 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
438 #undef DEFINE_COLLECTION_COMPARISON
440 //____________________________________________________________________________//
443 } // namespace assertion
444 } // namespace test_tools
447 #include <boost/test/detail/enable_warnings.hpp>
449 #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER