'How does target_link_libraries(--wrap) work?

I want to create mock functions for C code testing and get to know that in target_link_libraries() have option to wrap the function which work similar to mock, But not understand how it will work?

target_link_libraries(IntegrationTests crypto-testutils mbedcrypto mbedtls sodium cmocka-static
"-Wl,\
--wrap=ExportCTRKeys,\
--wrap=malloc,\
--wrap=GenRandom)

How do I write this wrap functionality and how it will work?



Solution 1:[1]

Since the question is about CMake, let me propose an alternative from CMake perspective. With CMake you can construct your tests to compile your source file to be tested (SUT) together with your test instead of linking with the target being tested.

This would add some extra compilation time as the source file needs to be recompiled within the test. If this is a problem please, you might stop reading.

Assuming this is not an issue for you, then you can simply pull in the PUBLIC header dependencies without pulling in their implementations. You can then implement mocks/fakes for dependencies used in your test file.

Here is an example source file include/foo.h, foo.c, and CMakeLists.txt.

#include <ext_decl.h> //Declares struct ext_lib_struct_t in a CMake target ext_decl_lib
int foo(struct ext_lib_struct_t a);
#include <foo.h> //Declares void* foo();
#include <ext_impl.h> //This is the header declaring extlibcall in a CMake target ext_impl_lib
int foo(struct ext_lib_struct_t a) {
   return extlibcall(a); //A mock will be used for this call. 
}
add_library(foo_lib)
target_sources(foo_lib
  PRIVATE
    foo.c
)
target_link_libraries(foo_lib
PUBLIC
    ext_decl_lib
PRIVATE
    ext_impl_lib
)
target_include_directories(foo_lib
  PUBLIC
    include # Where foo.h is.
)

Here is your test file, testfoo.c. Customize this with your favorite unit testing framework.

#include <foo.h>
#include <assert.h>
int test_data;
int extlibcall() {
 return test_data;
}
void testA() { //Replace this with test cases from your favorite unit testing platform.   
   test_data = 2;
   int tr = foo();
   ASSERT(test_data == tr); //Use your favorite assert utility. 
}
int main(void)
{
    testA();
    return 0; 
}

And finally CMake instructions for your test, which can go into a CMakeLists.txt file in your test directory.

add_executable(testlibfoo)
target_sources(testlibfoo
  PRIVATE
    testfoo.c
    $<TARGET_PROPERTY:foo_lib,SOURCE_DIR>/foo.c
)
target_include_directories(test_unity_sall_mgm_join
  PRIVATE
    include
    $<TARGET_PROPERTY:foo_lib,INCLUDE_DIRECTORIES>
)
target_link_libraries(test_unity_sall_mgm_join
  PRIVATE
    assert_lib
    #Add your favorite unit test framework and/or other libraries used in the test
)

Test code compiles foo.c only once since foo_lib is not linked. However, it will probably be recompiled later for your production code when some other library links to foo_lib.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1