Intro
Two weeks ago I started a new project and came along another idea for a project: a test runner for automating tests of template functions - which I'm currently working on. The main reason behind all that is that I want to
- learn more about (modern) C and
- implement some stuff from my uni lectures.
Said test runner should be able to test a template function, i.e.:
// Said template function (*)
template <class T>
T add(T a, T b) {
return a b;
}
Setup Explanation
In order to do so I created a class TestRunner (shown in the following) that gets a tuple of parameters via its constructor and has a friend (run(...)
) that executed the test.
template <class... PS>
class TestRunner {
public:
// constructors
explicit TestRunner(std::tuple<PS...> paramSetTuple) : paramSets_(paramSetTuple) {}
// ... other unimportant stuff ...
// friends
template <size_t idx, typename F, class... P>
friend constexpr void run(TestRunner<P...> testRunner, F&& testFunc, std::string_view testFuncName);
private:
std::tuple<PS...> paramSets_;
};
As seen here run(...)
gets the an instance of TestRunner, a rvalue reference to the function that shall be tested and some string for a better console output.
(just FYI, but not important to the problem itself: The reason for making this friend function is that I want to implement different tests and I don't want to just copy paste the basic functionality behind run(...)
as well as I want to created a macro that spares me of the run(...)
's last argument.)
Finally, the problem itself:
I want to be able to pass add(...)
to run(...)
without specifying add(...)
's template parameter, because this template parameter should be specified automatically when I use the add(...)
function in run(...)
, which looks like this:
template <size_t idx = 0, typename F, ParameterSetConcept... P>
constexpr void run(TestRunner<P...> testRunner, F&& testFunc, std::string_view testFuncName) {
// ... some stuff to iterate through the tuple ...
// ... some other stuff to get the input parameters for add(...) and it's expected output
// for now, let's just say the input is a tuple i.e. testInputs,
// and the expected output i.e. expectedOutput
auto output = std::apply(std::forward<F>(testFunc), testInputs;
if ( output == expectedOutput ) {
// this == is just an example for a successful test
// (more options will be implemented later)
run<idx 1>(testRunner, std::forward<F>(testFunc), testFuncName);
} else {
// ... some error output ...
}
}
It be said that the iteration through tuples, and fetching of the tuple testInputs
as well as the expected output expextedOutput
work just fine.
Now what I need is to be able to call run(...)
in the main (or a gtest) without specifying it's template parameter.
This may look something like this:
int main() {
TestRunner testRunner(...); // init testRunner as it's supposed to be
run(testRunner, add, "add");
return 0;
}
Is there even a solution to this problem? In advance: THANKS FOR ANY HELP!
Last Comments
I'm aware that the total setup of using such a 'complex' construct in a UnitTest as I mentioned before (gtest) might be a bad idea for the UnitTest concept itself, but I mainly do all this because I want to learn something about C and came along this problem. Please don't judge ^^ I know that there is a option for value parameterized tests and even type parameterized tests in the gtest framework.
CodePudding user response:
The closest thing I can think of is,
auto call_add = [](auto&&... args){ return add(std::forward<decltype(args)>(args)...); };
doSomethingWithAdd(call_add);
Of course, you can add a macro for it if it's too complicated.