| use core::mem; |
| use oneshot::TryRecvError; |
| |
| #[cfg(feature = "std")] |
| use oneshot::{RecvError, RecvTimeoutError}; |
| #[cfg(feature = "std")] |
| use std::time::{Duration, Instant}; |
| |
| #[cfg(feature = "std")] |
| mod thread { |
| #[cfg(loom)] |
| pub use loom::thread::spawn; |
| #[cfg(not(loom))] |
| pub use std::thread::{sleep, spawn}; |
| |
| #[cfg(loom)] |
| pub fn sleep(_timeout: core::time::Duration) { |
| loom::thread::yield_now() |
| } |
| } |
| |
| mod helpers; |
| use helpers::{maybe_loom_model, DropCounter}; |
| |
| #[test] |
| fn send_before_try_recv() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| assert!(sender.send(19i128).is_ok()); |
| |
| assert_eq!(receiver.try_recv(), Ok(19i128)); |
| assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected)); |
| #[cfg(feature = "std")] |
| { |
| assert_eq!(receiver.recv_ref(), Err(RecvError)); |
| assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err()); |
| } |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn send_before_recv() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<()>(); |
| assert!(sender.send(()).is_ok()); |
| assert_eq!(receiver.recv(), Ok(())); |
| }); |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u8>(); |
| assert!(sender.send(19).is_ok()); |
| assert_eq!(receiver.recv(), Ok(19)); |
| }); |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u64>(); |
| assert!(sender.send(21).is_ok()); |
| assert_eq!(receiver.recv(), Ok(21)); |
| }); |
| // FIXME: This test does not work with loom. There is something that happens after the |
| // channel object becomes larger than ~500 bytes and that makes an atomic read from the state |
| // result in "signal: 10, SIGBUS: access to undefined memory" |
| #[cfg(not(loom))] |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<[u8; 4096]>(); |
| assert!(sender.send([0b10101010; 4096]).is_ok()); |
| assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]); |
| }); |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn send_before_recv_ref() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| assert!(sender.send(19i128).is_ok()); |
| |
| assert_eq!(receiver.recv_ref(), Ok(19i128)); |
| assert_eq!(receiver.recv_ref(), Err(RecvError)); |
| assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected)); |
| assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err()); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn send_before_recv_timeout() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| assert!(sender.send(19i128).is_ok()); |
| |
| let start = Instant::now(); |
| let timeout = Duration::from_secs(1); |
| assert_eq!(receiver.recv_timeout(timeout), Ok(19i128)); |
| assert!(start.elapsed() < Duration::from_millis(100)); |
| |
| assert!(receiver.recv_timeout(timeout).is_err()); |
| assert!(receiver.try_recv().is_err()); |
| assert!(receiver.recv().is_err()); |
| }) |
| } |
| |
| #[test] |
| fn send_then_drop_receiver() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| assert!(sender.send(19i128).is_ok()); |
| mem::drop(receiver); |
| }) |
| } |
| |
| #[test] |
| fn send_with_dropped_receiver() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| mem::drop(receiver); |
| let send_error = sender.send(5u128).unwrap_err(); |
| assert_eq!(*send_error.as_inner(), 5); |
| assert_eq!(send_error.into_inner(), 5); |
| }) |
| } |
| |
| #[test] |
| fn try_recv_with_dropped_sender() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| mem::drop(sender); |
| receiver.try_recv().unwrap_err(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_with_dropped_sender() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| mem::drop(sender); |
| receiver.recv().unwrap_err(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_before_send() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| let t = thread::spawn(move || { |
| thread::sleep(Duration::from_millis(2)); |
| sender.send(9u128).unwrap(); |
| }); |
| assert_eq!(receiver.recv(), Ok(9)); |
| t.join().unwrap(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_timeout_before_send() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| let t = thread::spawn(move || { |
| thread::sleep(Duration::from_millis(2)); |
| sender.send(9u128).unwrap(); |
| }); |
| assert_eq!(receiver.recv_timeout(Duration::from_secs(1)), Ok(9)); |
| t.join().unwrap(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_before_send_then_drop_sender() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| let t = thread::spawn(move || { |
| thread::sleep(Duration::from_millis(10)); |
| mem::drop(sender); |
| }); |
| assert!(receiver.recv().is_err()); |
| t.join().unwrap(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_timeout_before_send_then_drop_sender() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| let t = thread::spawn(move || { |
| thread::sleep(Duration::from_millis(10)); |
| mem::drop(sender); |
| }); |
| assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err()); |
| t.join().unwrap(); |
| }) |
| } |
| |
| #[test] |
| fn try_recv() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty)); |
| mem::drop(sender) |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn try_recv_then_drop_receiver() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel::<u128>(); |
| let t1 = thread::spawn(move || { |
| let _ = sender.send(42); |
| }); |
| let t2 = thread::spawn(move || { |
| assert!(matches!( |
| receiver.try_recv(), |
| Ok(42) | Err(TryRecvError::Empty) |
| )); |
| mem::drop(receiver); |
| }); |
| t1.join().unwrap(); |
| t2.join().unwrap(); |
| }) |
| } |
| |
| #[cfg(feature = "std")] |
| #[test] |
| fn recv_deadline_and_timeout_no_time() { |
| maybe_loom_model(|| { |
| let (_sender, receiver) = oneshot::channel::<u128>(); |
| |
| let start = Instant::now(); |
| assert_eq!( |
| receiver.recv_deadline(start), |
| Err(RecvTimeoutError::Timeout) |
| ); |
| assert!(start.elapsed() < Duration::from_millis(200)); |
| |
| let start = Instant::now(); |
| assert_eq!( |
| receiver.recv_timeout(Duration::from_millis(0)), |
| Err(RecvTimeoutError::Timeout) |
| ); |
| assert!(start.elapsed() < Duration::from_millis(200)); |
| }) |
| } |
| |
| // This test doesn't give meaningful results when run with oneshot_test_delay and loom |
| #[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))] |
| #[test] |
| fn recv_deadline_time_should_elapse() { |
| maybe_loom_model(|| { |
| let (_sender, receiver) = oneshot::channel::<u128>(); |
| |
| let start = Instant::now(); |
| #[cfg(not(loom))] |
| let timeout = Duration::from_millis(100); |
| #[cfg(loom)] |
| let timeout = Duration::from_millis(1); |
| assert_eq!( |
| receiver.recv_deadline(start + timeout), |
| Err(RecvTimeoutError::Timeout) |
| ); |
| assert!(start.elapsed() > timeout); |
| assert!(start.elapsed() < timeout * 3); |
| }) |
| } |
| |
| #[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))] |
| #[test] |
| fn recv_timeout_time_should_elapse() { |
| maybe_loom_model(|| { |
| let (_sender, receiver) = oneshot::channel::<u128>(); |
| |
| let start = Instant::now(); |
| #[cfg(not(loom))] |
| let timeout = Duration::from_millis(100); |
| #[cfg(loom)] |
| let timeout = Duration::from_millis(1); |
| |
| assert_eq!( |
| receiver.recv_timeout(timeout), |
| Err(RecvTimeoutError::Timeout) |
| ); |
| assert!(start.elapsed() > timeout); |
| assert!(start.elapsed() < timeout * 3); |
| }) |
| } |
| |
| #[cfg(not(loom))] |
| #[test] |
| fn non_send_type_can_be_used_on_same_thread() { |
| use std::ptr; |
| |
| #[derive(Debug, Eq, PartialEq)] |
| struct NotSend(*mut ()); |
| |
| let (sender, receiver) = oneshot::channel(); |
| sender.send(NotSend(ptr::null_mut())).unwrap(); |
| let reply = receiver.try_recv().unwrap(); |
| assert_eq!(reply, NotSend(ptr::null_mut())); |
| } |
| |
| #[test] |
| fn message_in_channel_dropped_on_receiver_drop() { |
| maybe_loom_model(|| { |
| let (sender, receiver) = oneshot::channel(); |
| let (message, counter) = DropCounter::new(()); |
| assert_eq!(counter.count(), 0); |
| sender.send(message).unwrap(); |
| assert_eq!(counter.count(), 0); |
| mem::drop(receiver); |
| assert_eq!(counter.count(), 1); |
| }) |
| } |
| |
| #[test] |
| fn send_error_drops_message_correctly() { |
| maybe_loom_model(|| { |
| let (sender, _) = oneshot::channel(); |
| let (message, counter) = DropCounter::new(()); |
| |
| let send_error = sender.send(message).unwrap_err(); |
| assert_eq!(counter.count(), 0); |
| mem::drop(send_error); |
| assert_eq!(counter.count(), 1); |
| }); |
| } |
| |
| #[test] |
| fn send_error_drops_message_correctly_on_into_inner() { |
| maybe_loom_model(|| { |
| let (sender, _) = oneshot::channel(); |
| let (message, counter) = DropCounter::new(()); |
| |
| let send_error = sender.send(message).unwrap_err(); |
| assert_eq!(counter.count(), 0); |
| let message = send_error.into_inner(); |
| assert_eq!(counter.count(), 0); |
| mem::drop(message); |
| assert_eq!(counter.count(), 1); |
| }); |
| } |