use crate::CALC_APP;
use crate::common::TestInfo;
use crate::common::{TestHooks, rust_version};
use crate::{HW_APP, RECURSION_APP, VARS_APP, assert_no_proc, prepare_debugee_process};
use bugstalker::debugger::variable::value::{SupportedScalar, Value};
use bugstalker::debugger::{Debugger, DebuggerBuilder};
use bugstalker::ui::command::parser::expression;
use bugstalker::version_switch;
use chumsky::Parser;
use serial_test::serial;
use std::mem;
#[test]
#[serial]
fn test_step_into() {
let process = prepare_debugee_process(CALC_APP, &["1", "2", "3", "--description", "result"]);
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("main.rs", 10).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(10));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(25));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(21));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(22));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(26));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(21));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(22));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(27));
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(15));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_into_recursion() {
let process = prepare_debugee_process(RECURSION_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_fn("infinite_inc").unwrap();
fn assert_arg(debugger: &Debugger, expected: u64) {
let get_i_expr = expression::parser().parse("i").unwrap();
let i_arg = debugger.read_argument(get_i_expr).unwrap().pop().unwrap();
let Value::Scalar(scalar) = i_arg.into_value() else {
panic!("not a scalar");
};
assert_eq!(scalar.value, Some(SupportedScalar::U64(expected)));
}
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(11));
assert_arg(&debugger, 1);
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(11));
assert_arg(&debugger, 2);
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(11));
assert_arg(&debugger, 3);
debugger.step_into().unwrap();
assert_eq!(info.line.take(), Some(11));
assert_arg(&debugger, 4);
mem::drop(debugger);
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_out() {
let process = prepare_debugee_process(HW_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_fn("main").unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(5));
let rust_version = rust_version(HW_APP).unwrap();
let step_count = version_switch!(
rust_version,
.. (1 . 81) => 4,
(1 . 81) .. (1 . 85) => 5,
(1 . 85) .. => 1,
)
.unwrap();
for _ in 0..step_count {
debugger.step_into().unwrap();
}
assert_eq!(info.line.take(), Some(15));
debugger.step_out().unwrap();
assert_eq!(info.line.take(), Some(7));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_over() {
let process = prepare_debugee_process(HW_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_fn("main").unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(5));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(7));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(9));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(10));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_over_inline_code() {
let process = prepare_debugee_process(VARS_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("vars.rs", 545).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(545));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(546));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_over_on_fn_decl() {
let process = prepare_debugee_process(HW_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("hello_world.rs", 14)
.unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(14));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(15));
debugger.continue_debugee().unwrap();
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}
#[test]
#[serial]
fn test_step_over_for_loop_issue_156() {
let process = prepare_debugee_process(VARS_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("vars.rs", 358).unwrap();
debugger.start_debugee().unwrap();
assert_eq!(info.line.take(), Some(358));
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(358));
for _ in 0..100 {
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(359));
}
debugger.step_over().unwrap();
assert_eq!(info.line.take(), Some(363));
debugger.continue_debugee().unwrap();
assert_no_proc!(debugee_pid);
}