Home > OS >  Trying to match on a c-style array in gmock is failing at compile time
Trying to match on a c-style array in gmock is failing at compile time

Time:06-13

Background:

I'm mocking a hardware i2c transmit function, and trying to match on an array passed into it. This is in an embedded context, hence the c-style arrays and lack of STL containers.

Trying to match my second parameter, a c-style array (the buffer below), is failing at compile time.

Setup:

The interface defined as:

virtual I2C_Status_e i2c1Transmit(uint8_t address, 
                                  const uint8_t buffer[], 
                                  uint8_t length) = 0;

And I'm setting up my test mock as:

MOCK_METHOD(I2C_Status_e,
            i2c1Transmit,
            (uint8_t address, const uint8_t buffer[], uint8_t length),
            (override));

Call point in the binary (this transmit sends a single 8-bit command):

status = hal->i2c1Transmit(address, readStatusCommand, 1);

Where readStatusCommand is def as:

const uint8_t readStatusCommand[1] = {0x00};

Test Code:

Here readStatusCommand has an identical signature to the one above.

EXPECT_CALL(hal, i2c1Transmit(address0, ElementsAreArray(readStatusCommand, 1), txLength))
    .WillOnce(Return(HAL_Ok));

Compiler Output:

/home/.../vendor/gtest/googletest-release-1.10.x/googlemock/include/gmock/gmock-matchers.h: In instantiation of ‘class testing::internal::ElementsAreMatcherImpl<const unsigned char* const&>’:
/home/.../vendor/gtest/googletest-release-1.10.x/googlemock/include/gmock/gmock-matchers.h:3518:31:   required from ‘testing::internal::ElementsAreArrayMatcher<T>::operator testing::Matcher<T>() const [with Container = const unsigned char*; T = unsigned char]’
/home/.../..._tests.cpp:88:5:   required from here 
    ^^^* Note: Expect Call above is line 88 here. *^^^
/home/.../vendor/gtest/googletest-release-1.10.x/googlemock/include/gmock/gmock-matchers.h:3084:45: error: ‘testing::internal::ElementsAreMatcherImpl<const unsigned char* const&>::StlContainer’ {aka ‘const unsigned char*’} is not a class, struct, or union type
 3084 |   typedef typename StlContainer::value_type Element;
      |                                             ^~~~~~~
/home/.../vendor/gtest/googletest-release-1.10.x/googlemock/include/gmock/gmock-matchers.h:3218:43: error: ‘testing::internal::StlContainerView<const unsigned char*>::type’ {aka ‘const unsigned char*’} is not a class, struct, or union type
 3218 |   ::std::vector<Matcher<const Element&> > matchers_;
      |                                           ^~~~~~~~~

Expected behavior/What I tried:

According to the matcher documentation here, it should work? ElementsAreArray is defined as working on c-style arrays if a length is passed in. I tried ElementsAre to the same effect.

It's also definitely the matcher, switching the matcher for ::_ allows it to compile fine.

CodePudding user response:

No, it should not work - the matcher documentation refers to the case where the argument being matched is an STL container, whereas const uint8_t buffer[] is a pointer.

The ElementsAreArray(readStatusCommand, 1) is a matcher for a container of length 1. However the second argument that it is being compared with doesn't have an associated length.

This will work, see ii. in These matchers can also match notes, that refers to Multi-argument Matchers.

EXPECT_CALL(hal, i2c1Transmit(address0, _, _))
    .With(Args<1, 2>(ElementsAreArray(readStatusCommand)))
    .WillOnce(Return(HAL_Ok));

ElementsAreArray(readStatusCommand) does not require setting the explicit array length, since readStatusCommand has type const uint8_t[1] that has an associated length.

  • Related