cmocka is a C unit test library.
https://cmocka.org/
It has the following functions. https://api.cmocka.org/
--assertion macro --Mock support --Catch the signal and handle the exception --Test for memory leaks, buffer overflows and underflows --Supports several output formats (stdou, XUnit xml, etc.)
If it is a RHEL OS, the package is provided by EPEL, so it seems good to use it.
# yum install epel-release
# yum install libcmocka-devel
The execution environment is CentOS7, EPEL libcmocka-devel package is installed
assert_test.c
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <cmocka.h>
static void simple_assert_example(void **state) {
int *test_state = *state;
assert_int_equal(*test_state, 100);
}
static int setup(void **state) {
int *test_state = malloc(sizeof(int));
if (test_state == NULL) {
return -1;
}
*test_state = 100;
*state = test_state;
return 0;
}
static int teardown(void **state) {
free(*state);
return 0;
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(simple_assert_example),
};
return cmocka_run_group_tests(tests, setup, teardown);
}
In the main function, the CMUnitTest structure is created with the test function as an argument to cmocka_unit_test. The test function type must take (void \ * \ * state) as an argument and have a return value of void. The argument \ * \ * state is used to pass values between the setup and teardown functions that are called before and after the test.
I'm running tests with cmocka_run_group_tests. The first argument is an array of CMUnitTest structures, and the second and third arguments specify the functions to be called before and after the test. You can also pass NULL if you don't need it.
You can validate the value with macros such as ʻassert_int_equal, ʻassert_string_equal, ʻassert_ptr_equal, ʻassert_null.
https://api.cmocka.org/group__cmocka__asserts.html
When compiling, specify cmocka as the link option of the library.
gcc -o assert_test.bin assert_test.c -lcmocka
./test.bin
[==========] Running 1 test(s).
[ RUN ] simple_assert_example
[ OK ] simple_assert_example
[==========] 1 test(s) run.
[ PASSED ] 1 test(s).
If you want to change the output format, change the format with cmocka_set_message_output before calling cmocka_run_group_tests.
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(simple_assert_example),
};
// out put format is CM_OUTPUT_STDOUT by default, other options : CM_OUTPUT_SUBUNIT, CM_OUTPUT_TAP or CM_OUTPUT_XML.
cmocka_set_message_output(CM_OUTPUT_XML);
return cmocka_run_group_tests(tests, setup, teardown);
}
If you specify CM_OUTPUT_XML, the output will look like this:
<?xml version="1.0" encoding="UTF-8" ?>
<testsuites>
<testsuite name="tests" time="0.000" tests="1" failures="0" errors="0" skipped="0" >
<testcase name="simple_assert_example" time="0.000" >
</testcase>
</testsuite>
</testsuites>
cmocka provides a wrapper function for testing memory problems.
cmocka.h has the following definition:
#ifdef UNIT_TESTING
#define malloc test_malloc
#define realloc test_realloc
#define calloc test_calloc
#define free test_free
#endif /* UNIT_TESTING */
By defining the UNIT_TESTING constant before reading the header, the default function will be replaced by cmocka's memory checking function, which will detect memory allocation problems.
#define UNIT_TESTING 1
#include <cmocka.h>
static void test_free1(void **state) {
int *ptr_int = malloc(sizeof(int));
free(ptr_int);
}
static void test_free2(void **state) {
int *ptr_int = malloc(sizeof(int));
//free(ptr_int);
}
The test in the above sample test_free2 will fail because the allocated memory has not been released.
# make test
gcc -o test.bin memory_test.c -lcmocka
./test.bin
[==========] Running 2 test(s).
[ RUN ] test_free1
[ OK ] test_free1
[ RUN ] test_free2
[ ERROR ] --- Blocks allocated...
memory_test.c:17: note: block 0xa11080 allocated here
ERROR: test_free2 leaked 1 block(s)
[ FAILED ] test_free2
[==========] 2 test(s) run.
[ PASSED ] 1 test(s).
[ FAILED ] 1 test(s), listed below:
[ FAILED ] test_free2
1 FAILED TEST(S)
make: *** [test] Error 1
Mock
cmocka provides helper functions for testing by replacing parts of your code with mock functions.
The mock itself is realized by using the function of the linker. Specify "-Wl, --wrap = FUNC_TO_MOCK" as a gcc option at compile time so that the mock is called instead of the actual function.
The following is an excerpt from the man page.
Man "ld"
--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.
Man "gcc"
Linker Options
(...omit) -Wl,option -Xlinker option -u symbol
As an example, consider the case of testing a function like the one below.
int read_from_device_at_position(int val) {
return device_read(val);
}
Suppose device_read is a function that accesses some hardware device. You need to replace device_read with a mock to test read_from_device_at_position.
The mock and test functions are defined as follows:
int __wrap_device_read(int position) {
check_expected(position);
return mock();
}
static void simple_mock_example(void **state) {
int ret;
will_return(__wrap_device_read, 256);
expect_value(__wrap_device_read, position, 52);
ret = read_from_device_at_position(52);
assert_int_equal(ret, 256);
}
\ _ \ _ Wrap_device_read is a mock function of device_read called by read_from_device_at_position. This mock function can be called instead of the actual function by including "-Wl, --wrap = device_read" in the compile-time options. The compile command looks like this:
# gcc -o test.bin test.c mock_test.c -Wl,--wrap=device_read
The test function simple_mock_example defines arguments and return values. will_return defines the value returned by \ _ \ _wrap_device_read. This value can be retrieved in the function via a helper function. expect_value defines the value that should be passed as an argument to \ _ \ _wrap_device_read. Use the helper function to verify that the value defined here was passed.
The mock function __wrap_device_read validates the parameters and returns the predefined values. check_expected verifies that the parameters as defined in the test function will_return are passed. mock () takes the return value of the predefined mock function and returns it as is.
Recommended Posts