c++googletestgooglemock

Generic custom action to set value to void** argument using gmock


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).


Solution

  • 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.