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>
21 #include <boost/mpl/bool.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/type_traits/decay.hpp>
25 #include <boost/test/detail/suppress_warnings.hpp>
27 //____________________________________________________________________________//
30 namespace test_tools {
33 // ************************************************************************** //
34 // ************* selectors for specialized comparizon routines ************** //
35 // ************************************************************************** //
38 struct specialized_compare : public mpl::false_ {};
40 #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
41 namespace boost { namespace test_tools { namespace assertion { \
43 struct specialized_compare<Col> : public mpl::true_ {}; \
47 // ************************************************************************** //
48 // ************** lexicographic_compare ************** //
49 // ************************************************************************** //
53 template <typename OP, bool can_be_equal, bool prefer_shorter,
54 typename Lhs, typename Rhs>
55 inline assertion_result
56 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
58 assertion_result ar( true );
60 typename Lhs::const_iterator first1 = lhs.begin();
61 typename Rhs::const_iterator first2 = rhs.begin();
62 typename Lhs::const_iterator last1 = lhs.end();
63 typename Rhs::const_iterator last2 = rhs.end();
66 for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
67 assertion_result const& element_ar = OP::eval(*first1, *first2);
68 if( !can_be_equal && element_ar )
71 assertion_result const& reverse_ar = OP::eval(*first2, *first1);
72 if( element_ar && !reverse_ar )
73 return ar; // a<=b and !(b<=a) => a < b => return true
75 if( element_ar || !reverse_ar )
76 continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
78 // !(a<=b) and b<=a => b < a => return false
80 ar.message() << "\nFailure at position " << pos << ": "
81 << tt_detail::print_helper(*first1)
83 << tt_detail::print_helper(*first2)
84 << ". " << element_ar.message();
89 if( first1 != last1 ) {
90 if( prefer_shorter ) {
92 ar.message() << "\nFirst collection has extra trailing elements.";
95 else if( first2 != last2 ) {
96 if( !prefer_shorter ) {
98 ar.message() << "\nSecond collection has extra trailing elements.";
101 else if( !can_be_equal ) {
103 ar.message() << "\nCollections appear to be equal.";
109 //____________________________________________________________________________//
111 // ************************************************************************** //
112 // ************** equality_compare ************** //
113 // ************************************************************************** //
115 template <typename OP, typename Lhs, typename Rhs>
116 inline assertion_result
117 element_compare( Lhs const& lhs, Rhs const& rhs )
119 assertion_result ar( true );
121 if( lhs.size() != rhs.size() ) {
123 ar.message() << "\nCollections size mismatch: " << lhs.size() << " != " << rhs.size();
127 typename Lhs::const_iterator left = lhs.begin();
128 typename Rhs::const_iterator right = rhs.begin();
131 for( ; pos < lhs.size(); ++left, ++right, ++pos ) {
132 assertion_result const element_ar = OP::eval( *left, *right );
137 ar.message() << "\nMismatch at position " << pos << ": "
138 << tt_detail::print_helper(*left)
140 << tt_detail::print_helper(*right)
141 << ". " << element_ar.message();
147 //____________________________________________________________________________//
149 // ************************************************************************** //
150 // ************** non_equality_compare ************** //
151 // ************************************************************************** //
153 template <typename OP, typename Lhs, typename Rhs>
154 inline assertion_result
155 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
157 assertion_result ar( true );
159 if( lhs.size() != rhs.size() )
162 typename Lhs::const_iterator left = lhs.begin();
163 typename Rhs::const_iterator right = rhs.begin();
164 typename Lhs::const_iterator end = lhs.end();
166 for( ; left != end; ++left, ++right ) {
167 if( OP::eval( *left, *right ) )
172 ar.message() << "\nCollections appear to be equal";
177 //____________________________________________________________________________//
179 // ************************************************************************** //
180 // ************** cctraits ************** //
181 // ************************************************************************** //
182 // set of collection comparison traits per comparison OP
184 template<typename OP>
187 template<typename Lhs, typename Rhs>
188 struct cctraits<op::EQ<Lhs, Rhs> > {
189 typedef specialized_compare<Lhs> is_specialized;
192 template<typename Lhs, typename Rhs>
193 struct cctraits<op::NE<Lhs, Rhs> > {
194 typedef specialized_compare<Lhs> is_specialized;
197 template<typename Lhs, typename Rhs>
198 struct cctraits<op::LT<Lhs, Rhs> > {
199 static const bool can_be_equal = false;
200 static const bool prefer_short = true;
202 typedef specialized_compare<Lhs> is_specialized;
205 template<typename Lhs, typename Rhs>
206 struct cctraits<op::LE<Lhs, Rhs> > {
207 static const bool can_be_equal = true;
208 static const bool prefer_short = true;
210 typedef specialized_compare<Lhs> is_specialized;
213 template<typename Lhs, typename Rhs>
214 struct cctraits<op::GT<Lhs, Rhs> > {
215 static const bool can_be_equal = false;
216 static const bool prefer_short = false;
218 typedef specialized_compare<Lhs> is_specialized;
221 template<typename Lhs, typename Rhs>
222 struct cctraits<op::GE<Lhs, Rhs> > {
223 static const bool can_be_equal = true;
224 static const bool prefer_short = false;
226 typedef specialized_compare<Lhs> is_specialized;
229 // ************************************************************************** //
230 // ************** compare_collections ************** //
231 // ************************************************************************** //
232 // Overloaded set of functions dispatching to specific implementation of comparison
234 template <typename Lhs, typename Rhs, typename L, typename R>
235 inline assertion_result
236 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
238 return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
241 //____________________________________________________________________________//
243 template <typename Lhs, typename Rhs, typename L, typename R>
244 inline assertion_result
245 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
250 //____________________________________________________________________________//
252 template <typename Lhs, typename Rhs, typename L, typename R>
253 inline assertion_result
254 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
256 return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
259 //____________________________________________________________________________//
261 template <typename Lhs, typename Rhs, typename L, typename R>
262 inline assertion_result
263 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
268 //____________________________________________________________________________//
270 template <typename OP, typename Lhs, typename Rhs>
271 inline assertion_result
272 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
274 return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
277 //____________________________________________________________________________//
279 template <typename Lhs, typename Rhs, typename OP>
280 inline assertion_result
281 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
283 return lexicographic_compare<OP>( lhs, rhs );
286 //____________________________________________________________________________//
288 template <typename Lhs, typename Rhs, typename L, typename R>
289 inline assertion_result
290 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
295 //____________________________________________________________________________//
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::LE<L, R> >*, mpl::false_ )
304 //____________________________________________________________________________//
306 template <typename Lhs, typename Rhs, typename L, typename R>
307 inline assertion_result
308 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
313 //____________________________________________________________________________//
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::GE<L, R> >*, mpl::false_ )
322 //____________________________________________________________________________//
324 // ************************************************************************** //
325 // ********* specialization of comparison operators for collections ********* //
326 // ************************************************************************** //
328 #define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \
329 template<typename Lhs,typename Rhs> \
330 struct name<Lhs,Rhs,typename boost::enable_if_c< \
331 unit_test::is_forward_iterable<Lhs>::value && \
332 unit_test::is_forward_iterable<Rhs>::value>::type> { \
334 typedef assertion_result result_type; \
336 typedef name<Lhs, Rhs> OP; \
338 mpl::if_c<is_same<typename decay<Lhs>::type, \
339 typename decay<Rhs>::type>::value, \
340 typename cctraits<OP>::is_specialized, \
341 mpl::false_>::type is_specialized; \
343 typedef name<typename Lhs::value_type, \
344 typename Rhs::value_type> elem_op; \
346 static assertion_result \
347 eval( Lhs const& lhs, Rhs const& rhs) \
349 return assertion::op::compare_collections( lhs, rhs, \
350 (boost::type<elem_op>*)0, \
351 is_specialized() ); \
354 template<typename PrevExprType> \
356 report( std::ostream&, \
357 PrevExprType const&, \
360 static char const* revert() \
361 { return " " #rev " "; } \
366 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
367 #undef DEFINE_COLLECTION_COMPARISON
369 //____________________________________________________________________________//
372 } // namespace assertion
373 } // namespace test_tools
376 #include <boost/test/detail/enable_warnings.hpp>
378 #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER