1 use core::mem;
2 use oneshot::TryRecvError;
3 
4 #[cfg(feature = "std")]
5 use oneshot::{RecvError, RecvTimeoutError};
6 #[cfg(feature = "std")]
7 use std::time::{Duration, Instant};
8 
9 #[cfg(feature = "std")]
10 mod thread {
11     #[cfg(loom)]
12     pub use loom::thread::spawn;
13     #[cfg(not(loom))]
14     pub use std::thread::{sleep, spawn};
15 
16     #[cfg(loom)]
sleep(_timeout: core::time::Duration)17     pub fn sleep(_timeout: core::time::Duration) {
18         loom::thread::yield_now()
19     }
20 }
21 
22 mod helpers;
23 use helpers::{maybe_loom_model, DropCounter};
24 
25 #[test]
send_before_try_recv()26 fn send_before_try_recv() {
27     maybe_loom_model(|| {
28         let (sender, receiver) = oneshot::channel();
29         assert!(sender.send(19i128).is_ok());
30 
31         assert_eq!(receiver.try_recv(), Ok(19i128));
32         assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
33         #[cfg(feature = "std")]
34         {
35             assert_eq!(receiver.recv_ref(), Err(RecvError));
36             assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
37         }
38     })
39 }
40 
41 #[cfg(feature = "std")]
42 #[test]
send_before_recv()43 fn send_before_recv() {
44     maybe_loom_model(|| {
45         let (sender, receiver) = oneshot::channel::<()>();
46         assert!(sender.send(()).is_ok());
47         assert_eq!(receiver.recv(), Ok(()));
48     });
49     maybe_loom_model(|| {
50         let (sender, receiver) = oneshot::channel::<u8>();
51         assert!(sender.send(19).is_ok());
52         assert_eq!(receiver.recv(), Ok(19));
53     });
54     maybe_loom_model(|| {
55         let (sender, receiver) = oneshot::channel::<u64>();
56         assert!(sender.send(21).is_ok());
57         assert_eq!(receiver.recv(), Ok(21));
58     });
59     // FIXME: This test does not work with loom. There is something that happens after the
60     // channel object becomes larger than ~500 bytes and that makes an atomic read from the state
61     // result in "signal: 10, SIGBUS: access to undefined memory"
62     #[cfg(not(loom))]
63     maybe_loom_model(|| {
64         let (sender, receiver) = oneshot::channel::<[u8; 4096]>();
65         assert!(sender.send([0b10101010; 4096]).is_ok());
66         assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]);
67     });
68 }
69 
70 #[cfg(feature = "std")]
71 #[test]
send_before_recv_ref()72 fn send_before_recv_ref() {
73     maybe_loom_model(|| {
74         let (sender, receiver) = oneshot::channel();
75         assert!(sender.send(19i128).is_ok());
76 
77         assert_eq!(receiver.recv_ref(), Ok(19i128));
78         assert_eq!(receiver.recv_ref(), Err(RecvError));
79         assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
80         assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
81     })
82 }
83 
84 #[cfg(feature = "std")]
85 #[test]
send_before_recv_timeout()86 fn send_before_recv_timeout() {
87     maybe_loom_model(|| {
88         let (sender, receiver) = oneshot::channel();
89         assert!(sender.send(19i128).is_ok());
90 
91         let start = Instant::now();
92         let timeout = Duration::from_secs(1);
93         assert_eq!(receiver.recv_timeout(timeout), Ok(19i128));
94         assert!(start.elapsed() < Duration::from_millis(100));
95 
96         assert!(receiver.recv_timeout(timeout).is_err());
97         assert!(receiver.try_recv().is_err());
98         assert!(receiver.recv().is_err());
99     })
100 }
101 
102 #[test]
send_then_drop_receiver()103 fn send_then_drop_receiver() {
104     maybe_loom_model(|| {
105         let (sender, receiver) = oneshot::channel();
106         assert!(sender.send(19i128).is_ok());
107         mem::drop(receiver);
108     })
109 }
110 
111 #[test]
send_with_dropped_receiver()112 fn send_with_dropped_receiver() {
113     maybe_loom_model(|| {
114         let (sender, receiver) = oneshot::channel();
115         mem::drop(receiver);
116         let send_error = sender.send(5u128).unwrap_err();
117         assert_eq!(*send_error.as_inner(), 5);
118         assert_eq!(send_error.into_inner(), 5);
119     })
120 }
121 
122 #[test]
try_recv_with_dropped_sender()123 fn try_recv_with_dropped_sender() {
124     maybe_loom_model(|| {
125         let (sender, receiver) = oneshot::channel::<u128>();
126         mem::drop(sender);
127         receiver.try_recv().unwrap_err();
128     })
129 }
130 
131 #[cfg(feature = "std")]
132 #[test]
recv_with_dropped_sender()133 fn recv_with_dropped_sender() {
134     maybe_loom_model(|| {
135         let (sender, receiver) = oneshot::channel::<u128>();
136         mem::drop(sender);
137         receiver.recv().unwrap_err();
138     })
139 }
140 
141 #[cfg(feature = "std")]
142 #[test]
recv_before_send()143 fn recv_before_send() {
144     maybe_loom_model(|| {
145         let (sender, receiver) = oneshot::channel();
146         let t = thread::spawn(move || {
147             thread::sleep(Duration::from_millis(2));
148             sender.send(9u128).unwrap();
149         });
150         assert_eq!(receiver.recv(), Ok(9));
151         t.join().unwrap();
152     })
153 }
154 
155 #[cfg(feature = "std")]
156 #[test]
recv_timeout_before_send()157 fn recv_timeout_before_send() {
158     maybe_loom_model(|| {
159         let (sender, receiver) = oneshot::channel();
160         let t = thread::spawn(move || {
161             thread::sleep(Duration::from_millis(2));
162             sender.send(9u128).unwrap();
163         });
164         assert_eq!(receiver.recv_timeout(Duration::from_secs(1)), Ok(9));
165         t.join().unwrap();
166     })
167 }
168 
169 #[cfg(feature = "std")]
170 #[test]
recv_before_send_then_drop_sender()171 fn recv_before_send_then_drop_sender() {
172     maybe_loom_model(|| {
173         let (sender, receiver) = oneshot::channel::<u128>();
174         let t = thread::spawn(move || {
175             thread::sleep(Duration::from_millis(10));
176             mem::drop(sender);
177         });
178         assert!(receiver.recv().is_err());
179         t.join().unwrap();
180     })
181 }
182 
183 #[cfg(feature = "std")]
184 #[test]
recv_timeout_before_send_then_drop_sender()185 fn recv_timeout_before_send_then_drop_sender() {
186     maybe_loom_model(|| {
187         let (sender, receiver) = oneshot::channel::<u128>();
188         let t = thread::spawn(move || {
189             thread::sleep(Duration::from_millis(10));
190             mem::drop(sender);
191         });
192         assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
193         t.join().unwrap();
194     })
195 }
196 
197 #[test]
try_recv()198 fn try_recv() {
199     maybe_loom_model(|| {
200         let (sender, receiver) = oneshot::channel::<u128>();
201         assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
202         mem::drop(sender)
203     })
204 }
205 
206 #[cfg(feature = "std")]
207 #[test]
try_recv_then_drop_receiver()208 fn try_recv_then_drop_receiver() {
209     maybe_loom_model(|| {
210         let (sender, receiver) = oneshot::channel::<u128>();
211         let t1 = thread::spawn(move || {
212             let _ = sender.send(42);
213         });
214         let t2 = thread::spawn(move || {
215             assert!(matches!(
216                 receiver.try_recv(),
217                 Ok(42) | Err(TryRecvError::Empty)
218             ));
219             mem::drop(receiver);
220         });
221         t1.join().unwrap();
222         t2.join().unwrap();
223     })
224 }
225 
226 #[cfg(feature = "std")]
227 #[test]
recv_deadline_and_timeout_no_time()228 fn recv_deadline_and_timeout_no_time() {
229     maybe_loom_model(|| {
230         let (_sender, receiver) = oneshot::channel::<u128>();
231 
232         let start = Instant::now();
233         assert_eq!(
234             receiver.recv_deadline(start),
235             Err(RecvTimeoutError::Timeout)
236         );
237         assert!(start.elapsed() < Duration::from_millis(200));
238 
239         let start = Instant::now();
240         assert_eq!(
241             receiver.recv_timeout(Duration::from_millis(0)),
242             Err(RecvTimeoutError::Timeout)
243         );
244         assert!(start.elapsed() < Duration::from_millis(200));
245     })
246 }
247 
248 // This test doesn't give meaningful results when run with oneshot_test_delay and loom
249 #[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
250 #[test]
recv_deadline_time_should_elapse()251 fn recv_deadline_time_should_elapse() {
252     maybe_loom_model(|| {
253         let (_sender, receiver) = oneshot::channel::<u128>();
254 
255         let start = Instant::now();
256         #[cfg(not(loom))]
257         let timeout = Duration::from_millis(100);
258         #[cfg(loom)]
259         let timeout = Duration::from_millis(1);
260         assert_eq!(
261             receiver.recv_deadline(start + timeout),
262             Err(RecvTimeoutError::Timeout)
263         );
264         assert!(start.elapsed() > timeout);
265         assert!(start.elapsed() < timeout * 3);
266     })
267 }
268 
269 #[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
270 #[test]
recv_timeout_time_should_elapse()271 fn recv_timeout_time_should_elapse() {
272     maybe_loom_model(|| {
273         let (_sender, receiver) = oneshot::channel::<u128>();
274 
275         let start = Instant::now();
276         #[cfg(not(loom))]
277         let timeout = Duration::from_millis(100);
278         #[cfg(loom)]
279         let timeout = Duration::from_millis(1);
280 
281         assert_eq!(
282             receiver.recv_timeout(timeout),
283             Err(RecvTimeoutError::Timeout)
284         );
285         assert!(start.elapsed() > timeout);
286         assert!(start.elapsed() < timeout * 3);
287     })
288 }
289 
290 #[cfg(not(loom))]
291 #[test]
non_send_type_can_be_used_on_same_thread()292 fn non_send_type_can_be_used_on_same_thread() {
293     use std::ptr;
294 
295     #[derive(Debug, Eq, PartialEq)]
296     struct NotSend(*mut ());
297 
298     let (sender, receiver) = oneshot::channel();
299     sender.send(NotSend(ptr::null_mut())).unwrap();
300     let reply = receiver.try_recv().unwrap();
301     assert_eq!(reply, NotSend(ptr::null_mut()));
302 }
303 
304 #[test]
message_in_channel_dropped_on_receiver_drop()305 fn message_in_channel_dropped_on_receiver_drop() {
306     maybe_loom_model(|| {
307         let (sender, receiver) = oneshot::channel();
308         let (message, counter) = DropCounter::new(());
309         assert_eq!(counter.count(), 0);
310         sender.send(message).unwrap();
311         assert_eq!(counter.count(), 0);
312         mem::drop(receiver);
313         assert_eq!(counter.count(), 1);
314     })
315 }
316 
317 #[test]
send_error_drops_message_correctly()318 fn send_error_drops_message_correctly() {
319     maybe_loom_model(|| {
320         let (sender, _) = oneshot::channel();
321         let (message, counter) = DropCounter::new(());
322 
323         let send_error = sender.send(message).unwrap_err();
324         assert_eq!(counter.count(), 0);
325         mem::drop(send_error);
326         assert_eq!(counter.count(), 1);
327     });
328 }
329 
330 #[test]
send_error_drops_message_correctly_on_into_inner()331 fn send_error_drops_message_correctly_on_into_inner() {
332     maybe_loom_model(|| {
333         let (sender, _) = oneshot::channel();
334         let (message, counter) = DropCounter::new(());
335 
336         let send_error = sender.send(message).unwrap_err();
337         assert_eq!(counter.count(), 0);
338         let message = send_error.into_inner();
339         assert_eq!(counter.count(), 0);
340         mem::drop(message);
341         assert_eq!(counter.count(), 1);
342     });
343 }
344