From 56d0889b37c140404e778ff672c67ea0b9eafa96 Mon Sep 17 00:00:00 2001 From: Callum Leslie Date: Wed, 4 Mar 2026 20:43:15 +0000 Subject: [PATCH] test: increase code coverage of failure paths --- src/sync/std.rs | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/sync/std.rs b/src/sync/std.rs index 8568b98..809d4b7 100644 --- a/src/sync/std.rs +++ b/src/sync/std.rs @@ -77,8 +77,18 @@ impl StdSuck { mod tests { use super::*; use crate::Error; + use crate::sync::traits::ChannelType; use std::thread; + #[derive(Debug)] + struct PanicOnClone; + + impl Clone for PanicOnClone { + fn clone(&self) -> Self { + panic!("intentional panic from Clone"); + } + } + #[test] fn test_pre_computed_value() { let (sucker, sourcer) = StdSuck::::pair(); @@ -218,6 +228,110 @@ mod tests { let _ = producer_handle.join(); } + #[test] + fn test_run_breaks_when_response_receiver_is_dropped() { + let (request_tx, request_rx) = StdChannel::create_request_channel(); + let (response_tx, response_rx) = StdChannel::create_response_channel::(); + drop(response_rx); + + let state = Arc::new(crate::types::ValueSource::None); + let state = ArcSwap::new(state); + let sourcer = crate::Sourcer::new(request_rx, response_tx, state); + sourcer.set_static(42).unwrap(); + + let producer_handle = thread::spawn(move || sourcer.run().unwrap()); + + request_tx.send(crate::types::Request::GetValue).unwrap(); + + producer_handle.join().unwrap(); + } + + #[test] + fn test_run_breaks_when_request_sender_is_dropped() { + let (request_tx, request_rx) = StdChannel::create_request_channel(); + let (response_tx, _response_rx) = StdChannel::create_response_channel::(); + drop(request_tx); + + let state = Arc::new(crate::types::ValueSource::None); + let state = ArcSwap::new(state); + let sourcer = crate::Sourcer::new(request_rx, response_tx, state); + + sourcer.run().unwrap(); + } + + #[test] + fn test_static_source_panic_returns_no_source() { + let (sucker, sourcer) = StdSuck::::pair(); + + let producer_handle = thread::spawn(move || { + sourcer.set_static(PanicOnClone).unwrap(); + sourcer.run().unwrap(); + }); + + let result = sucker.get(); + assert!(matches!(result, Err(Error::NoSource))); + + sucker.close().unwrap(); + producer_handle.join().unwrap(); + } + + #[test] + fn test_dynamic_source_panic_returns_no_source() { + let (sucker, sourcer) = StdSuck::::pair(); + + let producer_handle = thread::spawn(move || { + sourcer + .set(|| -> i32 { + panic!("intentional panic from Fn source"); + }) + .unwrap(); + sourcer.run().unwrap(); + }); + + let result = sucker.get(); + assert!(matches!(result, Err(Error::NoSource))); + + sucker.close().unwrap(); + producer_handle.join().unwrap(); + } + + #[test] + fn test_dynamic_mut_source_panic_returns_no_source() { + let (sucker, sourcer) = StdSuck::::pair(); + + let producer_handle = thread::spawn(move || { + sourcer + .set_mut(|| -> i32 { + panic!("intentional panic from FnMut source"); + }) + .unwrap(); + sourcer.run().unwrap(); + }); + + let result = sucker.get(); + assert!(matches!(result, Err(Error::NoSource))); + + sucker.close().unwrap(); + producer_handle.join().unwrap(); + } + + #[test] + fn test_cleared_source_returns_channel_closed() { + let (sucker, sourcer) = StdSuck::::pair(); + + let producer_handle = thread::spawn(move || { + sourcer.set_static(42).unwrap(); + sourcer.close().unwrap(); + sourcer.run().unwrap(); + }); + + let result = sucker.get(); + assert!(matches!(result, Err(Error::ChannelClosed))); + + sucker.close().unwrap(); + producer_handle.join().unwrap(); + } + #[test] fn test_is_closed() { let (sucker, sourcer) = StdSuck::::pair();