namezero namezero - 1 month ago 6
C++ Question

BOOST_CHECK_EQUAL (and dervatives) Add custom message

We recently started using the Boost Test framework, and like it so far.
However, there are certain tests where it would be great if we could add custom messages to an existing helper.

For example, I can get the output in mytest and mytest2, but have found no way to get the output in mytest3:

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


BOOST_AUTO_TEST_SUITE(myunit)

BOOST_AUTO_TEST_CASE(mytest)
{
// This give a nice output [2+2 != 5]
BOOST_CHECK_EQUAL(2+2, 5);
}

BOOST_AUTO_TEST_CASE(mytest2)
{
// This give only a custom output
BOOST_CHECK_MESSAGE(2+2 == 5, "comparison error");
}

BOOST_AUTO_TEST_CASE(mytest3)
{
// Ideally, it should output [2+2 != 5] comparison error
BOOST_CHECK_EQUAL_WITH_ADDITIONAL_MESSAGE(2+2, 5, "comparison error");
}

BOOST_AUTO_TEST_SUITE_END()


The reason I want this is because if I wish to have test cases like this:

BOOST_AUTO_TEST_CASE(mytest4)
{
for(int i = 0; i < 10; ++i)
{
BOOST_CHECK_EQUAL_WITH_ADDITIONAL_MESSAGE(i%3, 0, i);
}
}


In that case, there is no way to know for which i the test failed.

I have tried to "duplicate" the BOOST_CHECK_EQUAL macro as follows in hopes boost would append to the passed message as the original macro passes an empty literal:

#define BOOST_CHECK_EQUAL2( L, R ) \
BOOST_CHECK_WITH_ARGS_IMPL( ::boost::test_tools::tt_detail::equal_impl_frwd(), "hello world", CHECK, CHECK_EQUAL, (L)(R) )


However, "hello world: is overwritten somewhere in the test implementation with the failed condition.

Is there any (easy and clean) way to solve this?

UPDATE It appears as though the check_impl() implementation in test_tools.ipp doesn't utilize the check_descr parameter for the equality checks.

Is there an elegant way to override/provide my own?

Answer

Ok, I would just like to post for reference in case someone else runs into this that I solved it like this:

//____________________________________________________________________________//

#define BOOST_TEST_REL_EQ_MESSAGE_EXTENSION(L, R, M, CMP, ICMP, CT)         \
    {                                                                       \
        auto _1(L);                                                         \
        auto _2(R);                                                         \
        std::stringstream ss;                                               \
        ss << "check " << BOOST_TEST_STRINGIZE(L) << " " << BOOST_TEST_STRINGIZE(CMP) << " " << BOOST_TEST_STRINGIZE(R) << " failed [" << _1 << " " << BOOST_TEST_STRINGIZE(ICMP) << " " << _2 << "] : " << M;\
        BOOST_CHECK_IMPL( (_1 CMP _2), ss.str(), CT, CHECK_MSG );           \
    }                                                                       \
/**/

#define BOOST_CHECK_EQUAL_MESSAGE(L, R, M)      BOOST_TEST_REL_EQ_MESSAGE_EXTENSION(L, R, M, ==, !=, CHECK )
#define BOOST_WARN_EQUAL_MESSAGE(L, R, M)       BOOST_TEST_REL_EQ_MESSAGE_EXTENSION(L, R, M, ==, !=, WARN )
#define BOOST_REQUIRE_EQUAL_MESSAGE(L, R, M)    BOOST_TEST_REL_EQ_MESSAGE_EXTENSION(L, R, M, ==, !=, REQUIRE )

While this may not be optimal (mostly due to stringstream being used on every iteration in mytest4 above), it seems as through this provides a reasonably clean and non-intrusive solution for the few cases where the extra message might be required

Comments