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