151 lines
4.1 KiB
Rust
151 lines
4.1 KiB
Rust
//! Test for swift-rs bindings
|
|
//!
|
|
//! Needs to be run with the env var `TEST_SWIFT_RS=true`, to allow for
|
|
//! the test swift code to be linked.
|
|
|
|
use serial_test::serial;
|
|
use std::{env, process::Command};
|
|
use swift_rs::*;
|
|
|
|
macro_rules! test_with_leaks {
|
|
( $op:expr ) => {{
|
|
let leaks_env_var = "TEST_RUNNING_UNDER_LEAKS";
|
|
if env::var(leaks_env_var).unwrap_or_else(|_| "false".into()) == "true" {
|
|
let _ = $op();
|
|
} else {
|
|
// we run $op directly in the current process first, as leaks will not give
|
|
// us the exit code of $op, but only if memory leaks happened or not
|
|
$op();
|
|
|
|
// and now we run the above codepath under leaks monitoring
|
|
let exe = env::current_exe().unwrap();
|
|
|
|
// codesign the binary first, so that leaks can be run
|
|
let debug_plist = exe.parent().unwrap().join("debug.plist");
|
|
let plist_path = &debug_plist.to_string_lossy();
|
|
std::fs::write(&debug_plist, DEBUG_PLIST_XML.as_bytes()).unwrap();
|
|
let status = Command::new("codesign")
|
|
.args([
|
|
"-s",
|
|
"-",
|
|
"-v",
|
|
"-f",
|
|
"--entitlements",
|
|
plist_path,
|
|
&exe.to_string_lossy(),
|
|
])
|
|
.status()
|
|
.expect("cmd failure");
|
|
assert!(status.success(), "failed to codesign");
|
|
|
|
// run leaks command to detect memory leaks
|
|
let status = Command::new("leaks")
|
|
.args(["-atExit", "--", &exe.to_string_lossy(), "--nocapture"])
|
|
.env(leaks_env_var, "true")
|
|
.status()
|
|
.expect("cmd failure");
|
|
assert!(status.success(), "leaks detected in memory pressure test");
|
|
}
|
|
}};
|
|
}
|
|
|
|
swift!(fn echo(string: &SRString) -> SRString);
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_reflection() {
|
|
test_with_leaks!(|| {
|
|
// create memory pressure
|
|
let name: SRString = "Brendan".into();
|
|
for _ in 0..10_000 {
|
|
let reflected = unsafe { echo(&name) };
|
|
assert_eq!(name.as_str(), reflected.as_str());
|
|
}
|
|
});
|
|
}
|
|
|
|
swift!(fn get_greeting(name: &SRString) -> SRString);
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_string() {
|
|
test_with_leaks!(|| {
|
|
let name: SRString = "Brendan".into();
|
|
let greeting = unsafe { get_greeting(&name) };
|
|
assert_eq!(greeting.as_str(), "Hello Brendan!");
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_memory_pressure() {
|
|
test_with_leaks!(|| {
|
|
// create memory pressure
|
|
let name: SRString = "Brendan".into();
|
|
for _ in 0..10_000 {
|
|
let greeting = unsafe { get_greeting(&name) };
|
|
assert_eq!(greeting.as_str(), "Hello Brendan!");
|
|
}
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_autoreleasepool() {
|
|
test_with_leaks!(|| {
|
|
// create memory pressure
|
|
let name: SRString = "Brendan".into();
|
|
for _ in 0..10_000 {
|
|
autoreleasepool!({
|
|
let greeting = unsafe { get_greeting(&name) };
|
|
assert_eq!(greeting.as_str(), "Hello Brendan!");
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct Complex {
|
|
a: SRString,
|
|
b: Int,
|
|
c: Bool,
|
|
}
|
|
|
|
swift!(fn complex_data() -> SRObjectArray<Complex>);
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_complex() {
|
|
test_with_leaks!(|| {
|
|
let mut v = vec![];
|
|
|
|
for _ in 0..10_000 {
|
|
let data = unsafe { complex_data() };
|
|
assert_eq!(data[0].a.as_str(), "Brendan");
|
|
v.push(data);
|
|
}
|
|
});
|
|
}
|
|
|
|
swift!(fn echo_data(data: &SRData) -> SRData);
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_data() {
|
|
test_with_leaks!(|| {
|
|
let str: &str = "hello";
|
|
let bytes = str.as_bytes();
|
|
for _ in 0..10_000 {
|
|
let data = unsafe { echo_data(&bytes.into()) };
|
|
assert_eq!(data.as_slice(), bytes);
|
|
}
|
|
});
|
|
}
|
|
|
|
const DEBUG_PLIST_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict><key>com.apple.security.get-task-allow</key><true/></dict>
|
|
</plist>
|
|
"#;
|