We use a simple object model for our low level networking code at work where struct pointers are passed around to functions which are pretending to be methods. I've inherited most of this code which was written by consultants with passable C/C++ experience at best and I've spent many late nights trying to refactor code into something that would resemble a reasonable structure.
Now I would like to bring the code under unit testing but considering the object model we have chosen I have no idea how to mock objects. See the example below:
Sample header (foo.h):
#ifndef FOO_H_
#define FOO_H_
typedef struct Foo_s* Foo;
Foo foo_create(TcpSocket tcp_socket);
void foo_destroy(Foo foo);
int foo_transmit_command(Foo foo, enum Command command);
#endif /* FOO_H_ */
Sample source (foo.c):
struct Foo_s {
TcpSocket tcp_socket;
};
Foo foo_create(TcpSocket tcp_socket)
{
Foo foo = NULL;
assert(tcp_socket != NULL);
foo = malloc(sizeof(struct Foo_s));
if (foo == NULL) {
goto fail;
}
memset(foo, 0UL, sizeof(struct Foo_s));
foo->tcp_socket = tcp_socket;
return foo;
fail:
foo_destroy(foo);
return NULL;
}
void foo_destroy(Foo foo)
{
if (foo != NULL) {
tcp_socket_destroy(foo->tcp_socket);
memset(foo, 0UL, sizeof(struct Foo_s));
free(foo);
}
}
int foo_transmit_command(Foo foo, enum Command command)
{
size_t len = 0;
struct FooCommandPacket foo_command_packet = {0};
assert(foo != NULL);
assert((Command_MIN <= command) && (command <= Command_MAX));
/* Serialize command into foo_command_packet struct */
...
len = tcp_socket_send(foo->tcp_socket, &foo_command_packet, sizeof(foo_command_packet));
if (len < sizeof(foo_command_packet)) {
return -1;
}
return 0;
}
In the example above I would like to mock the TcpSocket object so that I can bring *"foo_transmit_command"* under unit testing but I'm not sure how to go about this without inheritance. I don't really want to redesign the code to use vtables unless I really have to. Maybe there is a better approach to this than mocking?
My testing experience comes mainly from C++ and I'm a bit afraid that I might have painted myself into a corner here. I would highly appreciate any recommendations from more experienced testers.
Edit:
Like Richard Quirk pointed out it is really the call to *"tcp_socket_send"* that I want to override and I would prefer to do it without removing the real tcp_socket_send symbol from the library when linking the test since it is called by other tests in the same binary.
I'm starting to think that there is no obvious solution to this problem..