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