Problem calling C++ Class method from Rust - c++

The following code is generated by bindgen.
extern "C" {
#[doc = "MoraComm Properties"]
#[link_name = "\u{1}_ZN22MoraCommManagerWrapped10propertiesEj"]
pub fn MoraCommManagerWrapped_properties(
this: *mut MoraCommManagerWrapped,
deviceNumber: ::std::os::raw::c_uint,
) -> MoraCommPropertiesWrapped;
}
impl MoraCommManagerWrapped {
#[inline]
pub unsafe fn properties(
&mut self,
deviceNumber: ::std::os::raw::c_uint,
) -> MoraCommPropertiesWrapped {
MoraCommManagerWrapped_properties(self, deviceNumber)
}
#[inline]
pub unsafe fn new() -> Self {
let mut __bindgen_tmp = ::std::mem::MaybeUninit::uninit();
MoraCommManagerWrapped_MoraCommManagerWrapped(__bindgen_tmp.as_mut_ptr());
__bindgen_tmp.assume_init()
}
}
fn main() {
unsafe {
let mut mgr: MoraCommManagerWrapped = MoraCommManagerWrapped::new();
let p = mgr.properties(0); // <- segfault
}
}
When main is run, there is a segfault.
I added logging on the C++ side, that shows that the value of the this pointer is equal to value of the deviceNumber arg.
I call another class that is part of the same bindgen generated bindings and it works.
Any thoughts on what might be going on?

Related

Unit testing a service that accepts an Fn closure as a callback

I have the following service that registers callbacks to execute at a certain epoch, identified by an i64. The service has a vector of callbacks (that are bounded by the Send + Fn() -> () traits). Each callback can be executed multiple times (hence Fn instead of FnOnce or FnMut). The Send trait is needed because the callbacks will be registered by other threads, and this service will run in the background.
So far so good, but I'd like to test that the callbacks are executed the way they should be (i.e. the i64 epoch ticking in some direction which may (or may not) cause the callback to be executed). The problem is that I cannot seem to be able to think of a way to achieve this. I'm coming from Golang in which it is quite easy to inject a mock callback and assert whether it was called since such limitations are not imposed by the compiler, however when I employ the same methods in Rust, I end up with an FnMut instead of an Fn.
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
struct Service<T: Send + Fn() -> ()> {
triggers: Arc<Mutex<HashMap<i64, Vec<Box<T>>>>>,
}
impl<T: Send + Fn() -> ()> Service<T> {
pub fn build() -> Self {
Service {
triggers: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn poll(&'static self) {
let hs = Arc::clone(&self.triggers);
tokio::spawn(async move {
loop {
// do some stuff and get `val`
if let Some(v) = hs.lock().unwrap().get(&val) {
for cb in v.iter() {
cb();
}
}
}
});
()
}
pub fn register_callback(&self, val: i64, cb: Box<T>) -> () {
self.triggers
.lock()
.unwrap()
.entry(val)
.or_insert(Vec::new())
.push(cb);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_poll() {
let c = Service::build();
let mut called = false;
let cb = || called = true;
let h: i64 = 10;
c.register_callback(h, Box::new(cb));
assert_eq!(called, false);
}
}
Any ideas on how would this sort of behavior could be tested in Rust? The only thing I can think of is perhaps some channel that would pass a local value to the test and relinquish ownership over it?
The best way would probably be to make your interface as general as possible:
// type bounds on structs are generally unnecessary so I removed it here.
struct Service<T> {
triggers: Arc<Mutex<HashMap<i64, Vec<Box<T>>>>>,
}
impl<T: Send + FnMut() -> ()> Service<T> {
pub fn build() -> Self {
Service {
triggers: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn poll(&'static self, val: i64) {
let hs = Arc::clone(&self.triggers);
tokio::spawn(async move {
loop {
// do some stuff and get `val`
if let Some(v) = hs.lock().unwrap().get_mut(&val) {
for cb in v.iter_mut() {
cb();
}
}
}
});
()
}
pub fn register_callback(&self, val: i64, cb: Box<T>) -> () {
self.triggers
.lock()
.unwrap()
.entry(val)
.or_insert(Vec::new())
.push(cb);
}
}
But if you can't generalize the interface you can just use an AtomicBool like this:
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{Ordering, AtomicBool};
#[test]
fn test_poll() {
let c = Service::build();
let mut called = AtomicBool::new(false);
let cb = || called.store(true, Ordering::Relaxed);
let h: i64 = 10;
c.register_callback(h, Box::new(cb));
assert!(!called.load(Ordering::Relaxed));
}
}

Mocking functions in rust

Is there a way to mock regular functions in rust?
Consider the following code:
fn main() {
println!("{}", foo());
}
fn get_user_input() -> u8 {
// Placeholder for some unknown value
42
}
fn foo() -> u8 {
get_user_input()
}
#[cfg(test)]
mod tests {
#[test]
fn test_foo() {
use super::*;
get_user_input = || 12u8;
assert_eq!(foo(), 12u8);
}
}
I would like to unit test foo() without having to rely on the output of get_user_input().
I obviously cannot overwrite get_user_input() like I tried in the example code.
I have only found ways to mock structs, traits and modules but nothing about mocking regular free functions. Am I missing something?
Edit: I have looked primarily at the mockall crate.
You could use cfg:
#[cfg(not(test))]
fn get_user_input() -> u8 {
// Placeholder for some unknown value
42
}
#[cfg(test)]
fn get_user_input() -> u8 {
12
}
playground
Or dependency injection:
pub fn main() {
println!("{}", foo(get_user_input));
}
fn get_user_input() -> u8 {
// Placeholder for some unknown value
42
}
fn foo(get_user_input_: impl Fn() -> u8) -> u8 {
get_user_input_()
}
#[cfg(test)]
mod tests {
#[test]
fn test_foo() {
use super::*;
let get_user_input = || 12u8;
assert_eq!(foo(get_user_input), 12u8);
}
}
playgound

Create tempfiles for testing

I'm trying to create some temporary files but I would like the creation and destruction of those temporary files to be on it's own function. I don't know how to pass the reference of many files from the creation function to the destruction function.
use walkdir::{WalkDir, DirEntry};
fn get_type_filepaths(dir: &Path, _type: &str) -> Vec<&Path> {
let mut filepaths = vec![];
let walker = WalkDir::new(dir).into_iter()
for entry in walker.filter_map(|e| e.ok() && is_filetype(e, _type)) {
filepaths.push(entry);
return filepaths;
fn is_filetype(entry: &DirEntry, _type: &str) -> bool {
entry.file_name()
.to_str()
.to_lowercase()
.map(|s| s.ends_with(_type))
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use tempfile::tempdir;
use std::fs::File;
use std::io::{self, Write};
#[test]
fn test_is_filetype() {
// fn create_tempfiles() -> vec! {
let dir = tempdir()?;
let file_path = dir.path().join("foo.txt");
let mut file = File::create(file_path)?;
writeln!(file, "asdf")?;
// return dir, [file1, file2...]
assert!(is_filetype("tmp/foo.txt", ".txt"));
// fn cleanup_tempfiles(dir, files: vec!) {
// for file in files:
drop(file);
dir.close()?;
}
}

How to recover the concrete type from Any

Code:
use std::fmt::Debug;
use std::any::Any;
fn any_to_u16(value: &dyn Any)
{
let v = value as u16;
}
fn main()
{
let x = true;
any_to_u16(&x);
}
Erorr :
error[E0606]: casting `&(dyn std::any::Any + 'static)` as `u16` is invalid
--> src/lib.rs:6:13
|
6 | let v = value as u16;
| ^^^^^^^^^^^^
|
= help: cast through a raw pointer first
Playground
How to fix?
You must use Any::downcast_ref:
use std::any::Any;
fn any_to_u16(value: &dyn Any)
{
if let Some(value) = value.downcast_ref::<bool>().map(|b| *b as u16) {
// value is a `bool`
assert_eq!(value, 1);
}
}
fn main()
{
let x = true;
any_to_u16(&x);
}

How do you test for a specific Rust error?

I can find ways to detect if Rust gives me an error,
assert!(fs::metadata(path).is_err())
source
How do I test for a specific error?
You can directly compare the returned Err variant if it impl Debug + PartialEq:
#[derive(Debug, PartialEq)]
enum MyError {
TooBig,
TooSmall,
}
pub fn encode(&self, decoded: &'a Bytes) -> Result<&'a Bytes, MyError> {
if decoded.len() > self.length() as usize {
Err(MyError::TooBig)
} else {
Ok(&decoded)
}
}
assert_eq!(fixed.encode(&[1]), Err(MyError::TooBig));
Following solution doesn't require PartialEq trait to be implemented. For instance std::io::Error does not implement this, and more general solution is required.
In these cases, you can borrow a macro assert_matches from matches crate. It works by giving more succinct way to pattern match, the macro is so short you can just type it too:
macro_rules! assert_err {
($expression:expr, $($pattern:tt)+) => {
match $expression {
$($pattern)+ => (),
ref e => panic!("expected `{}` but got `{:?}`", stringify!($($pattern)+), e),
}
}
}
// Example usages:
assert_err!(your_func(), Err(Error::UrlParsingFailed(_)));
assert_err!(your_func(), Err(Error::CanonicalizationFailed(_)));
assert_err!(your_func(), Err(Error::FileOpenFailed(er)) if er.kind() == ErrorKind::NotFound);
Full playground buildable example, with example Error enum:
#[derive(Debug)]
pub enum Error {
UrlCreationFailed,
CanonicalizationFailed(std::io::Error),
FileOpenFailed(std::io::Error),
UrlParsingFailed(url::ParseError),
}
pub fn your_func() -> Result<(), Error> {
Ok(())
}
#[cfg(test)]
mod test {
use std::io::ErrorKind;
use super::{your_func, Error};
macro_rules! assert_err {
($expression:expr, $($pattern:tt)+) => {
match $expression {
$($pattern)+ => (),
ref e => panic!("expected `{}` but got `{:?}`", stringify!($($pattern)+), e),
}
}
}
#[test]
fn test_failures() {
// Few examples are here:
assert_err!(your_func(), Err(Error::UrlParsingFailed(_)));
assert_err!(your_func(), Err(Error::CanonicalizationFailed(_)));
assert_err!(your_func(), Err(Error::FileOpenFailed(er)) if er.kind() == ErrorKind::NotFound);
}
}