Reputation: 736
On Debian I try to mock system function bind to bind an interface address to a socket. To set an ip address I think I have to use side effects on a parameter of bind. I use this code:
extern "C" {
int mysocket();
}
// --- mock bind -------------------------------------------
class BindInterface {
public:
virtual ~BindInterface() {}
virtual int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) = 0;
};
class BindMock : public BindInterface {
public:
virtual ~BindMock() {}
MOCK_METHOD(int, bind, (int, const struct sockaddr*, socklen_t), (override));
};
BindInterface* ptrBindMockObj = nullptr;
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen) {
return ptrBindMockObj->bind(sockfd, addr, addrlen);
}
TEST(MockTestSuite, bind_address_to_a_socket)
{
using ::testing::_;
using ::testing::Return;
using ::testing::DoAll;
using ::testing::SetArgPointee;
using ::testing::SetArgReferee;
struct sockaddr_in my_addr = {0};
BindMock bindMockObj;
ptrBindMockObj = &bindMockObj;
my_addr.sin_family = AF_INET;
EXPECT_EQ(inet_pton(AF_INET, "192.168.55.66", &my_addr.sin_addr.s_addr), 1);
EXPECT_CALL(bindMockObj, bind(_, _, _))
.WillOnce(DoAll(SetArgPointee<1>((struct sockaddr*)my_addr),
SetArgReferee<2>(sizeof(my_addr)),
Return(0)));
EXPECT_EQ(mysocket(), EXIT_SUCCESS);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
It doesn't work because the compiler complains invalid cast as follows:
test_mylib.cpp: In member function ‘virtual void MockTestSuite_bind_address_to_a_socket_Test::TestBody()’:
test_mylib.cpp:52:42: error: invalid cast from type ‘sockaddr_in’ to type ‘sockaddr*’
52 | .WillOnce(DoAll(SetArgPointee<1>((struct sockaddr*)my_addr),
| ^~~~~~~~~~~~~~~~~~~~~~~~~
Seems I do not really understand what SaveArgPointee<N>(pointer)
is doing. What I'm doing wrong with types and cast?
UPDATE:
With the suggestion from the answer of @Quarra to define the ACTION_P outside the TEST body I get two error messages within a bunch of stacked calls:
googlemock/include/gmock/gmock-actions.h:1116:56: error: static assertion failed: Argument must be a reference type.
1116 | static_assert(std::is_lvalue_reference<argk_type>::value,
| ^~~~~^
--- snip ---
test_mylib.cpp:33:54: error: no match for ‘operator=’ (operand types are ‘sockaddr’ and ‘const sockaddr_in’)
33 | ACTION_P(AssignSockAddr, param) { *(sockaddr*)(arg0) = param; }
| ~~~~~~~~~~~~~~~~~~~^~~~~~~
In file included from /usr/include/x86_64-linux-gnu/sys/socket.h:33,
from /usr/include/netinet/in.h:23,
from test_mylib.cpp:7:
Upvotes: 1
Views: 722
Reputation: 2695
I agree that it's strange that your example doesn't compile: it's trying to change the pointer to const socaddr
, not const pointer...
You can define your own action and use it like that:
ACTION_P(AssignSockAddr, param) { *(sockaddr*)(arg0) = param; }
TEST(MockTestSuite, bind_address_to_a_socket) {
// [ rest of the test code here ]
EXPECT_CALL(bindMockObj, bind(_, _, _)).WillOnce(
DoAll(WithArg<1>(AssignSockAddr(my_addr)),
SetArgReferee<2>(sizeof(my_addr)),
Return(0)));
EXPECT_EQ(mysocket(), EXIT_SUCCESS);
}
Upvotes: 1