use std::thread;
pub struct Pill {}
impl Pill {
#[allow(dead_code)]
pub fn new() -> Self {
Self {}
}
}
impl Drop for Pill {
fn drop(&mut self) {
if thread::panicking() {
panic!("Child thread panicked - propagating panic to parent thread");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::mpsc;
use std::thread;
#[test]
fn test_pill_does_not_panic_in_normal_case() {
{
let _pill = Pill::new();
}
assert!(true, "Pill should not panic when dropped normally");
}
#[test]
fn test_pill_propagates_panic() {
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
let pill = Pill::new();
sender.send(pill).unwrap();
panic!("Intentional panic in child thread");
});
let pill = receiver.recv().unwrap();
let result = handle.join();
assert!(result.is_err(), "Thread should have panicked");
drop(pill);
}
#[test]
fn test_catch_unwind_pill_panic() {
use std::panic;
let result = panic::catch_unwind(|| {
panic!("Initial panic");
});
assert!(result.is_err(), "Expected panic");
let is_panicking = thread::panicking();
assert!(!is_panicking, "Should not be in panic state here");
}
#[test]
fn test_pill_usage_in_typical_pattern() {
let (sender, receiver) = mpsc::channel();
let worker = thread::spawn(move || {
let _pill = Pill::new();
sender.send("Work completed successfully").unwrap();
});
let result = receiver.recv().unwrap();
assert_eq!(result, "Work completed successfully");
worker.join().unwrap();
}
}