2

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.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141

1 Answers1

5

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.

sh1
  • 4,324
  • 17
  • 30
Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182