blob: b9aef47f50d2cc93a14fd06a1b6a9ad2bf7c3299 [file] [log] [blame]
extern crate backtrace;
extern crate cpp_smoke_test;
use std::sync::atomic::{AtomicBool, Ordering};
extern "C" {
fn cpp_trampoline(func: extern "C" fn()) -> ();
}
#[test]
#[ignore] // fixme(fitzgen/cpp_demangle#73)
fn smoke_test_cpp() {
static RAN_ASSERTS: AtomicBool = AtomicBool::new(false);
extern "C" fn assert_cpp_frames() {
let mut physical_frames = Vec::new();
backtrace::trace(|cx| {
physical_frames.push(cx.ip());
// We only want to capture this closure's frame, assert_cpp_frames,
// space::templated_trampoline, and cpp_trampoline. Those are
// logical frames, which might be inlined into fewer physical
// frames, so we may end up with extra logical frames after
// resolving these.
physical_frames.len() < 4
});
let names: Vec<_> = physical_frames
.into_iter()
.flat_map(|ip| {
let mut logical_frame_names = vec![];
backtrace::resolve(ip, |sym| {
let sym_name = sym.name().expect("Should have a symbol name");
let demangled = sym_name.to_string();
logical_frame_names.push(demangled);
});
assert!(
!logical_frame_names.is_empty(),
"Should have resolved at least one symbol for the physical frame"
);
logical_frame_names
})
// Skip the backtrace::trace closure and assert_cpp_frames, and then
// take the two C++ frame names.
.skip_while(|name| !name.contains("trampoline"))
.take(2)
.collect();
println!("actual names = {:#?}", names);
let expected = [
"void space::templated_trampoline<void (*)()>(void (*)())",
"cpp_trampoline",
];
println!("expected names = {:#?}", expected);
assert_eq!(names.len(), expected.len());
for (actual, expected) in names.iter().zip(expected.iter()) {
assert_eq!(actual, expected);
}
RAN_ASSERTS.store(true, Ordering::SeqCst);
}
assert!(!RAN_ASSERTS.load(Ordering::SeqCst));
unsafe {
cpp_trampoline(assert_cpp_frames);
}
assert!(RAN_ASSERTS.load(Ordering::SeqCst));
}