1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// ---------------- [ File: src/backtrace_guard.rs ]
crate::ix!();
impl TracedTestGenerator {
/// Defines (via code generation) the `BacktraceGuard` type and its helpers, now accepting the
/// additional `enable_backtrace: bool` parameter to fix the two-argument call.
pub fn define_backtrace_guard(&self) -> TokenStream2 {
quote! {
#[derive(Debug)]
enum BacktraceMode {
Disabled,
Enabled,
Full,
}
impl BacktraceMode {
pub fn from_env() -> Self {
match std::env::var("RUST_BACKTRACE").as_deref() {
Ok("1") => BacktraceMode::Enabled,
Ok("full") => BacktraceMode::Full,
_ => BacktraceMode::Disabled,
}
}
}
#[derive(Debug)]
struct BacktraceGuard {
previous_rust_backtrace_value: BacktraceMode,
test_name: String,
enable_backtrace: bool,
}
impl BacktraceGuard {
/// Constructor for BacktraceGuard that sets
/// the previous backtrace state, then (if `enable_backtrace`
/// is false) updates RUST_BACKTRACE to "0" to disable it.
///
/// This fixes the mismatch so that code can call:
/// `BacktraceGuard::new("test_name".to_string(), <bool>)`.
fn new(test_name: String, enable_backtrace: bool) -> Self {
tracing::debug!(
%test_name,
%enable_backtrace,
"Creating new BacktraceGuard"
);
let previous_rust_backtrace_value = BacktraceMode::from_env();
if !enable_backtrace {
tracing::info!(
"Disabling RUST_BACKTRACE for test: {}",
test_name
);
std::env::set_var("RUST_BACKTRACE", "0");
}
BacktraceGuard {
previous_rust_backtrace_value,
test_name,
enable_backtrace,
}
}
pub fn maybe_print_backtrace(&self) {
match self.previous_rust_backtrace_value {
BacktraceMode::Enabled | BacktraceMode::Full => {
self.print_backtrace();
}
BacktraceMode::Disabled => {}
}
}
pub fn print_backtrace(&self) {
let header = format!(
"===== Backtrace for test: {} =====",
self.test_name
);
let backtrace = format!(
"{:#?}",
std::backtrace::Backtrace::force_capture()
);
tracing::debug!("Printing backtrace header...");
println!("{}", header.bright_black());
println!("{}", backtrace.bright_black());
}
/// Restore the previous RUST_BACKTRACE value
pub fn restore_previous_rust_backtrace_value(&self) {
match &self.previous_rust_backtrace_value {
BacktraceMode::Enabled => {
tracing::trace!(
"Restoring RUST_BACKTRACE to '1' after test: {}",
self.test_name
);
std::env::set_var("RUST_BACKTRACE", "1");
}
BacktraceMode::Full => {
tracing::trace!(
"Restoring RUST_BACKTRACE to 'full' after test: {}",
self.test_name
);
std::env::set_var("RUST_BACKTRACE", "full");
}
BacktraceMode::Disabled => {
tracing::trace!(
"RUST_BACKTRACE was disabled; resetting to '0' after test: {}",
self.test_name
);
std::env::set_var("RUST_BACKTRACE", "0");
}
}
}
}
impl Drop for BacktraceGuard {
fn drop(&mut self) {
if std::thread::panicking() {
if self.enable_backtrace {
tracing::debug!(
"Panic detected; printing backtrace for test: {}",
self.test_name
);
self.maybe_print_backtrace();
} else {
tracing::debug!(
"Panic detected, but `enable_backtrace` is false; skipping backtrace."
);
}
}
self.restore_previous_rust_backtrace_value();
}
}
}
}
}