Using -Wl,--wrap for mocking in C July 19, 2016 on Drew DeVault's blog

One of the comforts I’ve grown used to in higher level languages when testing my code is mocking. The idea is that in order to test some code in isolation, you should “mock” the behavior of things it depends on. Let’s see a (contrived) example:

int read_to_end(FILE *f, char *buf) {
    int r = 0, l;
    while (!feof(f)) {
        l = fread(buf, 1, 256, f);
        r += l;
        buf += l;
    }
    return r;
}

If we want to test this function without mocking, we would need to actually open a specially crafted file and provide a FILE* to the function. However, with the linker --wrap flag, we can define a wrapper function. Using -Wl,[flag] in your C compiler command line will pass [flag] to the linker. Gold (GNU) and lld (LLVM) both support the wrap flag, which specifies a function to be “wrapped”. If I use -Wl,--wrap=fread, then the code above will be compiled like so:

int read_to_end(FILE *f, char *buf) {
    int r = 0, l;
    while (!feof(f)) {
        l = __wrap_fread(buf, 1, 256, f);
        r += l;
        buf += l;
    }
    return r;
}

And if I add -Wl,--wrap=feof we’ll get this:

int read_to_end(FILE *f, char *buf) {
    int r = 0, l;
    while (!__wrap_feof(f)) {
        l = __wrap_fread(buf, 1, 256, f);
        r += l;
        buf += l;
    }
    return r;
}

Now, we can define some functions that do the behavior we need to test instead of invoking fread directly:

int feof_return_value = 0;

int __wrap_feof(FILE *f) {
    assert(f == (FILE *)0x1234);
    return feof_return_value;
}

void test_read_to_end_eof() {
    // ...
    feof_return_value = 1;
    read_to_end((FILE *)0x1234, buf);
    // ...
}

Using --wrap also conveniently defines __real_feof and __real_fread if we need them.

Unfortunately, you can’t have two different wrappers for the same function in an executable. This could lead to having to write several executables for each, or making your wrapper function smart enough to have several configurable outcomes.

Eventually I intend to write my own test framework for C, which will use wrappers to support mocking. I want wrappers to be done automatically and have it behave something like this:

static int fake_fread(void *ptr, size_t size,
        size_t nmemb, FILE *stream) {
    const char *hello = "Hello world!";
    memcpy(ptr, hello, strlen(hello) + 1);
    return strlen(hello) + 1;
}

void test_read_to_end() {
    FILE *test = (FILE *)0x1234;
    char *buffer = char[1024];

    mock_t *mock_feof = configure_mock(feof, "p");
    mock_feof->call(0)->returns(0);
    mock_feof->returns(1);

    // pzzp is pointer, size_t, size_t, pointer
    // Tells us what the fread arguments look like
    mock_t *mock_fread = configure_mock(fread, "pzzp");
    mock_fread->exec(fake_fread);

    read_to_end(test, buffer);

    assert(mock_feof->call_count == 2);
    assert((FILE*)mock_feof->call(0)->args(0) == test);

    assert(mock_fread->call_count == 1);
    assert((FILE*)mock_fread->call(0)->args(0) == buffer);
    assert((FILE*)mock_fread->call(0)->args(3) == test);

    assert(strcmp(buffer, "Hello world!") == 0);
}

Have a comment on one of my posts? Start a discussion in my public inbox by sending an email to ~sircmpwn/public-inbox@lists.sr.ht [mailing list etiquette]

Articles from blogs I read Generated by openring

Status update, May 2022

Hi all! This month’s status update will be shorter than usual, because I’ve taken some time off to visit Napoli. Discovering the city and the surrounding region was great! Of course the main reason to visit is to taste true Neapolitan pizza. I must admit, th…

via emersion May 24, 2022

What's cooking on SourceHut? May 2022

Hello everyone! We’re back at it for another month of news in the SourceHut sphere. Of our now 29,036 users, 630 are new this month: please offer them a warm welcome, and your patience, as they learn about the new platform. todo.sr.ht Comprehensive GraphQL-na…

via Blogs on Sourcehut May 16, 2022

Summary of changes for April

Hey everyone! This is the list of all the changes we've done to our projects and apps during the month of April. We'll also be reporting in our on position in the world, and on our future plans. Summary Of Changes Bicycle, released an Uxntal pla…

via Hundred Rabbits May 1, 2022