#[cfg(test)] mod tests { use std::path::Path; use backtrace::Backtrace; use libc::c_void; pub type Callback = extern "C" fn(data: *mut c_void); extern "C" { fn foo(cb: Callback, data: *mut c_void); } extern "C" fn store_backtrace(data: *mut c_void) { let bt = backtrace::Backtrace::new(); unsafe { *(data as *mut Option) = Some(bt) }; } fn assert_contains(backtrace: &Backtrace, expected_name: &str, expected_file: &str, expected_line: u32) { let expected_file = Path::new(expected_file); for frame in backtrace.frames() { for symbol in frame.symbols() { if let Some(name) = symbol.name() { if name.as_bytes() == expected_name.as_bytes() { assert!(symbol.filename().unwrap().ends_with(expected_file)); assert_eq!(symbol.lineno(), Some(expected_line)); return; } } } } panic!("symbol {:?} not found in backtrace: {:?}", expected_name, backtrace); } /// Verifies that when debug info includes only lines tables the generated /// backtrace is still generated successfully. The test exercises behaviour /// that failed previously when compiling with clang -g1. /// /// The test case uses C rather than rust, since at that time when it was /// written the debug info generated at level 1 in rustc was essentially /// the same as at level 2. #[test] #[cfg_attr(windows, ignore)] fn backtrace_works_with_line_tables_only() { let mut backtrace: Option = None; unsafe { foo(store_backtrace, &mut backtrace as *mut _ as *mut c_void) }; let backtrace = backtrace.expect("backtrace"); assert_contains(&backtrace, "foo", "src/callback.c", 13); assert_contains(&backtrace, "bar", "src/callback.c", 9); assert_contains(&backtrace, "baz", "src/callback.c", 5); } }