#![cfg(feature = "fancy")]
#![cfg_attr(
feature = "unstable-error-generic-member-access",
feature(error_generic_member_access)
)]
#![allow(
clippy::all,
reason = "integration test fixtures intentionally trip style lints"
)]
mod common;
use oopsie::Diagnostic as _;
use oopsie::{Report, oopsie};
#[oopsie(traced)]
#[oopsie("kaboom: {message}")]
pub struct KaboomError {
message: String,
}
fn fail_deep() -> Result<(), KaboomError> {
Err(KaboomOopsie {
message: "deep failure",
}
.build())
}
#[test]
fn report_run_hides_its_own_plumbing_and_the_runtime_tail() {
common::force_backtrace();
let report = Report::run(fail_deep).no_colors();
let rendered = report.to_string();
assert!(
rendered.contains("fail_deep"),
"user frame missing\n{rendered}"
);
let boundary_lines: Vec<_> = rendered
.lines()
.filter(|line| line.contains("::report::"))
.collect();
assert!(
boundary_lines.len() == 1 && boundary_lines[0].contains("closure"),
"exactly the run-closure boundary frame may be visible, got {boundary_lines:?}\n{rendered}"
);
assert!(
!rendered.contains("catch_unwind"),
"catch_unwind cluster leaked\n{rendered}"
);
assert!(
!rendered.contains("thread_start"),
"frames below Report::run leaked\n{rendered}"
);
}
#[test]
fn start_marker_macro_cuts_in_a_spawned_thread() {
let rendered = std::thread::spawn(|| {
common::force_backtrace();
oopsie::start_marker!();
let err = KaboomOopsie {
message: "in thread",
}
.build();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(
bt.marker_hidden_frames().is_some(),
"exclusive marker must produce a cut on its own thread"
);
Report::new(err).no_colors().to_string()
})
.join()
.unwrap();
assert!(
rendered.contains("start_marker_macro_cuts_in_a_spawned_thread"),
"marker caller frame missing\n{rendered}"
);
assert!(
!rendered.contains("thread_start"),
"thread spawn plumbing leaked\n{rendered}"
);
assert!(
!rendered.contains("::thread::"),
"thread spawn plumbing leaked\n{rendered}"
);
}
#[test]
fn mid_stack_catch_unwind_user_frames_survive() {
fn supervisor() -> KaboomError {
std::panic::catch_unwind(|| {
KaboomOopsie {
message: "inside supervised section",
}
.build()
})
.unwrap()
}
common::force_backtrace();
let rendered = Report::new(supervisor()).no_colors().to_string();
assert!(
rendered.contains("supervisor"),
"user frame below mid-stack catch_unwind was over-trimmed\n{rendered}"
);
}
#[test]
fn report_run_mid_stack_catch_unwind_survives_with_marker() {
common::force_backtrace();
let report = Report::run(|| -> Result<(), KaboomError> {
fn supervised() -> Result<(), KaboomError> {
std::panic::catch_unwind(|| {
Err(KaboomOopsie {
message: "inside guarded section",
}
.build())
})
.unwrap()
}
supervised()
})
.no_colors();
let rendered = report.to_string();
assert!(
rendered.contains("supervised"),
"user frame below mid-stack catch_unwind was over-trimmed\n{rendered}"
);
let boundary_lines: Vec<_> = rendered
.lines()
.filter(|line| line.contains("::report::"))
.collect();
assert!(
boundary_lines.len() == 1 && boundary_lines[0].contains("closure"),
"exactly the run-closure boundary frame may be visible, got {boundary_lines:?}\n{rendered}"
);
}
#[test]
fn marker_from_another_thread_never_applies() {
common::force_backtrace();
oopsie::start_marker!();
let err = std::thread::spawn(|| {
common::force_backtrace();
KaboomOopsie {
message: "cross-thread",
}
.build()
})
.join()
.unwrap();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(bt.marker_hidden_frames().is_none());
}
#[test]
fn report_run_restores_previous_marker_on_return() {
common::force_backtrace();
oopsie::start_marker!();
let _ = Report::run(fail_deep);
let err = KaboomOopsie {
message: "after run",
}
.build();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(bt.marker_hidden_frames().is_some());
}
#[test]
fn report_run_restores_previous_marker_on_unwind() {
common::force_backtrace();
oopsie::start_marker!();
let payload = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _ = Report::run(|| -> Result<(), KaboomError> {
panic!("boom through run");
});
}));
assert!(payload.is_err());
let err = KaboomOopsie {
message: "after unwound run",
}
.build();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(bt.marker_hidden_frames().is_some());
}
#[test]
fn full_backtrace_bypasses_marker_on_error_path() {
oopsie::backtrace::with_override(oopsie::RustBacktrace::Full, || {
let rendered = Report::run(fail_deep).no_colors().to_string();
assert!(
rendered.contains("catch_unwind"),
"full mode must show the unwind plumbing the marker hides\n{rendered}"
);
});
}
#[test]
fn report_run_leaves_no_marker_on_a_clean_thread() {
std::thread::spawn(|| {
common::force_backtrace();
let _ = Report::run(fail_deep);
let err = KaboomOopsie {
message: "after clean run",
}
.build();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(bt.marker_hidden_frames().is_none());
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _ = Report::run(|| -> Result<(), KaboomError> { panic!("boom") });
}));
let err = KaboomOopsie {
message: "after unwound clean run",
}
.build();
let bt = err
.oopsie_backtrace()
.expect("traced error has a backtrace");
assert!(bt.marker_hidden_frames().is_none());
})
.join()
.unwrap();
}
#[test]
fn generated_selector_frames_are_hidden() {
common::force_backtrace();
let err = KaboomOopsie {
message: "generated frames",
}
.build();
let rendered = Report::new(err).no_colors().to_string();
let first = rendered
.lines()
.find(|line| line.trim_start().starts_with("1:"))
.expect("a first frame");
assert!(
first.contains("generated_selector_frames_are_hidden"),
"{rendered}"
);
assert!(!rendered.contains("kaboom_oopsies"), "{rendered}");
}