/about /posts /pages

Using `cmocka` to mock functions with pointer arguments

2026-08-23

Backstory

I recently wanted to work on some units tests of a C library I have written years ago, just for the sake of writing C again. The library is called swayipc and is simple client library for interacting with the Sway window manager via IPC. For testing, cmocka is used. Previously, the unit tests had a runtime dependency on Sway, meaning you could not test that in a different environment (Gnome, headless, whatever). Yeah, ikr ... Well, time to change that. Time to take a closer look at mocking with cmocka.

Setup

There are multiple source files (swayipc.c, socket.c, events.c); at the moment I am adapting the tests for swayipc.c. First goal is to avoid interacting with the actual Sway IPC socket, therefore we need to mock some functions from the socket.c file.

Although there is quite a bit documentation and examples available, I couldn't find a proper example how to mock struct references in function parameters. Well, there probably is somewhere and this is yet another cheap excuse for writing a stupid blog post :)

Anyways, the official API documentation is definitely something to check out: https://api.cmocka.org/.

In the end, it's nothing really exciting, especially with version 2.0.0 and higher; but who knows, maybe it do helps somebody.

Current State

The following code snippets show the relevant parts. The function swayipc_get_version() should be tested (trivial, I know, but it just an example):

// swayipc.c
int swayipc_get_version(char* buf, size_t len)
{
    return swayipc_get_info(GET_VERSION, buf, len);
}

int swayipc_get_info(enum message_type type, char* buf, size_t len)
{
    message_s req = {.size = 0, .type = type, .data = 0};
    message_s res;

    if (socket_request(swayipc_fd, &req, &res) < 0) {
        perror("Cannot send request");
        return -errno;
    }

    snprintf(buf, len, "%s", res.data);
    return 0;
}

It basically calls swayipc_get_info() with a command enum. The function swayipc_get_info() creates a message_s struct req for the request and the respective response res struct. These are then passed to socket_request() (defined in socket.c), which sends out the request and returns the response.

As we don't care about calling the actual low-level socket_request() function, it needs to be mocked. However, as the res pointer is used to store the servers reply, the mock function must write data to this as well.

/// socket.c
int socket_request(int fd, const message_s* req, message_s* res)
{
    if (socket_send(fd, req) < 0) return -errno;

    if (socket_recv(fd, res) < 0) return -errno;

    return 0;
}

Mocking

In general, mocking functions with cmocka is done by weak linking the function to be mocked. This can be done by creating a function with the same signature, but with the specific prefix __wrap_. Additionally, in the linker arguments, we explicitly add it with --wrap=<function-name-to-be-mocked>.

So, to mock the function socket_request(), we

Next, in our test function (let's use test_swayipc_get_info), we can parameterize the mock function: using the functions starting with will_*, we can add data to a queue, which can later be used by the mock function using functions starting with mock_*.

With version >= 2.0.0, we can also give mocked items a name and reference it by that (will_set_parameter_ptr() and mock_parameter_ptr()).

Additionally, we can also use the "typed" functions (will_set_parameter_ptr_type() and mock_parameter_ptr_type()), which not only verify that the type of the mocked data is correct, but also cast the returned pointer automatically.

Mhm, maybe it's easier to show with an example. For instance:

// tester function
static void test_swayipc_get_version(void** state)
{
    // prepare data for mock function
    char*     s = "{ \"human_readable\": \"0.5.1\", \"sway_original_version\": "
                  "\"1.10.1\", \"variant\": \"sway\", \"major\": 0, \"minor\": 5, "
                  "\"patch\": 1, "
                  "\"loaded_config_file_name\":,\"~\\/.config\\/sway\\/config\"}";
    message_s buf = {.size = strlen(s), .type = GET_VERSION, .data = s};

    // add an item with key `mocked_res` and value `&buf` of type `message_s*`
    // to the mock queue
    will_set_parameter_ptr_type(__wrap_socket_request, mocked_res, &buf, message_s*);

    // push an unamed integer to the mock queue
    will_return(__wrap_socket_request, 3);

    // call the function to be tested
    int ret = swayipc_get_version(data, LEN);

    // verify return value and the data written to the buffer
    assert_int_equal(ret, 0);
    assert_string_equal(data, buf.data);
}

// mock function
int __wrap_socket_request(int fd, const message_s* req, message_s* res)
{
    (void)fd;
    (void)message;

    // retrieve the named item 
    // note: do not write the pointer itself, but the data it points to ... duh
    *res = *mock_parameter_ptr_type(mocked_res, message_s*);

    // pops the second message from the mock queue
    return mock_type(int);
}

cmocka version < 2.0.0

With cmocka version < 2.0.0, the functions will_set_parameter_ptr, will_set_parameter_ptr_type, mock_parameter_ptr(), mock_parameter_ptr_type() are not available, meaning we don't have any named types. Instead, we have to work with the basic functions will_return() and mock(), which push the data into a FIFO queue. But as long we remember the sequence, we can pop it and cast it manually. See below:

static void test_swayipc_get_version(void** state)
{
    // prepare data for mock function
    char*     s = "{ \"human_readable\": \"0.5.1\", \"sway_original_version\": "
                  "\"1.10.1\", \"variant\": \"sway\", \"major\": 0, \"minor\": 5, "
                  "\"patch\": 1, "
                  "\"loaded_config_file_name\":\"~\\/.config\\/sway\\/config\"}";
    message_s buf = {.size = strlen(s), .type = GET_VERSION, .data = s};

    // push pointer referencing our dummy struct to the mock queue
    will_return(__wrap_socket_request, &buf);

    // push an integer to the mock queue
    will_return(__wrap_socket_request, 3);

    // verify return value and the data written to the buffer
    assert_int_equal(swayipc_get_version(data, LEN), 0);
    assert_string_equal(data, out.data);
}

// mock function
int __wrap_socket_request(int fd, const message_s* message,
                              message_s* reply)
{
    (void)fd;
    (void)message;

    // manual cast and  copy from the mock queue into the reply buffer
    memcpy(reply, (message_s*)mock(), sizeof(*reply));

    // pops the second element from the mock queue
    return mock_type(int);
}

Maybe not as elegant as the new API, but it works as OK too. Downside is the missing name lookup and the automatic type-check & casting.

Summary

In the end, mocking functions with pointer arguments is the same as any mocking any other type, add the pointer to the queue, make sure to cast it correctly and copy the data into the out-param in the mock function:

For versions < 2.0.0, there's no named-parameter mock queue - use will_return() / mock() instead, remember the queue sequence and memcpy() the popped struct into the out-param manually.