summaryrefslogtreecommitdiff
path: root/boost/test/tools/collection_comparison_op.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/test/tools/collection_comparison_op.hpp')
-rw-r--r--boost/test/tools/collection_comparison_op.hpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/boost/test/tools/collection_comparison_op.hpp b/boost/test/tools/collection_comparison_op.hpp
new file mode 100644
index 0000000000..81a7046725
--- /dev/null
+++ b/boost/test/tools/collection_comparison_op.hpp
@@ -0,0 +1,375 @@
+// (C) Copyright Gennadiy Rozental 2014-2015.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org/libs/test for the library home page.
+//
+//!@file
+//!@brief Collection comparison with enhanced reporting
+// ***************************************************************************
+
+#ifndef BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
+#define BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
+
+// Boost.Test
+#include <boost/test/tools/assertion.hpp>
+
+#include <boost/test/utils/is_forward_iterable.hpp>
+
+// Boost
+#include <boost/mpl/bool.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits/decay.hpp>
+
+#include <boost/test/detail/suppress_warnings.hpp>
+
+//____________________________________________________________________________//
+
+namespace boost {
+namespace test_tools {
+namespace assertion {
+
+// ************************************************************************** //
+// ************* selectors for specialized comparizon routines ************** //
+// ************************************************************************** //
+
+template<typename T>
+struct specialized_compare : public mpl::false_ {};
+
+#define BOOST_TEST_SPECIALIZED_COLLECTION_COMPARE(Col) \
+namespace boost { namespace test_tools { namespace assertion { \
+template<> \
+struct specialized_compare<Col> : public mpl::true_ {}; \
+}}} \
+/**/
+
+// ************************************************************************** //
+// ************** lexicographic_compare ************** //
+// ************************************************************************** //
+
+namespace op {
+
+template <typename OP, bool can_be_equal, bool prefer_shorter,
+ typename Lhs, typename Rhs>
+inline assertion_result
+lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
+{
+ assertion_result ar( true );
+
+ typename Lhs::const_iterator first1 = lhs.begin();
+ typename Rhs::const_iterator first2 = rhs.begin();
+ typename Lhs::const_iterator last1 = lhs.end();
+ typename Rhs::const_iterator last2 = rhs.end();
+ std::size_t pos = 0;
+
+ for( ; (first1 != last1) && (first2 != last2); ++first1, ++first2, ++pos ) {
+ assertion_result const& element_ar = OP::eval(*first1, *first2);
+ if( !can_be_equal && element_ar )
+ return ar; // a < b
+
+ assertion_result const& reverse_ar = OP::eval(*first2, *first1);
+ if( element_ar && !reverse_ar )
+ return ar; // a<=b and !(b<=a) => a < b => return true
+
+ if( element_ar || !reverse_ar )
+ continue; // (a<=b and b<=a) or (!(a<b) and !(b<a)) => a == b => keep looking
+
+ // !(a<=b) and b<=a => b < a => return false
+ ar = false;
+ ar.message() << "\nFailure at position " << pos << ": "
+ << tt_detail::print_helper(*first1)
+ << OP::revert()
+ << tt_detail::print_helper(*first2)
+ << ". " << element_ar.message();
+ return ar;
+ }
+
+
+ if( first1 != last1 ) {
+ if( prefer_shorter ) {
+ ar = false;
+ ar.message() << "\nFirst collection has extra trailing elements.";
+ }
+ }
+ else if( first2 != last2 ) {
+ if( !prefer_shorter ) {
+ ar = false;
+ ar.message() << "\nSecond collection has extra trailing elements.";
+ }
+ }
+ else if( !can_be_equal ) {
+ ar = false;
+ ar.message() << "\nCollections appear to be equal.";
+ }
+
+ return ar;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** equality_compare ************** //
+// ************************************************************************** //
+
+template <typename OP, typename Lhs, typename Rhs>
+inline assertion_result
+element_compare( Lhs const& lhs, Rhs const& rhs )
+{
+ assertion_result ar( true );
+
+ if( lhs.size() != rhs.size() ) {
+ ar = false;
+ ar.message() << "\nCollections size mismatch: " << lhs.size() << " != " << rhs.size();
+ return ar;
+ }
+
+ typename Lhs::const_iterator left = lhs.begin();
+ typename Rhs::const_iterator right = rhs.begin();
+ std::size_t pos = 0;
+
+ for( ; pos < lhs.size(); ++left, ++right, ++pos ) {
+ assertion_result const element_ar = OP::eval( *left, *right );
+ if( element_ar )
+ continue;
+
+ ar = false;
+ ar.message() << "\nMismatch at position " << pos << ": "
+ << tt_detail::print_helper(*left)
+ << OP::revert()
+ << tt_detail::print_helper(*right)
+ << ". " << element_ar.message();
+ }
+
+ return ar;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** non_equality_compare ************** //
+// ************************************************************************** //
+
+template <typename OP, typename Lhs, typename Rhs>
+inline assertion_result
+non_equality_compare( Lhs const& lhs, Rhs const& rhs )
+{
+ assertion_result ar( true );
+
+ if( lhs.size() != rhs.size() )
+ return ar;
+
+ typename Lhs::const_iterator left = lhs.begin();
+ typename Rhs::const_iterator right = rhs.begin();
+ typename Lhs::const_iterator end = lhs.end();
+
+ for( ; left != end; ++left, ++right ) {
+ if( OP::eval( *left, *right ) )
+ return ar;
+ }
+
+ ar = false;
+ ar.message() << "\nCollections appear to be equal";
+
+ return ar;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ************** cctraits ************** //
+// ************************************************************************** //
+// set of collection comparison traits per comparison OP
+
+template<typename OP>
+struct cctraits;
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::EQ<Lhs, Rhs> > {
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::NE<Lhs, Rhs> > {
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::LT<Lhs, Rhs> > {
+ static const bool can_be_equal = false;
+ static const bool prefer_short = true;
+
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::LE<Lhs, Rhs> > {
+ static const bool can_be_equal = true;
+ static const bool prefer_short = true;
+
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::GT<Lhs, Rhs> > {
+ static const bool can_be_equal = false;
+ static const bool prefer_short = false;
+
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+template<typename Lhs, typename Rhs>
+struct cctraits<op::GE<Lhs, Rhs> > {
+ static const bool can_be_equal = true;
+ static const bool prefer_short = false;
+
+ typedef specialized_compare<Lhs> is_specialized;
+};
+
+// ************************************************************************** //
+// ************** compare_collections ************** //
+// ************************************************************************** //
+// Overloaded set of functions dispatching to specific implementation of comparison
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::true_ )
+{
+ return assertion::op::element_compare<op::EQ<L, R> >( lhs, rhs );
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::EQ<L, R> >*, mpl::false_ )
+{
+ return lhs == rhs;
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::true_ )
+{
+ return assertion::op::non_equality_compare<op::NE<L, R> >( lhs, rhs );
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::NE<L, R> >*, mpl::false_ )
+{
+ return lhs != rhs;
+}
+
+//____________________________________________________________________________//
+
+template <typename OP, typename Lhs, typename Rhs>
+inline assertion_result
+lexicographic_compare( Lhs const& lhs, Rhs const& rhs )
+{
+ return assertion::op::lexicographic_compare<OP, cctraits<OP>::can_be_equal, cctraits<OP>::prefer_short>( lhs, rhs );
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename OP>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<OP>* tp, mpl::true_ )
+{
+ return lexicographic_compare<OP>( lhs, rhs );
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LT<L, R> >* tp, mpl::false_ )
+{
+ return lhs < rhs;
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::LE<L, R> >* tp, mpl::false_ )
+{
+ return lhs <= rhs;
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GT<L, R> >* tp, mpl::false_ )
+{
+ return lhs > rhs;
+}
+
+//____________________________________________________________________________//
+
+template <typename Lhs, typename Rhs, typename L, typename R>
+inline assertion_result
+compare_collections( Lhs const& lhs, Rhs const& rhs, boost::type<op::GE<L, R> >* tp, mpl::false_ )
+{
+ return lhs >= rhs;
+}
+
+//____________________________________________________________________________//
+
+// ************************************************************************** //
+// ********* specialization of comparison operators for collections ********* //
+// ************************************************************************** //
+
+#define DEFINE_COLLECTION_COMPARISON( oper, name, _ ) \
+template<typename Lhs,typename Rhs> \
+struct name<Lhs,Rhs,typename boost::enable_if_c< \
+ unit_test::is_forward_iterable<Lhs>::value && \
+ unit_test::is_forward_iterable<Rhs>::value>::type> { \
+public: \
+ typedef assertion_result result_type; \
+ \
+ typedef name<Lhs, Rhs> OP; \
+ typedef typename \
+ mpl::if_c<is_same<typename decay<Lhs>::type, \
+ typename decay<Rhs>::type>::value, \
+ typename cctraits<OP>::is_specialized, \
+ mpl::false_>::type is_specialized; \
+ \
+ typedef name<typename Lhs::value_type, \
+ typename Rhs::value_type> elem_op; \
+ \
+ static assertion_result \
+ eval( Lhs const& lhs, Rhs const& rhs) \
+ { \
+ return assertion::op::compare_collections( lhs, rhs, \
+ (boost::type<elem_op>*)0, \
+ is_specialized() ); \
+ } \
+ \
+ template<typename PrevExprType> \
+ static void \
+ report( std::ostream&, \
+ PrevExprType const&, \
+ Rhs const& ) {} \
+}; \
+/**/
+
+BOOST_TEST_FOR_EACH_COMP_OP( DEFINE_COLLECTION_COMPARISON )
+#undef DEFINE_COLLECTION_COMPARISON
+
+//____________________________________________________________________________//
+
+} // namespace op
+} // namespace assertion
+} // namespace test_tools
+} // namespace boost
+
+#include <boost/test/detail/enable_warnings.hpp>
+
+#endif // BOOST_TEST_TOOLS_COLLECTION_COMPARISON_OP_HPP_050815GER
+