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