1 #![warn(rust_2018_idioms)] 2 #![cfg(all(feature = "time", not(target_os = "wasi")))] // Wasi does not support panic recovery 3 4 use parking_lot::{const_mutex, Mutex}; 5 use std::error::Error; 6 use std::panic; 7 use std::sync::Arc; 8 use tokio::time::Duration; 9 use tokio_stream::{self as stream, StreamExt}; 10 test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String>11fn test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String> { 12 static PANIC_MUTEX: Mutex<()> = const_mutex(()); 13 14 { 15 let _guard = PANIC_MUTEX.lock(); 16 let panic_file: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None)); 17 18 let prev_hook = panic::take_hook(); 19 { 20 let panic_file = panic_file.clone(); 21 panic::set_hook(Box::new(move |panic_info| { 22 let panic_location = panic_info.location().unwrap(); 23 panic_file 24 .lock() 25 .clone_from(&Some(panic_location.file().to_string())); 26 })); 27 } 28 29 let result = panic::catch_unwind(func); 30 // Return to the previously set panic hook (maybe default) so that we get nice error 31 // messages in the tests. 32 panic::set_hook(prev_hook); 33 34 if result.is_err() { 35 panic_file.lock().clone() 36 } else { 37 None 38 } 39 } 40 } 41 42 #[test] stream_chunks_timeout_panic_caller() -> Result<(), Box<dyn Error>>43fn stream_chunks_timeout_panic_caller() -> Result<(), Box<dyn Error>> { 44 let panic_location_file = test_panic(|| { 45 let iter = vec![1, 2, 3].into_iter(); 46 let stream0 = stream::iter(iter); 47 48 let _chunk_stream = stream0.chunks_timeout(0, Duration::from_secs(2)); 49 }); 50 51 // The panic location should be in this file 52 assert_eq!(&panic_location_file.unwrap(), file!()); 53 54 Ok(()) 55 } 56