How to mock function in C when its caller function is defined in same file?
Asked Answered
I

3

6

I am trying to mock a function in C, mocking works fine when the function and its caller function are defined in different files. But when both functions (function itself and its caller) are defined in the same file, the mocked function does not get invoked.


Case 1 :

//test.c

#include <stdio.h>

/*mocked function*/
int __wrap_func() {
   printf("Mock function !!!\n"); 
}

/*caller function*/
int myTest() {
  return func();
}

int main() {
    myTest();
    return 0;
}

//file.c
#include<stdio.h>

/*function need to be mocked*/
int func() {
  printf("Original function !!!\n");
    }

Case 2 :

//test.c
#include <stdio.h>
extern int myTest();
/*mocked function*/
int __wrap_func() {
  printf("Mock function !!!\n");
}

int main() {
    myTest();
}
//file.c
#include<stdio.h>

/*function need to be mocked*/
int func() {
  printf("Original function !!!\n");
}

/*caller function*/
int myTest() {
  return func();
}

Code compilation command : gcc -Wl,--wrap=func test.c file.c

In Case 1 . Mock function !!!
In Case 2 . Original function !!!

In case 2, mocking function is not being invoked. I am looking for a solution where I can mock function even caller and called function are in same file.

Irmairme answered 1/7, 2015 at 8:33 Comment(0)
J
2

You cannot.

From the linker documentation,

--wrap symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol. This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_symbol. If it wishes to call the system function, it should call __real_symbol. Here is a trivial example:

void *
__wrap_malloc (int c)
{
  printf ("malloc called with %ld\n", c);
  return __real_malloc (c);
}

If you link other code with this file using --wrap malloc, then all calls to malloc will call the function __wrap_malloc instead. The call to __real_malloc in __wrap_malloc will call the real malloc function. You may wish to provide a __real_malloc function as well, so that links without the --wrap option will succeed.

Here'e the iimportant part ...

If you do this, you should not put the definition of __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve the call before the linker has a chance to wrap it to malloc.

Jealousy answered 23/10, 2015 at 8:53 Comment(0)
A
3

Using a function name starting with two underscores is undefined behaviour in C.

(In your case I suspect that the function name __wrap_func is clashing with the decorated name for func but that's speculative and entirely compiler-dependent.)

You ought to consider a solution using function pointers instead.

Adamis answered 1/7, 2015 at 8:40 Comment(0)
J
2

You cannot.

From the linker documentation,

--wrap symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol. This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_symbol. If it wishes to call the system function, it should call __real_symbol. Here is a trivial example:

void *
__wrap_malloc (int c)
{
  printf ("malloc called with %ld\n", c);
  return __real_malloc (c);
}

If you link other code with this file using --wrap malloc, then all calls to malloc will call the function __wrap_malloc instead. The call to __real_malloc in __wrap_malloc will call the real malloc function. You may wish to provide a __real_malloc function as well, so that links without the --wrap option will succeed.

Here'e the iimportant part ...

If you do this, you should not put the definition of __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve the call before the linker has a chance to wrap it to malloc.

Jealousy answered 23/10, 2015 at 8:53 Comment(0)
B
1

Using --wrap=symbol linker option will result so that undefined symbols will be resolved as __wrap_symbol. In your first case, func is undefined symbol so linker will search for __wrap_func and that function is called. In your second case, linker finds myTest because it is declared extern. When myTest calls func it is in the same translation unit so not undefiend that resides in the same file as being int func(). So the original func is calles instead of wrapped version. Your design is not suitable for using mocked functions when caller and callee are in the same file as well as in different files. I suggest you to use MACRO or function pointer technique as explained here.

Breathtaking answered 1/7, 2015 at 11:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.