Using -Wl,--wrap for mocking in C
source link: https://drewdevault.com/2016/07/19/Using-Wl-wrap-for-mocking-in-C.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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/[email protected] [mailing list etiquette]
Articles from blogs I read Generated by openring
Go on ARM and Beyond
The industry is abuzz about non-x86 processors recently, so we thought it would be worth a brief post about Go’s support for them. It has always been important to us for Go to be portable, not overfitting to any particular operating sys…
via The Go Programming Language Blog December 17, 2020Status update, December 2020
Hi all! This status update is the 24th one, so it’s been 2 years I’ve started writing those now (ignoring a little hiatus). Time flies! This month I’ve invested a lot of time into wlroots. My main focus has been renderer v6, which has now been internally rol…
via emersion December 16, 2020What's cooking on Sourcehut? December 2020
A brisk wind of winter chill sets a stir down my spine, as I sit down with a fresh cup of coffee to yarn a story of careful engineering and passionate spirit that took place over the course of 30 days. The last 30 days. Cause this is the monthly “what’s cook…
via Blogs on Sourcehut December 15, 2020Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK