Stubbing extern C functions for tests


#1

When you want to write unit tests for your Rust plugin that relies on functions / globals only available through a dynamically linked library, I thought the only way to test would be to abstract the functionality away. Abstracting is good, but may not always be the answer. I found out today that you can conditionally supply your own implementation of these functions for tests, benchmarks, etc.

I’ll use a crate of mine to give a concrete example. collectd-rust-plugin allows writing plugins in Rust that are instantiated by and communicate with the C daemon. This setup makes testing difficult.

Below is one such function that the daemon provides

extern "C" {
    pub fn plugin_dispatch_values(vl: *const value_list_t) -> ::std::os::raw::c_int;
}

Running any code that called this function in a unit test would result in a linker error, as the function would be missing. You can supply your own implementation for tests by using the export_name directive

#[cfg(test)]
pub mod overrides {
    #[no_mangle]
    pub extern "C" fn plugin_dispatch_values(vl: *const value_list_t) -> ::std::os::raw::c_int {
        0
    }
}

When I came across this solution and verified it works, I just had to share :smile:


#2

#[no_mangle]?


#3

I used no_mangle in my first attempt and failed, so I had turned to export_name – turns out #[no_mangle] works! I must have misstepped. I’ll edit my answer to prefer no_mangle. Thank you :sweat_smile: