If the following 3 template functions:
template <typename T, size_t SIZE>
size_t foo1(array<T, SIZE>& a, size_t start){}
template <typename T, size_t SIZE>
size_t foo2(array<T, SIZE>& a, size_t start){}
template <typename T, size_t SIZE>
size_t foo3(array<T, SIZE>& a, size_t start){}
All three do the same things with the array a but with different implementations.
Now I like to set up a google test for all three functions but without C'n'P all the tests itself. I read about "Value-Parameterized Tests" but I can't define a pointer on the template functions itself.
Test may look like:
TEST(Foo1, t1) {
std::array<int, 2> arr = {3,1};
EXPECT_EQ(1, arr[foo1(arr, 0)]);
}
TEST(Foo2, t1) {
std::array<int, 2> arr = {3,1};
EXPECT_EQ(1, arr[foo2(arr, 0)]);
}
TEST(Foo3, t1) {
std::array<int, 2> arr = {3,1};
EXPECT_EQ(1, arr[foo3(arr, 0)]);
}
(How) is it possible to set up a test case and reuse its tests for all three template functions without wrapping the tests in self-defined functions (with gTest only) ?
I only like to define a test once and "pass" the used function as some kind of test argument to the test.
Thanks in advance :-)
EDIT 1:
After long trying I got this running:
template<typename T, size_t SIZE>
using fooFp = size_t (*)(std::array<T, SIZE>&, size_t);
template <typename T, size_t SIZE>
class fooTemplateClass: public ::testing::TestWithParam<fooFp<T, SIZE>> {};
class Tc1 : public fooTemplateClass<int, 1>{};
TEST_P(Tc1 , Fnc) {
fooFp<int, 1> fnc = GetParam();
std::array<int, 1> arr = {1};
EXPECT_EQ(1, arr[fnc(arr, 0)]);
}
INSTANTIATE_TEST_CASE_P(Name, Tc1, ::testing::Values(foo1<int, 1>, foo2<int, 1>, foo3<int, 1>), );
But still, this is unhandy because I need to define a class (int this case Tc1) for every template combination. I also don't like that I need to define all template settings within the INSTANTIATE_TEST_CASE_P.
Is there a way to generalize this so that I only need to write something like this:
TEST_P(fooTemplateClass<int, 1>, Fnc) {
std::array<int, 1> arr = {1};
fooFp<int, 1> fnc = GetParam();
EXPECT_EQ(1, arr[fnc(arr, 0)]);
}
INSTANTIATE_TEST_CASE_P(Name, fooTemplateClass, ::testing::Values(foo1, foo2, foo3), );
I know all template types and sizes at compile time so I can pass them. But at the moment I don't found out how to pass a template class to a TEST_P macro ...
Don't have gtest at hand right now to test it, but I think you could use a single test fixture which derives from ::testing::TestWithParam<std::function<size_t(std::array<T, SIZE>, size_t)>>. This enables you to write tests using the TEST_P macro that can call GetParam() to get an instance of type std::function<size_t(std::array<T, SIZE>, size_t)>. You could then use this function object to call your method.
Your test fixture, however, would still be a template class due to your T and SIZE template arguments. The first problem with this is, that you can't have a , in a macro parameter if it is not surrounded by parenthesis. This could be circumvented by writing your own macro that defines a typedef and exploiting variadic macros. However, you would need to uniquely identify each typedef based on the template arguments to later pass it to INSTANTIATE_TEST_CASE_P. This, however would need some advanced template tricks I am not capable of.
The following code gives you a macro TEST_T which can be used as shown
#define CONCAT(a, b) CONCAT_(a,b)
#define CONCAT_(a,b) a ## b
#define ARG(arg1, ...) arg1
#define ARG1(arg, ...) CONCAT(arg, ARG( __VA_ARGS__ ))
#define ARG2(arg, ...) CONCAT(arg, ARG1( __VA_ARGS__ ))
#define ARG3(arg, ...) CONCAT(arg, ARG2( __VA_ARGS__ ))
#define TEST_T(test_case_name, test_name, ...) \
using CONCAT(test_case_name, ARG2( __VA_ARGS__ )) = test_case_name < __VA_ARGS__ >; \
TEST_P(CONCAT(test_case_name, ARG2( __VA_ARGS__ )), test_name)
TEST_T(fooTemplateClass, Fnc, int, 1) {
fooFp<int, 1> fnc = GetParam();
std::array<int, 1> arr = {1};
EXPECT_EQ(1, arr[fnc(arr, 0)]);
}
You would still have to instantiate it with
INSTANTIATE_TEST_CASE_P(Name, fooTemplateClassint1, ::testing::Values(foo1<int, 1>, foo2<int, 1>, foo3<int, 1>));
I could not solve this remaining problem, but maybe it helps you to find a solution that fits your needs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With