From this article Unit testing with mock objects in C:
This is done by using the
--wrap
linker option which takes the name of the wrapped function as an argument. If the test was compiled using gcc, the invocation might look like:
$ gcc -g -Wl,--wrap=chef_cook waiter_test.c chef.c
How can I do this when compiling a C project in visual studio?
The --wrap
in ld
can be emulated by the /ALTERNATENAME
option in MSVC Linker.
We start from two compilation units, say foo.o
compiled from foo.c
, whose external functions are declared in foo.h
, and main.o
from main.c
.
(If foo
has been compiled as a library, things won't change much.)
// foo.h
int foo();
// foo.c
int foo() {
return 0;
}
// main.c
#include <stdio.h>
#include "foo.h"
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
The return value of int foo()
is 0, so the snippet of code above will output "original".
Now we override the actual implementation by an alias: The #include "foo.h"
in main.c
is replaced by
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
Let me explain what happens here:
#define foo real_foo
, the function declaration in foo.h
is modified as int real_foo()
.foo.o
is still named after int foo()
, instead of the alias int real_foo()
. That's why we need the /alternatename
linker switch."/alternatename:real_foo=foo"
tells the linker that, if you cannot find the symbol called real_foo
, try foo
again before throwing an error.int real_foo()
. MSVC Linker will search for int foo()
and link it instead at each occurrence of int real_foo()
.As the previous implementation has been aliased, now we redirect int foo()
to our new implementation by a macro:
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
And we are done here. At last the main.cpp
looks like:
#include <stdio.h>
#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
int wrap_foo() {
return real_foo() + 1;
}
#define foo wrap_foo
int main() {
int x = foo();
printf("%s\n", x ? "wrapped" : "original");
}
Built in MSVC, it will output "wrapped".