Search code examples
c++googletestgooglemock

How can I match one element from a C++ tuple using gmock?


How can I match one element from a C++ tuple using gmock ?

For example let's try to extract the std::string from a std::tuple<std::string, int>.

I know I could write a custom matcher like this:

MATCHER_P(match0thOfTuple, expected, "") { return (std::get<0>(arg) == expected); }

But since I found the Pair(m1, m2) matcher for the std::pair, I expected also to find something similar for the std::tuple.

Gmock has Args<N1, N2, ..., Nk>(m) for selecting a subset of tuple arguments. When using it with just 1 argument, it still expects a tuple matcher. The following attempt does not seem to compile:

struct {
  MOCK_METHOD1(mockedFunction, void(std::tuple<std::string, int>&));
} mock;
EXPECT_CALL(mock, mockedFunction(testing::Args<0>(testing::Eq(expectedStringValue))));

And makes my clang give a compilation error like this:

.../gtest/googlemock/include/gmock/gmock-matchers.h:204:60: error: invalid operands to binary expression ('const std::__1::tuple<std::__1::basic_string<char> >' and 'const std::__1::basic_string<char>')
  bool operator()(const A& a, const B& b) const { return a == b; }
...

Is there a gmock solution for the std::tuple similar to the one for the std::pair, which uses the gmock Pair matcher?


Solution

  • On 2020-10-15 a matcher for tuples was added to googletest. This new matcher is called FieldsAre and it is now also mentioned in the matchers reference.

    It is used the same as Pair, the caveat here is that neither can extract a specific element as you had requested.

    auto const value = std::tuple{ std::string{ "foo" }, 42, 3.14 };
    EXPECT_THAT(value, FieldsAre("foo", 42, 3.14));
    
    // You can use any matcher as usual
    EXPECT_THAT(value, FieldsAre(SizeIs(3), Ge(41), Ne(2.71)));
    
    // To "extract" a field you could ignore the others with _
    EXPECT_THAT(value, FieldsAre("foo", _, _));