Hello,

We are in the process of creating unit tests for our in-house application development and have selected Boot.Test as a library.  I’ve been toying with the library for a while now and there is one feature that I feel is missing.  It is the capacity to check a whole collection for close values, i.e. the “close” equivalent of BOOST_*_EQUAL_COLLECTIONS.

From what I can tell, this has already been discussed (old threads from 2007 http://boost.2283326.n4.nabble.com/Boost-Test-request-BOOST-CLOSE-COLLECTIONS-td2619820.html) and did not end-up in the library (at least from what I can tell from my version of boost (1.57).  Other more recent threads (2012, http://boost.2283326.n4.nabble.com/test-BOOST-TEST-universal-testing-tool-td4638062.html) seem to suggest that the library is undergoing under the hood changes (I might be wrong here).  So this request might  be completely inappropriate, given the timing.

Nevertheless, I have come up with an implementation for those macros.  I wanted to share them here on the list (code at the end of the mail).  It might be useful for some people.  If Gennadiy (library maintainer) reads this mail and finds the macros adequate for use, great.  If not, too bad.

Anyhow, thanks.
Ghyslain




namespace boost_hlp
{
template <typename Left, typename Right>
inline ::boost::test_tools::predicate_result
close_coll_impl( Left lt_begin, Left lt_end, Right rt_begin, Right rt_end,
                 ::boost::test_tools::percent_tolerance_t<double> tolerance )
{
   ::boost::test_tools::predicate_result    res( true );
   ::std::size_t                            pos = 0;

   for( ; lt_begin != lt_end && rt_begin != rt_end; ++lt_begin, ++rt_begin, ++pos )
   {
      if( !(::boost::test_tools::check_is_close( *lt_begin, *rt_begin, tolerance )) )
      {
         res = false;
         res.message() << "\nMismatch in a position " << pos << ": "  << *lt_begin << " != " << *rt_begin;
      }
   }

   if( lt_begin != lt_end )
   {
      std::size_t r_size = pos;
      while( lt_begin != lt_end )
      {
         ++pos;
         ++lt_begin;
      }

      res = false;
      res.message() << "\nCollections size mismatch: " << pos << " != " << r_size;
   }

   if( rt_begin != rt_end )
   {
      std::size_t l_size = pos;
      while( rt_begin != rt_end )
      {
         ++pos;
         ++rt_begin;
      }

      res = false;
      res.message() << "\nCollections size mismatch: " << l_size << " != " << pos;
   }
   return res;
}

} // namespace boost_hlp


#define CLOSE_COLLECTIONS_IMPL( L_begin, L_end, R_begin, R_end, tolerance, TL )      \
    BOOST_TEST_TOOL_IMPL( \
         check_impl,\
         ::boost_hlp::close_coll_impl( (L_begin), (L_end), (R_begin), (R_end), \
         ::boost::test_tools::percent_tolerance_t<double>((tolerance) )), "", TL, CHECK_EQUAL_COLL ),   \
         5,                                                                          \
         BOOST_STRINGIZE( L_begin ), BOOST_STRINGIZE( L_end ),                       \
         BOOST_STRINGIZE( R_begin ), BOOST_STRINGIZE( R_end ),\
         BOOST_STRINGIZE( ::boost::test_tools::percent_tolerance_t<double>((tolerance) ) ) )   \
/**/


#define WARN_CLOSE_COLLECTIONS( L_begin, L_end, R_begin, R_end, tolerance )          \
   CLOSE_COLLECTIONS_IMPL( (L_begin), (L_end), (R_begin), (R_end), (tolerance), WARN )
#define CHECK_CLOSE_COLLECTIONS( L_begin, L_end, R_begin, R_end, tolerance )         \
   CLOSE_COLLECTIONS_IMPL( (L_begin), (L_end), (R_begin), (R_end), (tolerance), CHECK )
#define REQUIRE_CLOSE_COLLECTIONS( L_begin, L_end, R_begin, R_end, tolerance )       \
   CLOSE_COLLECTIONS_IMPL( (L_begin), (L_end), (R_begin), (R_end), (tolerance), REQUIRE )