test icon indicating copy to clipboard operation
test copied to clipboard

Feature request: helper macro to unpack tuples of test types

Open DarkerStar opened this issue 5 years ago • 0 comments

The template test API lets me do this:

using test_types = std::tuple<int, char, std::string>;

BOOST_AUTO_TEST_CASE_TEMPLATE(test_1, T, test_types)
{
    // tests for `T`
}

// 3 tests generated

This is great. I love this.

But sometimes I need to do tests on sets of types rather than on a single type.

I can handle that situation like this:

using test_types = std::tuple<
	std::tuple<int, char>,
	std::tuple<float, double>,
	std::tuple<std::vector<char>, std::string>
>;

BOOST_AUTO_TEST_CASE_TEMPLATE(test_1, Ts, test_types)
{
    using T = std::tuple_element_t<0, Ts>;
    using U = std::tuple_element_t<1, Ts>;

    // tests for `T`, `U`
}

// 3 tests generated

And this works fine, too. Nothing wrong with any of this.

But when there’s a test failure, discerning the types that triggered the failure from the test output can be, to put it mildly, unmild.

So what I’d like to propose is a new preprocessor macro. Let’s call it BOOST_TEST_EXPAND_TYPES(type_list, T...) (bike-shedding TBD).

What it would do is two-fold:

  • It would alias each type in the given type list to the identifier given in the variadic list, in order.
  • It would effectively add a BOOST_TEST_INFO_SCOPE() that records the alias in the test context.

For example:

using test_types = std::tuple<
	std::tuple<int, float>
>;

BOOST_AUTO_TEST_CASE_TEMPLATE(test_1, Ts, test_types)
{
    BOOST_TEST_EXPAND_TYPES(Ts, T, U)

    // The above *BASICALLY* expands to:
    //     using T = std::tuple_element_t<0, Ts>;
    //     BOOST_TEST_INFO_SCOPE("using T = " << __name_of_type(T));
    //     using U = std::tuple_element_t<1, Ts>;
    //     BOOST_TEST_INFO_SCOPE("using U = " << __name_of_type(U));

    // `T` is now `int`
    // `U` is now `float`

    BOOST_TEST(sizeof(T) != sizeof(U));
}

Note that if std::tuple_size_v<Ts> is less than the number of identifiers provided, or if Ts doesn’t support the tuple-like (it really just needs to support std::tuple_element<N, Ts> and/or the Boost.MP11, Hana, whatever, equivalents), then that should be a compile error.

And when the test fails, the output would be something like:

test.cpp(??): error: in "test_1<std__tuple<int_ float>>": check sizeof(T) != sizeof(U) has failed [4 == 4]
Failure occurred in a following context:
    using T = int
    using U = float

For the above example, it’s not hard to spot the int and the float in the first line, but even then it’s still not clear what T and U are in the actual test. The context provided is enormously helpful.

Implementing BOOST_TEST_EXPAND_TYPES() shouldn’t be too hard, but it’s not something the user can do because (so far as I can tell), while Boost.Test has some __name_of_type(???) function internally, it isn’t exposed to the user, and implementing it is far from trivial. (As an aside, perhaps Boost.Test should expose a way to pretty-print types!)

In summary:

BOOST_TEST_EXPAND_TYPES(Types, T1, ...)

Expands *as-if* to:

using T1 = std::tuple_element_t<0, Types>;
BOOST_TEST_INFO_SCOPE("using T1 = " << __name_of_type(T1));
// ... above repeated, replacing T1 with each subsequent identifier

Where:
- __name_of_type(T): pretty-prints the type T

DarkerStar avatar Nov 01 '20 09:11 DarkerStar