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