Wiki

Clone wiki

test_o_matic / Variadic_macro_support

Variadic macro support

Since C and C++ preprocessor macros are unaware of C and C++ syntax, it is possible to confuse them. For example, consider the following test:

TEST("silly test")
{
    std::vector<int, my_allocator> v;
    THROWS(throw v, std::vector<int, my_allocator>);
}

Without variadic macro support, this test wouldn't compile. Note that since there are two commas (,) between the brackets in the THROWS statement, the preprocessor looks for a macro that takes 3 arguments, when in fact it should only look for a macro containing only 2.

Compiler support

test-o-matic attempts to detect whether C99-style variadic macros should be enabled by checking to see if your compiler is one of a number of that are known to support this language feature.

If test-o-matic fails to identify that your compiler supports variadic macros, you can forcibly enable them by defining TEST_O_MATIC_USE_VARIADIC_MACROS when compiling your tests.

On the other hand, if for some reason test-o-matic falsely identifies your compiler as one that supports variadic macros, then you can define TEST_O_MATIC_DONT_USE_VARIADIC_MACROS when compiling your tests.

If TEST_O_MATIC_USE_VARIADIC_MACROS and TEST_O_MATIC_DONT_USE_VARIADIC_MACROS are both defined, TEST_O_MATIC_DONT_USE_VARIADIC_MACROS will win and variadic macro support will be disabled.

Which test-o-matic macros are variadic?

The following macros supplied by test-o-matic have variadic versions available:

  • TESTFIX
  • CHECK
  • REQUIRE
  • TRY
  • THROWS

[†] THROWS and TESTFIX are each variadic in the second argument. This means that the following will fail to compile, even if variadic macro support is available:

TEST("silly test 2")
{
    THROWS(throw std::vector<int, my_allocator>(), std::vector<int, my_allocator>);
}

This is because the preprocessor will see the first argument as throw std::vector<int and the variadic part as my_allocator>(), std::vector<int, my_allocator>. The segmentation has occurred in the wrong place.

Working around preprocessor limitations

If your compiler doesn't support variadic macros, or if you encounter a situation such as the above where you need variadics in two arguments, there are some workarounds involving adding extra brackets or introducing typedefs that you can use when you have an expression that contains too many commas.

Here are some examples:

TEST("test 1")
{
    // CHECK(boost::is_same<T, U>::value);
    CHECK((boost::is_same<T, U>::value)); // note extra pair of brackets ()
}

TEST("test 2")
{
    // CHECK(boost::is_same<T, U>::value);
    typedef boost::is_same<T, U> T_U_same;
    CHECK(T_U_same::value); // no comma because of the typedef
}

Improving support

Please file a bug report in the Bug Tracker if the default behavior for your compiler is incorrect. If you can provide a means of detecting your specific compiler using pre-defined macros, that would also be incredibly helpful.

Updated