You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在CMocka中验证函数指针参数的正确性?

How to Verify Function Pointer Arguments in 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:

  1. 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);
}
  1. Use expect_check in 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:28:58