Reputation: 39
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?
Upvotes: 1
Views: 2727
Reputation: 11
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.
Upvotes: 1
Reputation: 171167
When target_link_libraries
gets arguments which start with -
, it treats them as linker command-line options and passes them untouched to the linker. This therefore has nothing to do with CMake and everything to do with ld. You can study this in ld reference documentation, such as this one:
--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 (size_t c) { printf ("malloc called with %zu\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. 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"
.
Upvotes: 2