如何在CMocka中验证函数指针参数的正确性?
I get it, you're trying to validate that the correct function pointer is passed to your wrapped register_callback function, but expect_memory isn't working as expected—even when you pass the wrong callback, the test still passes. Let's break down why this happens and fix it properly.
Why expect_memory Fails Here
The issue with expect_memory is that it compares the content of the memory at the given pointer, not the pointer's value itself. When you pass callback_module_a or callback_module_b to expect_memory, it's trying to compare the first sizeof(CALLBACK) bytes of the function's code (since the pointer points to the start of the function). If your callback functions are simple (like empty stubs), their initial machine code bytes might be identical, which is why the test incorrectly passes even when the wrong callback is used.
Correct Solutions
Option 1: Use expect_value with Pointer-to-Integer Conversion
Function pointers are just memory addresses under the hood, so we can cast them to uintptr_t (a standard integer type designed to hold pointer values) and compare directly with expect_value:
First, update your wrapped function to use check_expected_ptr (it's clearer for pointer types, though check_expected might also work):
void __wrap_register_callback( CALLBACK callback ) { check_expected_ptr(callback); }
Then, in your test cases, cast the expected callback to uintptr_t when setting the expectation:
// TEST 1: Correct case (status=0 should use callback_module_b) status = 0; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_b); code_that_set_the_callback(status); // TEST 3: Incorrect case (should fail) status = 0; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_a); code_that_set_the_callback(status);
Option 2: Use a Custom Matcher with expect_check
If you prefer a more explicit approach, you can define a custom matching function to compare the function pointers directly:
- Define the matcher function:
// Custom matcher to compare CALLBACK function pointers int match_callback(const void *expected, const void *actual, const char **error_message) { (void)error_message; // Unused in this simple matcher const CALLBACK expected_cb = *(const CALLBACK*)expected; const CALLBACK actual_cb = *(const CALLBACK*)actual; return (expected_cb == actual_cb); }
- Use
expect_checkin your tests to apply this matcher:
// TEST 2: Correct case (status=-1 should use callback_module_a) status = -1; expect_check(__wrap_register_callback, callback, match_callback, callback_module_a); code_that_set_the_callback(status); // TEST 4: Incorrect case (should fail) status = -1; expect_check(__wrap_register_callback, callback, match_callback, callback_module_b); code_that_set_the_callback(status);
Modified Full Test Code
Here's your complete code updated with Option 1 (the simpler approach):
#include <stdarg.h> #include <stddef.h> #include <setjmp.h> #include <stdint.h> #include <cmocka.h> union EVENT{ uint8_t event; }; typedef void (*CALLBACK)(union EVENT * event); void register_callback( CALLBACK callback ); // Declare the original function void callback_module_a( union EVENT *event ) { (void)event; } void callback_module_b( union EVENT *event ) { (void)event; } void __wrap_register_callback( CALLBACK callback ) { check_expected_ptr(callback); } void code_that_set_the_callback( int status ) { if (status < 0){ register_callback(callback_module_a); }else{ register_callback(callback_module_b); } } void test_correct_handler( ) { int status; // TEST 1: Correct - status=0 uses callback_module_b status = 0; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_b); code_that_set_the_callback(status); // TEST 2: Correct - status=-1 uses callback_module_a status = -1; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_a); code_that_set_the_callback(status); // TEST 3: Incorrect - should fail (status=0 expects callback_module_a) status = 0; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_a); code_that_set_the_callback(status); // TEST 4: Incorrect - should fail (status=-1 expects callback_module_b) status = -1; expect_value(__wrap_register_callback, callback, (uintptr_t)callback_module_b); code_that_set_the_callback(status); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_correct_handler), }; return cmocka_run_group_tests(tests, NULL, NULL); }
Compile this with your usual command (including the --wrap linker flag):
gcc -o test_callbacks test_callbacks.c -lcmocka -Wl,--wrap=register_callback
Now when you run the test, cases 3 and 4 will fail as expected, confirming that the correct callback is being passed based on the status value.
内容的提问来源于stack exchange,提问作者andyinno

