Search code examples
c++unit-testinggoogletestgooglemock

c++ googlemock: How can you verify all the elements of an array pointer passed to a mocked function?


I am passing a pointer to an array to a function, which I am mocking with googlemock. I would like to verify the contents of the arguments, which works fine for scalars, but I am not able to fetch the elements of the array:

#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
class InterfaceTest : public ::testing::Test {};
class MockFortranFuncInterfacePointerArgs {
public:
  MOCK_METHOD(void, fortran_interface_test_func_pointerargs, (int*, int*));
};

void testfunc_pointer(MockFortranFuncInterfacePointerArgs* func_interface) {
  int testscalar = 123;
  int testarray[3] = {1, 2, 3};
  func_interface->fortran_interface_test_func_pointerargs(&testscalar, &testarray[0]);
}

TEST_F(InterfaceTest, TestFuncInterfacePointerArgs) {
  MockFortranFuncInterfacePointerArgs mock_func_interface;
  int passed_scalar = 0;
  int passed_array[3] = {0, 0, 0};
  // int passed_array = 0;
  EXPECT_CALL(mock_func_interface, fortran_interface_test_func_pointerargs(testing::_, testing::_))
    .WillOnce(testing::DoAll(
        testing::SaveArgPointee<0>(&passed_scalar),
        testing::SetArrayArgument<1>(passed_array, passed_array + 3)
    ));
  testfunc_pointer(&mock_func_interface);
  std::cout << passed_scalar << std::endl; // prints 123
  std::cout << passed_array[0] << " " << passed_array[1] << " " << passed_array[2] << std::endl; // prints 0 0 0
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

How can I modify this test so I am able to verify all three elements of the array that was passed to fortran_interface_test_func_pointerargs? I can't just compare them directly because I need to store the array that was passed in testfunc_pointer first, which is not possible with the current implementation using SetArrayArgument


Solution

  • Ok I can't find anything in google toolbox which could address this issue.

    But this can be solved by providing own matcher:

    MATCHER_P2(ArrayPointee, size, subMatcher, "")
    {
        return ExplainMatchResult(subMatcher, std::make_tuple(arg, size), result_listener);
    }
    

    This matcher allows convert pointer argument to tuple of pointer and size which other matchers are treating like std::span (available since C++20).

    So test can be tweaked this way (modification of my MCVE from comment):

    #include <gmock/gmock.h>
    #include <gtest/gtest.h>
    
    using ::testing::ElementsAre;
    
    MATCHER_P2(ArrayPointee, size, subMatcher, "")
    {
        return ExplainMatchResult(subMatcher, std::make_tuple(arg, size), result_listener);
    }
    
    class IFoo {
    public:
        virtual void foo(int*) = 0;
    };
    
    class MockFoo : public IFoo {
    public:
        MOCK_METHOD(void, foo, (int*), ());
    };
    
    void UseFoo(IFoo& foo)
    {
        int arr[] { 3, 5, 7 };
        foo.foo(arr);
    }
    
    TEST(TestFoo, fooIsCalledWithProperArray)
    {
        MockFoo mock;
        EXPECT_CALL(mock, foo(ArrayPointee(3, ElementsAre(3, 5, 7))));
        UseFoo(mock);
    }