use crate::ffi;
use std::ffi::CString;
use crate::ffi::types::primitive::Pointer;
use crate::ffi::types::Value;
use crate::platform::{LibcPath, LibmPath, StrdupSymbolName};
#[test]
fn signedIntegers() -> ()
{
ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
let resI8: i8 = libc.call("abs").arg::<i32>(-5).result::<i32>()? as i8;
assert!(matches!(resI8, 5));
let resI16: i16 = libc.call("abs").arg::<i32>(-15).result::<i32>()? as i16;
assert!(matches!(resI16, 15));
let resI32: i32 = libc.call("abs").arg::<i32>(-42).result()?;
assert!(matches!(resI32, 42));
#[cfg(unix)]
let resI64: i64 = libc.call("labs").arg::<i64>(-100000).result()?;
#[cfg(windows)]
let resI64: i64 = libc.call("labs").arg::<i32>(-100000).result::<i32>()? as i64;
assert!(matches!(resI64, 100000));
#[cfg(unix)]
let resIsize: isize = libc.call("labs").arg::<isize>(-500).result()?;
#[cfg(windows)]
let resIsize: isize = libc.call("labs").arg::<i32>(-500).result::<i32>()? as isize;
assert!(matches!(resIsize, 500));
Ok(())
}).expect("Signed integers test failed");
}
#[test]
fn unsignedIntegers() -> ()
{
ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
let resU8: u8 =
libc.call("strnlen")
.arg(c"a")
.arg::<u8>(10)
.result()?;
assert!(matches!(resU8, 1));
let resU16: u16 =
libc.call("strnlen")
.arg(c"ab")
.arg::<u16>(10)
.result()?;
assert!(matches!(resU16, 2));
let resU32: u32 =
libc.call("strnlen")
.arg(c"abc")
.arg::<u32>(10)
.result()?;
assert!(matches!(resU32, 3));
let resU64: u64 =
libc.call("strnlen")
.arg(c"abcd")
.arg::<u64>(10)
.result()?;
assert!(matches!(resU64, 4));
let resUsize: usize =
libc.call("strnlen")
.arg(c"abcde")
.arg::<usize>(10)
.result()?;
assert!(matches!(resUsize, 5));
Ok(())
}).expect("Unsigned integers test failed");
}
#[test]
fn float() -> ()
{
let resultF32: f32 = ffi!(|scope| {
let libm: Library = scope.load(LibmPath)?;
libm.call("sqrtf").arg::<f32>(16.0).result()
}).expect("FFI F32 call failed");
assert!((resultF32 - 4.0).abs() < f32::EPSILON);
let resultF64: f64 = ffi!(|scope| {
let libm: Library = scope.load(LibmPath)?;
libm.call("pow")
.arg::<f64>(2.0)
.arg::<f64>(3.0)
.result()
}).expect("FFI F64 call failed");
assert!((resultF64 - 8.0).abs() < f64::EPSILON);
}
#[test]
fn bool() -> ()
{
let result: bool = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
libc.call("isalpha").arg(true).result()
}).expect("FFI Bool call failed");
assert!(!result);
}
#[test]
fn pointer() -> ()
{
let result: Pointer = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
libc.call("getenv")
.arg(c"noSuchVar")
.result()
}).expect("FFI pointer call failed");
assert_eq!(result, Pointer(0));
}
#[test]
fn pointerRoundtrip() -> ()
{
let len: usize = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
let ptr: Pointer =
libc.call(StrdupSymbolName)
.arg(c"hello")
.result()?;
assert_ne!(ptr, Pointer(0));
let result: usize = libc.call("strlen").arg(ptr).result()?;
libc.call("free").arg(ptr).void()?;
Ok(result)
}).expect("pointer roundtrip failed");
assert!(matches!(len, 5));
}
#[test]
fn stringBridges() -> ()
{
let valString: Value = String::from("hello").into();
assert!(matches!(valString, Value::String(_)));
let valStr: Value = "hello".into();
assert_eq!(valStr, Value::String(b"hello".to_vec()));
let valCString: Value = CString::new("hello").unwrap().into();
assert_eq!(valCString, c"hello".into());
let valRawBytes: Value = vec![0u8, 1, 2].into();
assert_eq!(valRawBytes, Value::RawString(vec![0, 1, 2]));
let resString: String = Value::RawString(b"hello".to_vec()).try_into().unwrap();
assert_eq!(resString, "hello");
assert!(CString::try_from(Value::RawString(b"with\0nul".to_vec())).is_err());
}
#[test]
fn cString() -> ()
{
let result: usize = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
libc.call("strlen")
.arg(c"hello")
.result()
}).expect("FFI CString call failed");
assert_eq!(result, 5);
}
#[test]
fn string() -> ()
{
let result: usize = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
libc.call("strnlen")
.arg("hello world")
.result()
}).expect("FFI String call failed");
assert_eq!(result, 11);
}
#[test]
fn rawString() -> ()
{
let result: i32 = ffi!(|scope| {
let libc: Library = scope.load(LibcPath)?;
libc.call("atoi")
.arg(b"12345\0".to_vec())
.result()
}).expect("FFI RawString call failed");
assert_eq!(result, 12345);
}