File indexing completed on 2025-01-18 09:52:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
0013 #define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
0014
0015
0016 #include <boost/test/tools/assertion.hpp>
0017
0018 #include <boost/test/utils/is_forward_iterable.hpp>
0019 #include <boost/test/utils/is_cstring.hpp>
0020
0021
0022 #include <boost/mpl/bool.hpp>
0023 #include <boost/mpl/if.hpp>
0024 #include <boost/utility/enable_if.hpp>
0025 #include <boost/type_traits/decay.hpp>
0026
0027 #include <boost/test/detail/suppress_warnings.hpp>
0028
0029
0030
0031 namespace boost {
0032 namespace test_tools {
0033 namespace assertion {
0034
0035
0036
0037
0038
0039 template<typename T>
0040 struct specialized_compare : public mpl::false_ {};
0041
0042 template <typename T>
0043 struct is_c_array : public mpl::false_ {};
0044
0045 template<typename T, std::size_t N>
0046 struct is_c_array<T [N]> : public mpl::true_ {};
0047
0048 template<typename T, std::size_t N>
0049 struct is_c_array<T (&)[N]> : public mpl::true_ {};
0050
0051 #define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
0052 namespace boost { namespace test_tools { namespace assertion { \
0053 template<> \
0054 struct specialized_compare<Col> : public mpl::true_ {}; \
0055 }}} \
0056
0057
0058
0059
0060
0061
0062 namespace op {
0063
0064 template <typename OP, bool can_be_equal, bool prefer_shorter,
0065 typename Lhs, typename Rhs>
0066 inline
0067 typename boost::enable_if_c<
0068 unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
0069 && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
0070 assertion_result>::type
0071 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0072 {
0073 assertion_result ar( true );
0074
0075 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0076 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0077
0078 typename t_Lhs_iterator::const_iterator first1 = t_Lhs_iterator::begin(lhs);
0079 typename t_Rhs_iterator::const_iterator first2 = t_Rhs_iterator::begin(rhs);
0080 typename t_Lhs_iterator::const_iterator last1 = t_Lhs_iterator::end(lhs);
0081 typename t_Rhs_iterator::const_iterator last2 = t_Rhs_iterator::end(rhs);
0082 std::size_t pos = 0;
0083
0084 for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
0085 assertion_result const& element_ar = OP::eval(*first1, *first2);
0086 if( !can_be_equal && element_ar )
0087 return ar;
0088
0089 assertion_result const& reverse_ar = OP::eval(*first2, *first1);
0090 if( element_ar && !reverse_ar )
0091 return ar;
0092
0093 if( element_ar || !reverse_ar ) {
0094 continue;
0095 }
0096
0097
0098 ar = false;
0099 ar.message() << "\nFailure at position " << pos << ":";
0100 ar.message() << "\n - condition [" << tt_detail::print_helper(*first1) << OP::forward() << tt_detail::print_helper(*first2) << "] is false";
0101 if(!element_ar.has_empty_message())
0102 ar.message() << ": " << element_ar.message();
0103 ar.message() << "\n - inverse condition [" << tt_detail::print_helper(*first2) << OP::forward() << tt_detail::print_helper(*first1) << "] is true";
0104 if(!reverse_ar.has_empty_message())
0105 ar.message() << ": " << reverse_ar.message();
0106 return ar;
0107 }
0108
0109 if( first1 != last1 ) {
0110 if( prefer_shorter ) {
0111 ar = false;
0112 ar.message() << "\nFirst collection has extra trailing elements.";
0113 }
0114 }
0115 else if( first2 != last2 ) {
0116 if( !prefer_shorter ) {
0117 ar = false;
0118 ar.message() << "\nSecond collection has extra trailing elements.";
0119 }
0120 }
0121 else if( !can_be_equal ) {
0122 ar = false;
0123 ar.message() << "\nCollections appear to be equal.";
0124 }
0125
0126 return ar;
0127 }
0128
0129 template <typename OP, bool can_be_equal, bool prefer_shorter,
0130 typename Lhs, typename Rhs>
0131 inline
0132 typename boost::enable_if_c<
0133 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
0134 assertion_result>::type
0135 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0136 {
0137 typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
0138 typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
0139
0140 return lexicographic_compare<OP, can_be_equal, prefer_shorter>(
0141 lhs_char_type(lhs),
0142 rhs_char_type(rhs));
0143 }
0144
0145
0146
0147
0148
0149
0150
0151 template <typename OP, typename Lhs, typename Rhs>
0152 inline
0153 typename boost::enable_if_c<
0154 unit_test::is_forward_iterable<Lhs>::value && !unit_test::is_cstring<Lhs>::value
0155 && unit_test::is_forward_iterable<Rhs>::value && !unit_test::is_cstring<Rhs>::value,
0156 assertion_result>::type
0157 element_compare( Lhs const& lhs, Rhs const& rhs )
0158 {
0159 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0160 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0161
0162 assertion_result ar( true );
0163
0164 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) ) {
0165 ar = false;
0166 ar.message() << "\nCollections size mismatch: " << t_Lhs_iterator::size(lhs) << " != " << t_Rhs_iterator::size(rhs);
0167 return ar;
0168 }
0169
0170 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
0171 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
0172 std::size_t pos = 0;
0173
0174 for( ; pos < t_Lhs_iterator::size(lhs); ++left, ++right, ++pos ) {
0175 assertion_result const element_ar = OP::eval( *left, *right );
0176 if( element_ar )
0177 continue;
0178
0179 ar = false;
0180 ar.message() << "\n - mismatch at position " << pos << ": ["
0181 << tt_detail::print_helper(*left)
0182 << OP::forward()
0183 << tt_detail::print_helper(*right)
0184 << "] is false";
0185 if(!element_ar.has_empty_message())
0186 ar.message() << ": " << element_ar.message();
0187 }
0188
0189 return ar;
0190 }
0191
0192
0193 template <typename OP, typename Lhs, typename Rhs>
0194 inline
0195 typename boost::enable_if_c<
0196 (unit_test::is_cstring<Lhs>::value || unit_test::is_cstring<Rhs>::value),
0197 assertion_result>::type
0198 element_compare( Lhs const& lhs, Rhs const& rhs )
0199 {
0200 typedef typename unit_test::deduce_cstring_transform<Lhs>::type lhs_char_type;
0201 typedef typename unit_test::deduce_cstring_transform<Rhs>::type rhs_char_type;
0202
0203 return element_compare<OP>(lhs_char_type(lhs),
0204 rhs_char_type(rhs));
0205 }
0206
0207
0208
0209
0210
0211
0212
0213 template <typename OP, typename Lhs, typename Rhs>
0214 inline assertion_result
0215 non_equality_compare( Lhs const& lhs, Rhs const& rhs )
0216 {
0217 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator;
0218 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator;
0219
0220 assertion_result ar( true );
0221
0222 if( t_Lhs_iterator::size(lhs) != t_Rhs_iterator::size(rhs) )
0223 return ar;
0224
0225 typename t_Lhs_iterator::const_iterator left = t_Lhs_iterator::begin(lhs);
0226 typename t_Rhs_iterator::const_iterator right = t_Rhs_iterator::begin(rhs);
0227 typename t_Lhs_iterator::const_iterator end = t_Lhs_iterator::end(lhs);
0228
0229 for( ; left != end; ++left, ++right ) {
0230 if( OP::eval( *left, *right ) )
0231 return ar;
0232 }
0233
0234 ar = false;
0235 ar.message() << "\nCollections appear to be equal";
0236
0237 return ar;
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247 template<typename OP>
0248 struct cctraits;
0249
0250 template<typename Lhs, typename Rhs>
0251 struct cctraits<op::EQ<Lhs, Rhs> > {
0252 typedef specialized_compare<Lhs> is_specialized;
0253 };
0254
0255 template<typename Lhs, typename Rhs>
0256 struct cctraits<op::NE<Lhs, Rhs> > {
0257 typedef specialized_compare<Lhs> is_specialized;
0258 };
0259
0260 template<typename Lhs, typename Rhs>
0261 struct cctraits<op::LT<Lhs, Rhs> > {
0262 static const bool can_be_equal = false;
0263 static const bool prefer_short = true;
0264
0265 typedef specialized_compare<Lhs> is_specialized;
0266 };
0267
0268 template<typename Lhs, typename Rhs>
0269 struct cctraits<op::LE<Lhs, Rhs> > {
0270 static const bool can_be_equal = true;
0271 static const bool prefer_short = true;
0272
0273 typedef specialized_compare<Lhs> is_specialized;
0274 };
0275
0276 template<typename Lhs, typename Rhs>
0277 struct cctraits<op::GT<Lhs, Rhs> > {
0278 static const bool can_be_equal = false;
0279 static const bool prefer_short = false;
0280
0281 typedef specialized_compare<Lhs> is_specialized;
0282 };
0283
0284 template<typename Lhs, typename Rhs>
0285 struct cctraits<op::GE<Lhs, Rhs> > {
0286 static const bool can_be_equal = true;
0287 static const bool prefer_short = false;
0288
0289 typedef specialized_compare<Lhs> is_specialized;
0290 };
0291
0292
0293
0294
0295
0296
0297 template <typename Lhs, typename Rhs, typename L, typename R>
0298 inline assertion_result
0299 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
0300 {
0301 return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
0302 }
0303
0304
0305
0306 template <typename Lhs, typename Rhs, typename L, typename R>
0307 inline assertion_result
0308 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
0309 {
0310 return lhs == rhs;
0311 }
0312
0313
0314
0315 template <typename Lhs, typename Rhs, typename L, typename R>
0316 inline assertion_result
0317 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
0318 {
0319 return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
0320 }
0321
0322
0323
0324 template <typename Lhs, typename Rhs, typename L, typename R>
0325 inline assertion_result
0326 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
0327 {
0328 return lhs != rhs;
0329 }
0330
0331
0332
0333 template <typename OP, typename Lhs, typename Rhs>
0334 inline assertion_result
0335 lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
0336 {
0337 return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
0338 }
0339
0340
0341
0342 template <typename Lhs, typename Rhs, typename OP>
0343 inline assertion_result
0344 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>*, mpl::true_ )
0345 {
0346 return lexicographic_compare<OP>( lhs, rhs );
0347 }
0348
0349
0350
0351 template <typename Lhs, typename Rhs, typename L, typename R>
0352 inline assertion_result
0353 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >*, mpl::false_ )
0354 {
0355 return lhs < rhs;
0356 }
0357
0358
0359
0360 template <typename Lhs, typename Rhs, typename L, typename R>
0361 inline assertion_result
0362 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >*, mpl::false_ )
0363 {
0364 return lhs <= rhs;
0365 }
0366
0367
0368
0369 template <typename Lhs, typename Rhs, typename L, typename R>
0370 inline assertion_result
0371 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >*, mpl::false_ )
0372 {
0373 return lhs > rhs;
0374 }
0375
0376
0377
0378 template <typename Lhs, typename Rhs, typename L, typename R>
0379 inline assertion_result
0380 compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >*, mpl::false_ )
0381 {
0382 return lhs >= rhs;
0383 }
0384
0385
0386
0387
0388
0389
0390
0391 #define DEFINE_COLLECTION_COMPARISON( oper, name, rev, name_inverse ) \
0392 template<typename Lhs,typename Rhs> \
0393 struct name<Lhs,Rhs,typename boost::enable_if_c< \
0394 unit_test::is_forward_iterable<Lhs>::value \
0395 && !unit_test::is_cstring_comparable<Lhs>::value \
0396 && unit_test::is_forward_iterable<Rhs>::value \
0397 && !unit_test::is_cstring_comparable<Rhs>::value>::type> { \
0398 public: \
0399 typedef assertion_result result_type; \
0400 typedef name_inverse<Lhs, Rhs> inverse; \
0401 typedef unit_test::bt_iterator_traits<Lhs> t_Lhs_iterator_helper; \
0402 typedef unit_test::bt_iterator_traits<Rhs> t_Rhs_iterator_helper; \
0403 \
0404 typedef name<Lhs, Rhs> OP; \
0405 \
0406 typedef typename \
0407 mpl::if_c< \
0408 mpl::or_< \
0409 typename is_c_array<Lhs>::type, \
0410 typename is_c_array<Rhs>::type \
0411 >::value, \
0412 mpl::true_, \
0413 typename \
0414 mpl::if_c<is_same<typename decay<Lhs>::type, \
0415 typename decay<Rhs>::type>::value, \
0416 typename cctraits<OP>::is_specialized, \
0417 mpl::false_>::type \
0418 >::type is_specialized; \
0419 \
0420 typedef name<typename t_Lhs_iterator_helper::value_type, \
0421 typename t_Rhs_iterator_helper::value_type \
0422 > elem_op; \
0423 \
0424 static assertion_result \
0425 eval( Lhs const& lhs, Rhs const& rhs) \
0426 { \
0427 return assertion::op::compare_collections( lhs, rhs, \
0428 (boost::type<elem_op>*)0, \
0429 is_specialized() ); \
0430 } \
0431 \
0432 template<typename PrevExprType> \
0433 static void \
0434 report( std::ostream&, \
0435 PrevExprType const&, \
0436 Rhs const& ) {} \
0437 \
0438 static char const* forward() \
0439 { return " " #oper " "; } \
0440 static char const* revert() \
0441 { return " " #rev " "; } \
0442 \
0443 }; \
0444
0445
0446 BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
0447 #undef DEFINE_COLLECTION_COMPARISON
0448
0449
0450
0451 }
0452 }
0453 }
0454 }
0455
0456 #include <boost/test/detail/enable_warnings.hpp>
0457
0458 #endif