collection_comparison_op.hpp 17 KB

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