Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / test / tools / collection_comparison_op.hpp
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         // !(a<=b) and b<=a => b < a => return false
97         ar = false;
98         ar.message() << "\nFailure at position " << pos << ": "
99                      << tt_detail::print_helper(*first1)
100                      << OP::revert()
101                      << tt_detail::print_helper(*first2)
102                      << ". " << element_ar.message();
103         return ar;
104     }
105
106     if( first1 != last1 ) {
107         if( prefer_shorter ) {
108             ar = false;
109             ar.message() << "\nFirst collection has extra trailing elements.";
110         }
111     }
112     else if( first2 != last2 ) {
113         if( !prefer_shorter ) {
114             ar = false;
115             ar.message() << "\nSecond collection has extra trailing elements.";
116         }
117     }
118     else if( !can_be_equal ) {
119         ar = false;
120         ar.message() << "\nCollections appear to be equal.";
121     }
122
123     return ar;
124 }
125
126 template <typename OP, bool can_be_equal, bool prefer_shorter,
127           typename Lhs, typename Rhs>
128 inline
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 )
133 {
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;
136
137     return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
138         lhs_char_type(lhs),
139         rhs_char_type(rhs));
140 }
141
142 //____________________________________________________________________________//
143
144 // ************************************************************************** //
145 // **************               equality_compare               ************** //
146 // ************************************************************************** //
147
148 template <typename OP, typename Lhs, typename Rhs>
149 inline
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 )
155 {
156     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
157     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
158
159     assertion_result ar( true );
160
161     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
162         ar = false;
163         ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
164         return ar;
165     }
166
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);
169     std::size_t                             pos   = 0;
170
171     for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
172         assertion_result const element_ar = OP::eval( *left, *right );
173         if( element_ar )
174             continue;
175
176         ar = false;
177         ar.message() << "\nMismatch at position " << pos << ": "
178                      << tt_detail::print_helper(*left)
179                      << OP::revert()
180                      << tt_detail::print_helper(*right)
181                      << ". " << element_ar.message();
182     }
183
184     return ar;
185 }
186
187 // In case string comparison is branching here
188 template <typename OP, typename Lhs, typename Rhs>
189 inline
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 )
194 {
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;
197
198     return element_compare<OP>(lhs_char_type(lhs),
199                                rhs_char_type(rhs));
200 }
201
202 //____________________________________________________________________________//
203
204 // ************************************************************************** //
205 // **************             non_equality_compare             ************** //
206 // ************************************************************************** //
207
208 template <typename OP, typename Lhs, typename Rhs>
209 inline assertion_result
210 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
211 {
212     typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
213     typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
214
215     assertion_result ar( true );
216
217     if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
218         return ar;
219
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);
223
224     for( ; left != end; ++left, ++right ) {
225         if( OP::eval( *left, *right ) )
226             return ar;
227     }
228
229     ar = false;
230     ar.message() << "\nCollections appear to be equal";
231
232     return ar;
233 }
234
235 //____________________________________________________________________________//
236
237 // ************************************************************************** //
238 // **************                   cctraits                   ************** //
239 // ************************************************************************** //
240 // set of collection comparison traits per comparison OP
241
242 template<typename OP>
243 struct cctraits;
244
245 template<typename Lhs, typename Rhs>
246 struct cctraits<op::EQ<Lhs, Rhs> > {
247     typedef specialized_compare<Lhs> is_specialized;
248 };
249
250 template<typename Lhs, typename Rhs>
251 struct cctraits<op::NE<Lhs, Rhs> > {
252     typedef specialized_compare<Lhs> is_specialized;
253 };
254
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;
259
260     typedef specialized_compare<Lhs> is_specialized;
261 };
262
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;
267
268     typedef specialized_compare<Lhs> is_specialized;
269 };
270
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;
275
276     typedef specialized_compare<Lhs> is_specialized;
277 };
278
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;
283
284     typedef specialized_compare<Lhs> is_specialized;
285 };
286
287 // ************************************************************************** //
288 // **************              compare_collections             ************** //
289 // ************************************************************************** //
290 // Overloaded set of functions dispatching to specific implementation of comparison
291
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_ )
295 {
296     return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
297 }
298
299 //____________________________________________________________________________//
300
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_ )
304 {
305     return lhs == rhs;
306 }
307
308 //____________________________________________________________________________//
309
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_ )
313 {
314     return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
315 }
316
317 //____________________________________________________________________________//
318
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_ )
322 {
323     return lhs != rhs;
324 }
325
326 //____________________________________________________________________________//
327
328 template <typename OP, typename Lhs, typename Rhs>
329 inline assertion_result
330 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
331 {
332     return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
333 }
334
335 //____________________________________________________________________________//
336
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_ )
340 {
341     return lexicographic_compare<OP>( lhs, rhs );
342 }
343
344 //____________________________________________________________________________//
345
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_ )
349 {
350     return lhs < rhs;
351 }
352
353 //____________________________________________________________________________//
354
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_ )
358 {
359     return lhs <= rhs;
360 }
361
362 //____________________________________________________________________________//
363
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_ )
367 {
368     return lhs > rhs;
369 }
370
371 //____________________________________________________________________________//
372
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_ )
376 {
377     return lhs >= rhs;
378 }
379
380 //____________________________________________________________________________//
381
382 // ************************************************************************** //
383 // ********* specialization of comparison operators for collections ********* //
384 // ************************************************************************** //
385
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> {               \
393 public:                                                             \
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; \
397                                                                     \
398     typedef name<Lhs, Rhs> OP;                                      \
399                                                                     \
400     typedef typename                                                \
401         mpl::if_c<                                                  \
402           mpl::or_<                                                 \
403               typename is_c_array<Lhs>::type,                       \
404               typename is_c_array<Rhs>::type                        \
405           >::value,                                                 \
406           mpl::true_,                                               \
407           typename                                                  \
408               mpl::if_c<is_same<typename decay<Lhs>::type,          \
409                                 typename decay<Rhs>::type>::value,  \
410                         typename cctraits<OP>::is_specialized,      \
411                         mpl::false_>::type                          \
412           >::type is_specialized;                                   \
413                                                                     \
414     typedef name<typename t_Lhs_iterator_helper::value_type,        \
415                  typename t_Rhs_iterator_helper::value_type         \
416                  > elem_op;                                         \
417                                                                     \
418     static assertion_result                                         \
419     eval( Lhs const& lhs, Rhs const& rhs)                           \
420     {                                                               \
421         return assertion::op::compare_collections( lhs, rhs,        \
422             (boost::type<elem_op>*)0,                               \
423             is_specialized() );                                     \
424     }                                                               \
425                                                                     \
426     template<typename PrevExprType>                                 \
427     static void                                                     \
428     report( std::ostream&,                                          \
429             PrevExprType const&,                                    \
430             Rhs const& ) {}                                         \
431                                                                     \
432     static char const* revert()                                     \
433     { return " " #rev " "; }                                        \
434                                                                     \
435 };                                                                  \
436 /**/
437
438 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
439 #undef DEFINE_COLLECTION_COMPARISON
440
441 //____________________________________________________________________________//
442
443 } // namespace op
444 } // namespace assertion
445 } // namespace test_tools
446 } // namespace boost
447
448 #include <boost/test/detail/enable_warnings.hpp>
449
450 #endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER