Guillaume Racicot
Guillaume Racicot

Reputation: 41840

Unit testing highly templated library

I was wondering if something as unit testing template was a thing. Let me explain my needs.

I have a highly templated library. I have a lot of sfinae type traits, and some static_assert.

What I want to test is the validity of sfinae type traits, and test if my static_assert are throwing the right thing. Knowing what is my coverage would be awesome.

Here's an example of what my code look like:

template<typename T>
using false_v = !std::is_same<T, T>::value;

// Here are my types traits
template<typename T, typename... Args>
struct SomeCondition1 { /* ... */ };

template<typename T, typename... Args>
struct SomeCondition2 { /* ... */ };

// This is a master type trait, that test every others
template<typename T, typename... Args>
using Conditions = std::integral_constant<bool,
    SomeCondition1<T, Args...>::value && SomeCondition2<T, Args...>::value
>;

// This is the function that is call when everything is okay.
template<typename T, typename... Args,
    std::enable_if_t<Conditions<T, Args...>::value, int> = 0>
void doThing(Args...) {}

// These function are called only to trigger
// static asserts to give the user a diagnostic to explain what's wrong.
template<typename T, typename... Args,
    std::enable_if_t<SomeCondition1<T, Args...>::value && !SomeCondition2<T, Args...>::value, int> = 0>
void doThing(Args...) {
    static_assert(false_v<T>, "Error, SomeCondition2 not met");
}

template<typename T, typename... Args,
    std::enable_if_t<!SomeCondition1<T, Args...>::value && SomeCondition2<T, Args...>::value, int> = 0>
void doThing(Args...) {
    static_assert(false_v<T>, "Error, SomeCondition1 not met");
}

template<typename T, typename... Args,
    std::enable_if_t<!SomeCondition1<T, Args...>::value && !SomeCondition2<T, Args...>::value, int> = 0>
void doThing(Args...) {
    static_assert(false_v<T>, "Error, both conditions not met");
}

I was thinking about testing if the traits were ok, and if the right static assert is thrown for my cases. If the wrong static assert is triggered, that's a bug, and I would like to be able to test it. Trying to cover all cases for all compilers and check every message by hand is really time consuming and error prone.

Upvotes: 2

Views: 377

Answers (1)

Mike Kinghan
Mike Kinghan

Reputation: 61610

The problem of unit-testing template code for ranges of argument types is fairly well addressed by googletest with its TYPED TESTS feature and Type-Parameterized Tests feature.

A limitation of these features is that they are only immediately applicable to testing templates with just one parameter. But it's not difficult to work around this limitation: see this question and the accepted answer.

None of that helps, however, with the further problem of testing the correctness static_asserts in template code. The special obstacle for that kind of testing, of course, is that a static_assert fires by compilation failure; so if it fires, correctly or otherwise, there is nothing you can execute to show that it does.

This bothered me too several years ago. I posted How to write runnable tests of static_assert? and also wrote the only answer so far received (lately updated for C++14 and current compilers).

Combining these resources and techniques should yield the solution you're looking for.

Upvotes: 5

Related Questions