blob: c6ba081c6679d21190eaed96785d300cf5fe957e [file] [log] [blame]
James Farrell11eb3fc2024-10-11 15:41:14 +00001use core::mem;
2use oneshot::TryRecvError;
3
4#[cfg(feature = "std")]
5use oneshot::{RecvError, RecvTimeoutError};
6#[cfg(feature = "std")]
7use std::time::{Duration, Instant};
8
9#[cfg(feature = "std")]
10mod 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)]
17 pub fn sleep(_timeout: core::time::Duration) {
18 loom::thread::yield_now()
19 }
20}
21
22mod helpers;
23use helpers::{maybe_loom_model, DropCounter};
24
25#[test]
26fn 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]
43fn 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]
72fn 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]
86fn 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]
103fn 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]
112fn 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]
123fn 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]
133fn 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]
143fn 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]
157fn 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]
171fn 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]
185fn 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]
198fn 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]
208fn 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]
228fn 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]
251fn 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]
271fn 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]
292fn 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]
305fn 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]
318fn 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]
331fn 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}