Saturday, July 30, 2022

[SOLVED] How to fill structure with a mocked function using GoogleMock?

Issue

I have a function for example:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

The man page tell me "The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket, as known to the communications layer." So I would call the function with:

    struct sockaddr_storage clientAddr;
    struct sockaddr* sa{(sockaddr*)&clientAddr};
    clientLen = sizeof(clientAddr);;

    accept_sock = accept(listen_sock, (struct sockaddr*)&clientAddr, &clientLen);

With mocking accept I would like to fill clientAddr with:

    struct sockaddr_in* sa_in{(sockaddr_in*)&clientAddr};
    sa_in->sin_family = AF_INET;
    sa_in->sin_port = htons(50000);
    inet_pton(AF_INET, "192.168.1.2", &sa_in->sin_addr);

To return a mocked pointer to a filled structure I would use:

    EXPECT_CALL(mocked_sys_socket, accept(listen_sock, _, Pointee(clientLen)))
        .WillOnce(DoAll(SetArgPointee<1>(*sa), Return(accept_sock)));

But that isn't what I need here. The clientAddr structure is already given.

What action instead of SetArgPointee<1>(*sa) I have to use to return with filling the provided structure clientAddr?


Solution

IIUC, you want that as a result of a call to accept, the second parameter of accept, which is currently sa_int to be set to the value of sa_next.

If that's the case, I can think of two options:

struct sockaddr {
  std::string name;
};

class MockedSysSocket {
 public:
  MOCK_METHOD(int, accept, (int, sockaddr *, socklen_t *addrlen), ());
};

TEST(MockedSysSocketTest, SideEffect1) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(DoAll(SetArgPointee<1>(sa_next), Return(accept_sock)));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

TEST(MockedSysSocketTest, SideEffect2) {
  MockedSysSocket mocked_sys_socket;

  int accept_sock = 1;
  int listen_sock = 2;

  sockaddr sa_in{"initial"};
  sockaddr sa_next{"next"};

  socklen_t clientLen = sizeof(sockaddr);

  EXPECT_CALL(mocked_sys_socket, accept(listen_sock, &sa_in, &clientLen))
      .WillOnce(WithArg<1>(Invoke([&sa_next, accept_sock](sockaddr *in) {
        *in = sa_next;
        return accept_sock;
      })));

  auto actual = mocked_sys_socket.accept(listen_sock, &sa_in, &clientLen);
  EXPECT_EQ(sa_in.name, sa_next.name);
  EXPECT_EQ(actual, accept_sock);
}

Live example: https://godbolt.org/z/3h4ffcnd7



Answered By - Ari
Answer Checked By - Candace Johnson (WPSolving Volunteer)