collection_comparison_op.hpp 18 KB

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