vendredi 26 février 2016

print a std::vector of std::tuple with BOOST_CHECK_EQUAL_COLLECTION in Boost.Test

Hello I'm trying to use Boost.Test for my unit tests. However some of my functions return a collection of tuples, in a std::vector< std::tuple< TypeA, TypeB > >.

To work with BOOST_CHECK_EQUALS and BOOST_CHECK_EQUAL_COLLECTION, I specialized boost::test_tools::print_log_value to print nice tuples and vectors as the answer to this question explains. I also provide operator<< for tuples, so that my vector can use that while printing the whole vector. For cleanness this operator lies in the blank namespace.

However the compilation fails, as the implementation of boost::test_tools::print_log_value <std::vector<std::tuple<...>>> cannot find the operator<< for tuples.

Here is a minimal code which is, sorry, already quite verbose.

#define BOOST_TEST_MODULE my_test
#include <boost/test/included/unit_test.hpp>

#include <tuple>
#include <vector>

/////////////////
// std::vector //
/////////////////

// boost printing method
namespace boost {
namespace test_tools {
template< typename Type >
struct print_log_value< std::vector< Type > > {
    void operator()( std::ostream& s, const std::vector< Type > &collection ) {
        const int size = collection.size();

        if( size == 0 ) {
            s << "[]";
        }
        else {
            s << "[ ";
            for( int i =0; i <= size-2; ++i ) {
                s << collection[i] << ", ";
            }
            s << collection[size-1] << " ]";
        }
        return s;
    }
};
} //namespace test_tools
} //namespace boost

////////////////
// std::tuple //
////////////////

// recursive calls for printing
namespace tuple_print_aux{

    template< int I, int J, typename... Types >
    struct recursive_printer {
        static void print( std::ostream& s, const std::tuple<Types...> &collection ) {
            s << std::get< I >( collection ) << ", ";
            recursive_printer< I+1, J-1, Types... >::print( s, collection );
        }
    };

    template< int I, typename... Types >
    struct recursive_printer< I, 1, Types... > {
        static void print( std::ostream& s, const std::tuple<Types...> &collection ) {
            s << std::get< I >( collection );
        }
    };

    template< typename... Types >
    void recursive_print( std::ostream& s, const std::tuple<Types...> &collection ) {
        recursive_printer< 0, sizeof...(Types), Types... >::print( s, collection );
    }
}

// output stream operator
template< typename... Types >
std::ostream& operator<<( std::ostream& s, const std::tuple<Types...> &collection ) {
    s << "( ";
    tuple_print_aux::recursive_print< Types... >( s, collection );
    s << " )";
    return s;
}

// boost printing method
namespace boost {
namespace test_tools {
template< typename... Types >
struct print_log_value< std::tuple< Types... > > {
    void operator()( std::ostream& s, const std::tuple<Types...> &collection ) {
        s << "( ";
        tuple_print_aux::recursive_print< Types... >( s, collection );
        s << " )";
    }
};
} //namespace test_tools
} //namespace boost

BOOST_AUTO_TEST_CASE(my_test_case) {
    //builds successfully
    BOOST_CHECK_EQUAL( std::make_tuple(1,"a"), std::make_tuple(1,"a") );

    //builds successfully
    std::vector< int > v( 2, 3 ), w( 2, 7 );
    BOOST_CHECK_EQUAL_COLLECTIONS( v.begin(), v.end(), w.begin(), w.end() );

    //fails to build
    std::vector< std::tuple<int,int> > a( 1, std::make_tuple(1,3) ), b( 1, std::make_tuple(2,2) );
    BOOST_CHECK_EQUAL_COLLECTIONS( a.begin(), a.end(), b.begin(), b.end() );
};

Of course, putting the operator<< for std::tuples into the std namespace solve the problem, but this is a non-standard non-elegant solution. So... how should I approach the problem. ?

Thank you for any help.

Aucun commentaire:

Enregistrer un commentaire