I have been test-driving some code that uses COM interfaces using gmock. Win32 functions
for working with COM return interface pointers via void **
arguments. When mocking
a call to, for example, QueryInterface
function that will return a pointer to IPersistFile
interface, I do the following
CPersistFileMock mockIPersistFile;
EXPECT_CALL(mockIShellLink, QueryInterface(_, _)).WillOnce(DoAll(
SetArg1ToIPersistFile(&mockIPersistFile), Return(S_OK)));
where SetArg1ToIPersistFile is a custom action defined like this:
ACTION_P(SetArg1ToIPersistFile, pIPersistFile) {
*reinterpret_cast<CPersistFileMock**>(arg1) = pIPersistFile;
}
This works, but the problem is that you have to write a new custom action for every combination
of argument index and the type that need to be returned via void **
argument. Is there a way
to generalize this custom action so it can be applied regardless of type and argument index (to
something like SetArgPointee<>
but also aware of types).
This question has been bothering our team, we knew that we could exploit the the fact that args
is a tuple by using std::get<>
on it but we did not know how to pass argument index and type in a generic way. Finally, a colleague of mine figured out how to make action template. This is the final implementation:
ACTION_TEMPLATE(SetArgVoidPtrPtr, HAS_2_TEMPLATE_PARAMS(typename, Type, unsigned, uIndex), AND_1_VALUE_PARAMS(value))
{
*reinterpret_cast<Type**>(std::get<uIndex>(args)) = value;
}
and how it's use in context of IFilePersist
example mentioned above:
EXPECT_CALL(mockIShellLink, QueryInterface(_, _)).WillOnce(DoAll(
SetArgVoidPtrPtr<CPersistFileMock, 1>(&mockIPersistFile), Return(S_OK)));
Note that this approach can be used in general case, with functions that return values via void **
arguments. Just wanted to put this out there, since I did not find much information about this. Hope this helps someone with a similar problem.