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
20// Boost
21#include <boost/mpl/bool.hpp>
22#include <boost/utility/enable_if.hpp>
23#include <boost/type_traits/decay.hpp>
24
25#include <boost/test/detail/suppress_warnings.hpp>
26
27//____________________________________________________________________________//
28
29namespace boost {
30namespace test_tools {
31namespace assertion {
32
33// ************************************************************************** //
34// ************* selectors for specialized comparizon routines ************** //
35// ************************************************************************** //
36
37template<typename T>
38struct specialized_compare : public mpl::false_ {};
39
40#define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
41namespace boost { namespace test_tools { namespace assertion { \
42template<> \
43struct specialized_compare<Col> : public mpl::true_ {}; \
44}}} \
45/**/
46
47// ************************************************************************** //
48// ************** lexicographic_compare ************** //
49// ************************************************************************** //
50
51namespace op {
52
53template <typename OP, bool can_be_equal, bool prefer_shorter,
54 typename Lhs, typename Rhs>
55inline assertion_result
56lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
57{
58 assertion_result ar( true );
59
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();
64 std::size_t pos = 0;
65
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 )
69 return ar; // a < b
70
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
74
75 if( element_ar || !reverse_ar )
76 continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
77
78 // !(a<=b) and b<=a => b < a => return false
79 ar = false;
80 ar.message() << "\nFailure at position " << pos << ": "
81 << tt_detail::print_helper(*first1)
82 << OP::revert()
83 << tt_detail::print_helper(*first2)
84 << ". " << element_ar.message();
85 return ar;
86 }
87
88
89 if( first1 != last1 ) {
90 if( prefer_shorter ) {
91 ar = false;
92 ar.message() << "\nFirst collection has extra trailing elements.";
93 }
94 }
95 else if( first2 != last2 ) {
96 if( !prefer_shorter ) {
97 ar = false;
98 ar.message() << "\nSecond collection has extra trailing elements.";
99 }
100 }
101 else if( !can_be_equal ) {
102 ar = false;
103 ar.message() << "\nCollections appear to be equal.";
104 }
105
106 return ar;
107}
108
109//____________________________________________________________________________//
110
111// ************************************************************************** //
112// ************** equality_compare ************** //
113// ************************************************************************** //
114
115template <typename OP, typename Lhs, typename Rhs>
116inline assertion_result
117element_compare( Lhs const& lhs, Rhs const& rhs )
118{
119 assertion_result ar( true );
120
121 if( lhs.size() != rhs.size() ) {
122 ar = false;
123 ar.message() << "\nCollections size mismatch: " << lhs.size() << " != " << rhs.size();
124 return ar;
125 }
126
127 typename Lhs::const_iterator left = lhs.begin();
128 typename Rhs::const_iterator right = rhs.begin();
129 std::size_t pos = 0;
130
131 for( ; pos < lhs.size(); ++left, ++right, ++pos ) {
132 assertion_result const element_ar = OP::eval( *left, *right );
133 if( element_ar )
134 continue;
135
136 ar = false;
137 ar.message() << "\nMismatch at position " << pos << ": "
138 << tt_detail::print_helper(*left)
139 << OP::revert()
140 << tt_detail::print_helper(*right)
141 << ". " << element_ar.message();
142 }
143
144 return ar;
145}
146
147//____________________________________________________________________________//
148
149// ************************************************************************** //
150// ************** non_equality_compare ************** //
151// ************************************************************************** //
152
153template <typename OP, typename Lhs, typename Rhs>
154inline assertion_result
155non_equality_compare( Lhs const& lhs, Rhs const& rhs )
156{
157 assertion_result ar( true );
158
159 if( lhs.size() != rhs.size() )
160 return ar;
161
162 typename Lhs::const_iterator left = lhs.begin();
163 typename Rhs::const_iterator right = rhs.begin();
164 typename Lhs::const_iterator end = lhs.end();
165
166 for( ; left != end; ++left, ++right ) {
167 if( OP::eval( *left, *right ) )
168 return ar;
169 }
170
171 ar = false;
172 ar.message() << "\nCollections appear to be equal";
173
174 return ar;
175}
176
177//____________________________________________________________________________//
178
179// ************************************************************************** //
180// ************** cctraits ************** //
181// ************************************************************************** //
182// set of collection comparison traits per comparison OP
183
184template<typename OP>
185struct cctraits;
186
187template<typename Lhs, typename Rhs>
188struct cctraits<op::EQ<Lhs, Rhs> > {
189 typedef specialized_compare<Lhs> is_specialized;
190};
191
192template<typename Lhs, typename Rhs>
193struct cctraits<op::NE<Lhs, Rhs> > {
194 typedef specialized_compare<Lhs> is_specialized;
195};
196
197template<typename Lhs, typename Rhs>
198struct cctraits<op::LT<Lhs, Rhs> > {
199 static const bool can_be_equal = false;
200 static const bool prefer_short = true;
201
202 typedef specialized_compare<Lhs> is_specialized;
203};
204
205template<typename Lhs, typename Rhs>
206struct cctraits<op::LE<Lhs, Rhs> > {
207 static const bool can_be_equal = true;
208 static const bool prefer_short = true;
209
210 typedef specialized_compare<Lhs> is_specialized;
211};
212
213template<typename Lhs, typename Rhs>
214struct cctraits<op::GT<Lhs, Rhs> > {
215 static const bool can_be_equal = false;
216 static const bool prefer_short = false;
217
218 typedef specialized_compare<Lhs> is_specialized;
219};
220
221template<typename Lhs, typename Rhs>
222struct cctraits<op::GE<Lhs, Rhs> > {
223 static const bool can_be_equal = true;
224 static const bool prefer_short = false;
225
226 typedef specialized_compare<Lhs> is_specialized;
227};
228
229// ************************************************************************** //
230// ************** compare_collections ************** //
231// ************************************************************************** //
232// Overloaded set of functions dispatching to specific implementation of comparison
233
234template <typename Lhs, typename Rhs, typename L, typename R>
235inline assertion_result
236compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
237{
238 return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
239}
240
241//____________________________________________________________________________//
242
243template <typename Lhs, typename Rhs, typename L, typename R>
244inline assertion_result
245compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
246{
247 return lhs == rhs;
248}
249
250//____________________________________________________________________________//
251
252template <typename Lhs, typename Rhs, typename L, typename R>
253inline assertion_result
254compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
255{
256 return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
257}
258
259//____________________________________________________________________________//
260
261template <typename Lhs, typename Rhs, typename L, typename R>
262inline assertion_result
263compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
264{
265 return lhs != rhs;
266}
267
268//____________________________________________________________________________//
269
270template <typename OP, typename Lhs, typename Rhs>
271inline assertion_result
272lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
273{
274 return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
275}
276
277//____________________________________________________________________________//
278
279template <typename Lhs, typename Rhs, typename OP>
280inline assertion_result
281compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>* tp, mpl::true_ )
282{
283 return lexicographic_compare<OP>( lhs, rhs );
284}
285
286//____________________________________________________________________________//
287
288template <typename Lhs, typename Rhs, typename L, typename R>
289inline assertion_result
290compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >* tp, mpl::false_ )
291{
292 return lhs < rhs;
293}
294
295//____________________________________________________________________________//
296
297template <typename Lhs, typename Rhs, typename L, typename R>
298inline assertion_result
299compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >* tp, mpl::false_ )
300{
301 return lhs <= rhs;
302}
303
304//____________________________________________________________________________//
305
306template <typename Lhs, typename Rhs, typename L, typename R>
307inline assertion_result
308compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >* tp, mpl::false_ )
309{
310 return lhs > rhs;
311}
312
313//____________________________________________________________________________//
314
315template <typename Lhs, typename Rhs, typename L, typename R>
316inline assertion_result
317compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >* tp, mpl::false_ )
318{
319 return lhs >= rhs;
320}
321
322//____________________________________________________________________________//
323
324// ************************************************************************** //
325// ********* specialization of comparison operators for collections ********* //
326// ************************************************************************** //
327
328#define DEFINE_COLLECTION_COMPARISON( oper, name, rev ) \
329template<typename Lhs,typename Rhs> \
330struct 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> { \
333public: \
334 typedef assertion_result result_type; \
335 \
336 typedef name<Lhs, Rhs> OP; \
337 typedef typename \
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; \
342 \
343 typedef name<typename Lhs::value_type, \
344 typename Rhs::value_type> elem_op; \
345 \
346 static assertion_result \
347 eval( Lhs const& lhs, Rhs const& rhs) \
348 { \
349 return assertion::op::compare_collections( lhs, rhs, \
350 (boost::type<elem_op>*)0, \
351 is_specialized() ); \
352 } \
353 \
354 template<typename PrevExprType> \
355 static void \
356 report( std::ostream&, \
357 PrevExprType const&, \
358 Rhs const& ) {} \
359 \
360 static char const* revert() \
361 { return " " #rev " "; } \
362 \
363}; \
364/**/
365
366BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
367#undef DEFINE_COLLECTION_COMPARISON
368
369//____________________________________________________________________________//
370
371} // namespace op
372} // namespace assertion
373} // namespace test_tools
374} // namespace boost
375
376#include <boost/test/detail/enable_warnings.hpp>
377
378#endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
379