1 #![allow(unknown_lints, unexpected_cfgs)]
2 #![cfg(feature = "macros")]
3 #![allow(clippy::disallowed_names)]
4 
5 #[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
6 use wasm_bindgen_test::wasm_bindgen_test as maybe_tokio_test;
7 
8 #[cfg(not(all(target_family = "wasm", not(target_os = "wasi"))))]
9 use tokio::test as maybe_tokio_test;
10 
11 use tokio::sync::oneshot;
12 use tokio_test::{assert_ok, assert_pending, assert_ready};
13 
14 use std::future::poll_fn;
15 use std::task::Poll::Ready;
16 
17 #[maybe_tokio_test]
sync_one_lit_expr_comma()18 async fn sync_one_lit_expr_comma() {
19     let foo = tokio::select! {
20         foo = async { 1 } => foo,
21     };
22 
23     assert_eq!(foo, 1);
24 }
25 
26 #[maybe_tokio_test]
no_branch_else_only()27 async fn no_branch_else_only() {
28     let foo = tokio::select! {
29         else => 1,
30     };
31 
32     assert_eq!(foo, 1);
33 }
34 
35 #[maybe_tokio_test]
no_branch_else_only_biased()36 async fn no_branch_else_only_biased() {
37     let foo = tokio::select! {
38         biased;
39         else => 1,
40     };
41 
42     assert_eq!(foo, 1);
43 }
44 
45 #[maybe_tokio_test]
nested_one()46 async fn nested_one() {
47     let foo = tokio::select! {
48         foo = async { 1 } => tokio::select! {
49             bar = async { foo } => bar,
50         },
51     };
52 
53     assert_eq!(foo, 1);
54 }
55 
56 #[maybe_tokio_test]
sync_one_lit_expr_no_comma()57 async fn sync_one_lit_expr_no_comma() {
58     let foo = tokio::select! {
59         foo = async { 1 } => foo
60     };
61 
62     assert_eq!(foo, 1);
63 }
64 
65 #[maybe_tokio_test]
sync_one_lit_expr_block()66 async fn sync_one_lit_expr_block() {
67     let foo = tokio::select! {
68         foo = async { 1 } => { foo }
69     };
70 
71     assert_eq!(foo, 1);
72 }
73 
74 #[maybe_tokio_test]
sync_one_await()75 async fn sync_one_await() {
76     let foo = tokio::select! {
77         foo = one() => foo,
78     };
79 
80     assert_eq!(foo, 1);
81 }
82 
83 #[maybe_tokio_test]
sync_one_ident()84 async fn sync_one_ident() {
85     let one = one();
86 
87     let foo = tokio::select! {
88         foo = one => foo,
89     };
90 
91     assert_eq!(foo, 1);
92 }
93 
94 #[maybe_tokio_test]
sync_two()95 async fn sync_two() {
96     use std::cell::Cell;
97 
98     let cnt = Cell::new(0);
99 
100     let res = tokio::select! {
101         foo = async {
102             cnt.set(cnt.get() + 1);
103             1
104         } => foo,
105         bar = async {
106             cnt.set(cnt.get() + 1);
107             2
108         } => bar,
109     };
110 
111     assert_eq!(1, cnt.get());
112     assert!(res == 1 || res == 2);
113 }
114 
115 #[maybe_tokio_test]
drop_in_fut()116 async fn drop_in_fut() {
117     let s = "hello".to_string();
118 
119     let res = tokio::select! {
120         foo = async {
121             let v = one().await;
122             drop(s);
123             v
124         } => foo
125     };
126 
127     assert_eq!(res, 1);
128 }
129 
130 #[maybe_tokio_test]
131 #[cfg(feature = "full")]
one_ready()132 async fn one_ready() {
133     let (tx1, rx1) = oneshot::channel::<i32>();
134     let (_tx2, rx2) = oneshot::channel::<i32>();
135 
136     tx1.send(1).unwrap();
137 
138     let v = tokio::select! {
139         res = rx1 => {
140             assert_ok!(res)
141         },
142         _ = rx2 => unreachable!(),
143     };
144 
145     assert_eq!(1, v);
146 }
147 
148 #[maybe_tokio_test]
149 #[cfg(feature = "full")]
select_streams()150 async fn select_streams() {
151     use tokio::sync::mpsc;
152 
153     let (tx1, mut rx1) = mpsc::unbounded_channel::<i32>();
154     let (tx2, mut rx2) = mpsc::unbounded_channel::<i32>();
155 
156     tokio::spawn(async move {
157         assert_ok!(tx2.send(1));
158         tokio::task::yield_now().await;
159 
160         assert_ok!(tx1.send(2));
161         tokio::task::yield_now().await;
162 
163         assert_ok!(tx2.send(3));
164         tokio::task::yield_now().await;
165 
166         drop((tx1, tx2));
167     });
168 
169     let mut rem = true;
170     let mut msgs = vec![];
171 
172     while rem {
173         tokio::select! {
174             Some(x) = rx1.recv() => {
175                 msgs.push(x);
176             }
177             Some(y) = rx2.recv() => {
178                 msgs.push(y);
179             }
180             else => {
181                 rem = false;
182             }
183         }
184     }
185 
186     msgs.sort_unstable();
187     assert_eq!(&msgs[..], &[1, 2, 3]);
188 }
189 
190 #[maybe_tokio_test]
move_uncompleted_futures()191 async fn move_uncompleted_futures() {
192     let (tx1, mut rx1) = oneshot::channel::<i32>();
193     let (tx2, mut rx2) = oneshot::channel::<i32>();
194 
195     tx1.send(1).unwrap();
196     tx2.send(2).unwrap();
197 
198     let ran;
199 
200     tokio::select! {
201         res = &mut rx1 => {
202             assert_eq!(1, assert_ok!(res));
203             assert_eq!(2, assert_ok!(rx2.await));
204             ran = true;
205         },
206         res = &mut rx2 => {
207             assert_eq!(2, assert_ok!(res));
208             assert_eq!(1, assert_ok!(rx1.await));
209             ran = true;
210         },
211     }
212 
213     assert!(ran);
214 }
215 
216 #[maybe_tokio_test]
nested()217 async fn nested() {
218     let res = tokio::select! {
219         x = async { 1 } => {
220             tokio::select! {
221                 y = async { 2 } => x + y,
222             }
223         }
224     };
225 
226     assert_eq!(res, 3);
227 }
228 
229 #[cfg(target_pointer_width = "64")]
230 mod pointer_64_tests {
231     use super::maybe_tokio_test;
232     use futures::future;
233     use std::mem;
234 
235     #[maybe_tokio_test]
struct_size_1()236     async fn struct_size_1() {
237         let fut = async {
238             let ready = future::ready(0i32);
239 
240             tokio::select! {
241                 _ = ready => {},
242             }
243         };
244 
245         assert_eq!(mem::size_of_val(&fut), 32);
246     }
247 
248     #[maybe_tokio_test]
struct_size_2()249     async fn struct_size_2() {
250         let fut = async {
251             let ready1 = future::ready(0i32);
252             let ready2 = future::ready(0i32);
253 
254             tokio::select! {
255                 _ = ready1 => {},
256                 _ = ready2 => {},
257             }
258         };
259 
260         assert_eq!(mem::size_of_val(&fut), 40);
261     }
262 
263     #[maybe_tokio_test]
struct_size_3()264     async fn struct_size_3() {
265         let fut = async {
266             let ready1 = future::ready(0i32);
267             let ready2 = future::ready(0i32);
268             let ready3 = future::ready(0i32);
269 
270             tokio::select! {
271                 _ = ready1 => {},
272                 _ = ready2 => {},
273                 _ = ready3 => {},
274             }
275         };
276 
277         assert_eq!(mem::size_of_val(&fut), 48);
278     }
279 }
280 
281 #[maybe_tokio_test]
mutable_borrowing_future_with_same_borrow_in_block()282 async fn mutable_borrowing_future_with_same_borrow_in_block() {
283     let mut value = 234;
284 
285     tokio::select! {
286         _ = require_mutable(&mut value) => { },
287         _ = async_noop() => {
288             value += 5;
289         },
290     }
291 
292     assert!(value >= 234);
293 }
294 
295 #[maybe_tokio_test]
mutable_borrowing_future_with_same_borrow_in_block_and_else()296 async fn mutable_borrowing_future_with_same_borrow_in_block_and_else() {
297     let mut value = 234;
298 
299     tokio::select! {
300         _ = require_mutable(&mut value) => { },
301         _ = async_noop() => {
302             value += 5;
303         },
304         else => {
305             value += 27;
306         },
307     }
308 
309     assert!(value >= 234);
310 }
311 
312 #[maybe_tokio_test]
future_panics_after_poll()313 async fn future_panics_after_poll() {
314     use tokio_test::task;
315 
316     let (tx, rx) = oneshot::channel();
317 
318     let mut polled = false;
319 
320     let f = poll_fn(|_| {
321         assert!(!polled);
322         polled = true;
323         Ready(None::<()>)
324     });
325 
326     let mut f = task::spawn(async {
327         tokio::select! {
328             Some(_) = f => unreachable!(),
329             ret = rx => ret.unwrap(),
330         }
331     });
332 
333     assert_pending!(f.poll());
334     assert_pending!(f.poll());
335 
336     assert_ok!(tx.send(1));
337 
338     let res = assert_ready!(f.poll());
339     assert_eq!(1, res);
340 }
341 
342 #[maybe_tokio_test]
disable_with_if()343 async fn disable_with_if() {
344     use tokio_test::task;
345 
346     let f = poll_fn(|_| panic!());
347     let (tx, rx) = oneshot::channel();
348 
349     let mut f = task::spawn(async {
350         tokio::select! {
351             _ = f, if false => unreachable!(),
352             _ = rx => (),
353         }
354     });
355 
356     assert_pending!(f.poll());
357 
358     assert_ok!(tx.send(()));
359     assert!(f.is_woken());
360 
361     assert_ready!(f.poll());
362 }
363 
364 #[maybe_tokio_test]
join_with_select()365 async fn join_with_select() {
366     use tokio_test::task;
367 
368     let (tx1, mut rx1) = oneshot::channel();
369     let (tx2, mut rx2) = oneshot::channel();
370 
371     let mut f = task::spawn(async {
372         let mut a = None;
373         let mut b = None;
374 
375         while a.is_none() || b.is_none() {
376             tokio::select! {
377                 v1 = &mut rx1, if a.is_none() => a = Some(assert_ok!(v1)),
378                 v2 = &mut rx2, if b.is_none() => b = Some(assert_ok!(v2))
379             }
380         }
381 
382         (a.unwrap(), b.unwrap())
383     });
384 
385     assert_pending!(f.poll());
386 
387     assert_ok!(tx1.send(123));
388     assert!(f.is_woken());
389     assert_pending!(f.poll());
390 
391     assert_ok!(tx2.send(456));
392     assert!(f.is_woken());
393     let (a, b) = assert_ready!(f.poll());
394 
395     assert_eq!(a, 123);
396     assert_eq!(b, 456);
397 }
398 
399 #[tokio::test]
400 #[cfg(feature = "full")]
use_future_in_if_condition()401 async fn use_future_in_if_condition() {
402     use tokio::time::{self, Duration};
403 
404     tokio::select! {
405         _ = time::sleep(Duration::from_millis(10)), if false => {
406             panic!("if condition ignored")
407         }
408         _ = async { 1u32 } => {
409         }
410     }
411 }
412 
413 #[tokio::test]
414 #[cfg(feature = "full")]
use_future_in_if_condition_biased()415 async fn use_future_in_if_condition_biased() {
416     use tokio::time::{self, Duration};
417 
418     tokio::select! {
419         biased;
420         _ = time::sleep(Duration::from_millis(10)), if false => {
421             panic!("if condition ignored")
422         }
423         _ = async { 1u32 } => {
424         }
425     }
426 }
427 
428 #[maybe_tokio_test]
many_branches()429 async fn many_branches() {
430     let num = tokio::select! {
431         x = async { 1 } => x,
432         x = async { 1 } => x,
433         x = async { 1 } => x,
434         x = async { 1 } => x,
435         x = async { 1 } => x,
436         x = async { 1 } => x,
437         x = async { 1 } => x,
438         x = async { 1 } => x,
439         x = async { 1 } => x,
440         x = async { 1 } => x,
441         x = async { 1 } => x,
442         x = async { 1 } => x,
443         x = async { 1 } => x,
444         x = async { 1 } => x,
445         x = async { 1 } => x,
446         x = async { 1 } => x,
447         x = async { 1 } => x,
448         x = async { 1 } => x,
449         x = async { 1 } => x,
450         x = async { 1 } => x,
451         x = async { 1 } => x,
452         x = async { 1 } => x,
453         x = async { 1 } => x,
454         x = async { 1 } => x,
455         x = async { 1 } => x,
456         x = async { 1 } => x,
457         x = async { 1 } => x,
458         x = async { 1 } => x,
459         x = async { 1 } => x,
460         x = async { 1 } => x,
461         x = async { 1 } => x,
462         x = async { 1 } => x,
463         x = async { 1 } => x,
464         x = async { 1 } => x,
465         x = async { 1 } => x,
466         x = async { 1 } => x,
467         x = async { 1 } => x,
468         x = async { 1 } => x,
469         x = async { 1 } => x,
470         x = async { 1 } => x,
471         x = async { 1 } => x,
472         x = async { 1 } => x,
473         x = async { 1 } => x,
474         x = async { 1 } => x,
475         x = async { 1 } => x,
476         x = async { 1 } => x,
477         x = async { 1 } => x,
478         x = async { 1 } => x,
479         x = async { 1 } => x,
480         x = async { 1 } => x,
481         x = async { 1 } => x,
482         x = async { 1 } => x,
483         x = async { 1 } => x,
484         x = async { 1 } => x,
485         x = async { 1 } => x,
486         x = async { 1 } => x,
487         x = async { 1 } => x,
488         x = async { 1 } => x,
489         x = async { 1 } => x,
490         x = async { 1 } => x,
491         x = async { 1 } => x,
492         x = async { 1 } => x,
493         x = async { 1 } => x,
494         x = async { 1 } => x,
495     };
496 
497     assert_eq!(1, num);
498 }
499 
500 #[maybe_tokio_test]
never_branch_no_warnings()501 async fn never_branch_no_warnings() {
502     let t = tokio::select! {
503         _ = async_never() => 0,
504         one_async_ready = one() => one_async_ready,
505     };
506     assert_eq!(t, 1);
507 }
508 
one() -> usize509 async fn one() -> usize {
510     1
511 }
512 
require_mutable(_: &mut i32)513 async fn require_mutable(_: &mut i32) {}
async_noop()514 async fn async_noop() {}
515 
async_never() -> !516 async fn async_never() -> ! {
517     futures::future::pending().await
518 }
519 
520 // From https://github.com/tokio-rs/tokio/issues/2857
521 #[maybe_tokio_test]
mut_on_left_hand_side()522 async fn mut_on_left_hand_side() {
523     let v = async move {
524         let ok = async { 1 };
525         tokio::pin!(ok);
526         tokio::select! {
527             mut a = &mut ok => {
528                 a += 1;
529                 a
530             }
531         }
532     }
533     .await;
534     assert_eq!(v, 2);
535 }
536 
537 #[maybe_tokio_test]
biased_one_not_ready()538 async fn biased_one_not_ready() {
539     let (_tx1, rx1) = oneshot::channel::<i32>();
540     let (tx2, rx2) = oneshot::channel::<i32>();
541     let (tx3, rx3) = oneshot::channel::<i32>();
542 
543     tx2.send(2).unwrap();
544     tx3.send(3).unwrap();
545 
546     let v = tokio::select! {
547         biased;
548 
549         _ = rx1 => unreachable!(),
550         res = rx2 => {
551             assert_ok!(res)
552         },
553         _ = rx3 => {
554             panic!("This branch should never be activated because `rx2` should be polled before `rx3` due to `biased;`.")
555         }
556     };
557 
558     assert_eq!(2, v);
559 }
560 
561 #[maybe_tokio_test]
562 #[cfg(feature = "full")]
biased_eventually_ready()563 async fn biased_eventually_ready() {
564     use tokio::task::yield_now;
565 
566     let one = async {};
567     let two = async { yield_now().await };
568     let three = async { yield_now().await };
569 
570     let mut count = 0u8;
571 
572     tokio::pin!(one, two, three);
573 
574     loop {
575         tokio::select! {
576             biased;
577 
578             _ = &mut two, if count < 2 => {
579                 count += 1;
580                 assert_eq!(count, 2);
581             }
582             _ = &mut three, if count < 3 => {
583                 count += 1;
584                 assert_eq!(count, 3);
585             }
586             _ = &mut one, if count < 1 => {
587                 count += 1;
588                 assert_eq!(count, 1);
589             }
590             else => break,
591         }
592     }
593 
594     assert_eq!(count, 3);
595 }
596 
597 // https://github.com/tokio-rs/tokio/issues/3830
598 // https://github.com/rust-lang/rust-clippy/issues/7304
599 #[warn(clippy::default_numeric_fallback)]
default_numeric_fallback()600 pub async fn default_numeric_fallback() {
601     tokio::select! {
602         _ = async {} => (),
603         else => (),
604     }
605 }
606 
607 // https://github.com/tokio-rs/tokio/issues/4182
608 #[maybe_tokio_test]
mut_ref_patterns()609 async fn mut_ref_patterns() {
610     tokio::select! {
611         Some(mut foo) = async { Some("1".to_string()) } => {
612             assert_eq!(foo, "1");
613             foo = "2".to_string();
614             assert_eq!(foo, "2");
615         },
616     };
617 
618     tokio::select! {
619         Some(ref foo) = async { Some("1".to_string()) } => {
620             assert_eq!(*foo, "1");
621         },
622     };
623 
624     tokio::select! {
625         Some(ref mut foo) = async { Some("1".to_string()) } => {
626             assert_eq!(*foo, "1");
627             *foo = "2".to_string();
628             assert_eq!(*foo, "2");
629         },
630     };
631 }
632 
633 #[cfg(tokio_unstable)]
634 mod unstable {
635     use tokio::runtime::RngSeed;
636 
637     #[test]
deterministic_select_current_thread()638     fn deterministic_select_current_thread() {
639         let seed = b"bytes used to generate seed";
640         let rt1 = tokio::runtime::Builder::new_current_thread()
641             .rng_seed(RngSeed::from_bytes(seed))
642             .build()
643             .unwrap();
644         let rt1_values = rt1.block_on(async { (select_0_to_9().await, select_0_to_9().await) });
645 
646         let rt2 = tokio::runtime::Builder::new_current_thread()
647             .rng_seed(RngSeed::from_bytes(seed))
648             .build()
649             .unwrap();
650         let rt2_values = rt2.block_on(async { (select_0_to_9().await, select_0_to_9().await) });
651 
652         assert_eq!(rt1_values, rt2_values);
653     }
654 
655     #[test]
656     #[cfg(all(feature = "rt-multi-thread", not(target_os = "wasi")))]
deterministic_select_multi_thread()657     fn deterministic_select_multi_thread() {
658         let seed = b"bytes used to generate seed";
659         let rt1 = tokio::runtime::Builder::new_multi_thread()
660             .worker_threads(1)
661             .rng_seed(RngSeed::from_bytes(seed))
662             .build()
663             .unwrap();
664         let rt1_values = rt1.block_on(async {
665             let _ = tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) }).await;
666         });
667 
668         let rt2 = tokio::runtime::Builder::new_multi_thread()
669             .worker_threads(1)
670             .rng_seed(RngSeed::from_bytes(seed))
671             .build()
672             .unwrap();
673         let rt2_values = rt2.block_on(async {
674             let _ = tokio::spawn(async { (select_0_to_9().await, select_0_to_9().await) }).await;
675         });
676 
677         assert_eq!(rt1_values, rt2_values);
678     }
679 
select_0_to_9() -> u32680     async fn select_0_to_9() -> u32 {
681         tokio::select!(
682             x = async { 0 } => x,
683             x = async { 1 } => x,
684             x = async { 2 } => x,
685             x = async { 3 } => x,
686             x = async { 4 } => x,
687             x = async { 5 } => x,
688             x = async { 6 } => x,
689             x = async { 7 } => x,
690             x = async { 8 } => x,
691             x = async { 9 } => x,
692         )
693     }
694 }
695 
696 #[tokio::test]
select_into_future()697 async fn select_into_future() {
698     struct NotAFuture;
699     impl std::future::IntoFuture for NotAFuture {
700         type Output = ();
701         type IntoFuture = std::future::Ready<()>;
702 
703         fn into_future(self) -> Self::IntoFuture {
704             std::future::ready(())
705         }
706     }
707 
708     tokio::select! {
709         () = NotAFuture => {},
710     }
711 }
712 
713 // regression test for https://github.com/tokio-rs/tokio/issues/6721
714 #[tokio::test]
temporary_lifetime_extension()715 async fn temporary_lifetime_extension() {
716     tokio::select! {
717         () = &mut std::future::ready(()) => {},
718     }
719 }
720