use crate::common::{TestHooks, TestInfo, wait_for_stop_line};
use crate::prepare_debugee_process;
use crate::{MT_APP, assert_no_proc};
use bugstalker::debugger::DebuggerBuilder;
use bugstalker::debugger::unwind::Backtrace;
use itertools::Itertools;
use serial_test::serial;
use std::ffi::OsStr;
#[test]
#[serial]
fn test_multithreaded_app_running() {
let process = prepare_debugee_process(MT_APP, &[]);
let debugee_pid = process.pid();
let builder = DebuggerBuilder::new().with_hooks(TestHooks::default());
let mut debugger = builder.build(process).unwrap();
debugger.start_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_multithreaded_breakpoints() {
let process = prepare_debugee_process(MT_APP, &[]);
let debugee_pid = process.pid();
let info = TestInfo::default();
let builder = DebuggerBuilder::new().with_hooks(TestHooks::new(info.clone()));
let mut debugger = builder.build(process).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 6).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 24).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 36).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 14).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(wait_for_stop_line(&info, 6, 5), 6);
debugger.continue_debugee().unwrap();
assert_eq!(wait_for_stop_line(&info, 36, 5), 36);
debugger.continue_debugee().unwrap();
assert_eq!(wait_for_stop_line(&info, 24, 5), 24);
debugger.continue_debugee().unwrap();
assert_eq!(info.line.take(), Some(14));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
fn backtrace_contains_fn(backtrace: &Backtrace, f_name: &str) -> bool {
backtrace.iter().any(|frame| {
frame
.func_name
.as_ref()
.map(|f| f.contains(f_name))
.unwrap_or(false)
})
}
#[test]
#[serial]
fn test_multithreaded_backtrace() {
let process = prepare_debugee_process(MT_APP, &[]);
let debugee_pid = process.pid();
let info = TestInfo::default();
let builder = DebuggerBuilder::new().with_hooks(TestHooks::new(info.clone()));
let mut debugger = builder.build(process).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 24).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(24));
let threads = debugger.thread_state().unwrap();
let current_thread = threads.into_iter().find(|t| t.in_focus).unwrap();
let current_place = current_thread.place.unwrap();
assert!(current_place.file.iter().contains(&OsStr::new("mt.rs")));
assert_eq!(current_place.line_number, 24);
let bt = debugger.backtrace(current_thread.thread.pid).unwrap();
assert_eq!(bt[0].func_name.as_ref().unwrap(), "mt::sum1");
assert!(backtrace_contains_fn(&bt, "new::thread_start"));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_multithreaded_trace() {
let process = prepare_debugee_process(MT_APP, &[]);
let debugee_pid = process.pid();
let info = TestInfo::default();
let builder = DebuggerBuilder::new().with_hooks(TestHooks::new(info.clone()));
let mut debugger = builder.build(process).unwrap();
debugger.set_breakpoint_at_line("mt.rs", 23).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(23));
let trace = debugger.thread_state().unwrap();
assert_eq!(trace.len(), 5);
trace
.iter()
.any(|thread| backtrace_contains_fn(thread.bt.as_ref().unwrap(), "mt::main"));
trace
.iter()
.any(|thread| backtrace_contains_fn(thread.bt.as_ref().unwrap(), "std::thread::sleep"));
trace
.iter()
.any(|thread| backtrace_contains_fn(thread.bt.as_ref().unwrap(), "mt::sum2"));
trace
.iter()
.any(|thread| backtrace_contains_fn(thread.bt.as_ref().unwrap(), "mt::sum3"));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}