Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use BOOST_PARAM_TEST_CASE with automatic registration on boost::test?

Is it possible to mix up the BOOST_AUTO_TEST_CASE and BOOST_AUTO_TEST_CASE_TEMPLATE macros with the BOOST_PARAM_TEST_CASE in any way? I'm even interested in really messy ways of making this happen.

Having to build all of your test cases by hand seems really tedious. But the BOOST_PARAM_TEST_CASE mechanism is pretty darn useful, but only works if you have a test init function, which in turn requires you to have be using manual test case construction.

Is there any documentation on how to hook into the automated system yourself so you can provide your own tests that auto-register themselves?

I'm using boost 1.46 right now.

like image 434
Omnifarious Avatar asked Nov 10 '11 17:11

Omnifarious


4 Answers

Since Boost 1.59 internal details of realization was changed and Omnifarious's solution doesn't compile.

Reason ot that is changing signature of boost::unit_test::make_test_case function: now it take 2 additional args: __FILE__, __LINE__

Fixed solution:

#if BOOST_VERSION > 105800
#define MY_BOOST_TEST_ADD_ARGS __FILE__, __LINE__,
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR ,boost::unit_test::decorator::collector::instance()
#else
#define MY_BOOST_TEST_ADD_ARGS
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR
#endif

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend )     \
struct test_name : public F {                                           \
   typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
   void test_method(const param_t &);                                   \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       MY_BOOST_TEST_ADD_ARGS                                           \
       (mbegin), (mend))                                                \
       MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR);                            \
                                                                        \
void test_name::test_method(const param_t &param)                       \




#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  mbegin, mend)
like image 108
And-y Avatar answered Oct 21 '22 23:10

And-y


Starting with Boost version 1.59, this is being handled by data-driven test cases:

#define BOOST_TEST_MODULE MainTest

#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/array.hpp>

static const boost::array< int, 4 > DATA{ 1, 3, 4, 5 };

BOOST_DATA_TEST_CASE( Foo, DATA )
{
    BOOST_TEST( sample % 2 );
}

This functionality requires C++11 support from compiler and library, and does not work inside a BOOST_AUTO_TEST_SUITE.

If you have to support both old and new versions of Boost in your source, and / or pre-C++11 compilers, check out And-y's answer.

like image 39
DevSolar Avatar answered Oct 21 '22 22:10

DevSolar


I wrote my own support for this since there really didn't seem to be any good support. This requires the C++11 decltype feature and the ::std::remove_const and ::std::remove_reference library methods to work.

The macro definitions are a modified versions of the BOOST_FIXTURE_TEST_CASE and BOOST_AUTO_TEST_CASE macros.

You use this by declaring your function thus:

BOOST_AUTO_PARAM_TEST_CASE(name, begin, end)
{
    BOOST_CHECK_LT(param, 5);  // The function will have an argument named 'param'.
}

Here is the header that defines the BOOST_AUTO_PARAM_TEST_CASE macro:

#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#include <type_traits>

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend )     \
struct test_name : public F {                                           \
   typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
   void test_method(const param_t &);                                   \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       (mbegin), (mend)));                                              \
                                                                        \
void test_name::test_method(const param_t &param)                       \

// *******

#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  mbegin, mend)
like image 33
Omnifarious Avatar answered Oct 21 '22 22:10

Omnifarious


The solution provided by @Omnifarious works works, but requires a C++11 compiler.

Adapting that solution for a C++03 compiler:

#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, P, mbegin, mend )  \
struct test_name : public F                                             \
{                                                                       \
    typedef P param_t;                                                  \
    void test_method(const param_t &);                                  \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       (mbegin), (mend)));                                              \
                                                                        \
void test_name::test_method(const param_t &param)                       \

// *******

#define BOOST_AUTO_PARAM_TEST_CASE( test_name, param_type, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  param_type,                           \
                                  mbegin, mend)

This solution is slightly different is usage. Since there is no declspec in C++03, the type of the parameter object cannot be automatically deduced. We must pass it in as a parameter to BOOST_AUTO_PARAM_TEST_CASE:

class FooTestParam                           
{    
public:                        
    std::string mS;    

    FooTestParam (int n)    
    {            
        std::stringstream ss;    
        ss << n;         
        mS = ss.str();                            
    }    
};         

FooTestParam fooParams [] =    
{         
    FooTestParam (42),    
    FooTestParam (314)    
};           

BOOST_AUTO_PARAM_TEST_CASE (TestFoo, FooTestParam, fooParams, fooParams + 2)        
{                                                                                   
    const std::string testVal = param.mS;                                           
}                                                                                   

BOOST_AUTO_TEST_CASE (TestAddressField)                                             
{                                                                                   
    const uint32_t raw = 0x0100007f;    // 127.0.0.1                                
    const uint8_t expected[4] = {127, 0, 0, 1};                                     
    const Mdi::AddressField& field = *reinterpret_cast <const Mdi::AddressField*> (&raw);    
    for (size_t i = 0; i < 4; ++i)                                                  
        BOOST_CHECK_EQUAL (field[i], expected[i]);                                  
}                                                                                   
like image 40
John Dibling Avatar answered Oct 22 '22 00:10

John Dibling