1#![cfg(feature = "macros")]
2#![allow(clippy::disallowed_names)]
3
4#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
5use wasm_bindgen_test::wasm_bindgen_test as maybe_tokio_test;
6
7#[cfg(not(all(target_family = "wasm", not(target_os = "wasi"))))]
8use tokio::test as maybe_tokio_test;
9
10use tokio::sync::oneshot;
11use tokio_test::{assert_ok, assert_pending, assert_ready};
12
13use futures::future::poll_fn;
14use std::task::Poll::Ready;
15
16#[maybe_tokio_test]
17async 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]
26async 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]
37async 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]
46async 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]
55async 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]
64async 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]
75async 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]
96async 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")]
112async 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")]
130async 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]
171async 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]
197async 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")]
210mod pointer_64_tests {
211 use super::maybe_tokio_test;
212 use futures::future;
213 use std::mem;
214
215 #[maybe_tokio_test]
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]
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]
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]
262async 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]
276async 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]
293async 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]
323async 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]
345async 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")]
381async 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")]
395async 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]
409async 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]
481async 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
489async fn one() -> usize {
490 1
491}
492
493async fn require_mutable(_: &mut i32) {}
494async fn async_noop() {}
495
496async fn async_never() -> ! {
497 futures::future::pending().await
498}
499
500// From https://github.com/tokio-rs/tokio/issues/2857
501#[maybe_tokio_test]
502async 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]
518async 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")]
543async 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)]
580pub 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]
589async 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)]
614mod unstable {
615 use tokio::runtime::RngSeed;
616
617 #[test]
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")))]
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
660 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