blob: c08e816a015971af5131179817cae74d27082ca7 [file] [log] [blame]
use tokio::sync::{mpsc, oneshot};
use tokio::task;
use tokio_test::{assert_ok, assert_pending, assert_ready};
use futures::future::poll_fn;
use std::task::Poll::Ready;
#[tokio::test]
async fn sync_one_lit_expr_comma() {
let foo = tokio::select! {
foo = async { 1 } => foo,
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn nested_one() {
let foo = tokio::select! {
foo = async { 1 } => tokio::select! {
bar = async { foo } => bar,
},
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn sync_one_lit_expr_no_comma() {
let foo = tokio::select! {
foo = async { 1 } => foo
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn sync_one_lit_expr_block() {
let foo = tokio::select! {
foo = async { 1 } => { foo }
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn sync_one_await() {
let foo = tokio::select! {
foo = one() => foo,
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn sync_one_ident() {
let one = one();
let foo = tokio::select! {
foo = one => foo,
};
assert_eq!(foo, 1);
}
#[tokio::test]
async fn sync_two() {
use std::cell::Cell;
let cnt = Cell::new(0);
let res = tokio::select! {
foo = async {
cnt.set(cnt.get() + 1);
1
} => foo,
bar = async {
cnt.set(cnt.get() + 1);
2
} => bar,
};
assert_eq!(1, cnt.get());
assert!(res == 1 || res == 2);
}
#[tokio::test]
async fn drop_in_fut() {
let s = "hello".to_string();
let res = tokio::select! {
foo = async {
let v = one().await;
drop(s);
v
} => foo
};
assert_eq!(res, 1);
}
#[tokio::test]
async fn one_ready() {
let (tx1, rx1) = oneshot::channel::<i32>();
let (_tx2, rx2) = oneshot::channel::<i32>();
tx1.send(1).unwrap();
let v = tokio::select! {
res = rx1 => {
assert_ok!(res)
},
_ = rx2 => unreachable!(),
};
assert_eq!(1, v);
}
#[tokio::test]
async fn select_streams() {
let (tx1, mut rx1) = mpsc::unbounded_channel::<i32>();
let (tx2, mut rx2) = mpsc::unbounded_channel::<i32>();
tokio::spawn(async move {
assert_ok!(tx2.send(1));
task::yield_now().await;
assert_ok!(tx1.send(2));
task::yield_now().await;
assert_ok!(tx2.send(3));
task::yield_now().await;
drop((tx1, tx2));
});
let mut rem = true;
let mut msgs = vec![];
while rem {
tokio::select! {
Some(x) = rx1.recv() => {
msgs.push(x);
}
Some(y) = rx2.recv() => {
msgs.push(y);
}
else => {
rem = false;
}
}
}
msgs.sort();
assert_eq!(&msgs[..], &[1, 2, 3]);
}
#[tokio::test]
async fn move_uncompleted_futures() {
let (tx1, mut rx1) = oneshot::channel::<i32>();
let (tx2, mut rx2) = oneshot::channel::<i32>();
tx1.send(1).unwrap();
tx2.send(2).unwrap();
let ran;
tokio::select! {
res = &mut rx1 => {
assert_eq!(1, assert_ok!(res));
assert_eq!(2, assert_ok!(rx2.await));
ran = true;
},
res = &mut rx2 => {
assert_eq!(2, assert_ok!(res));
assert_eq!(1, assert_ok!(rx1.await));
ran = true;
},
}
assert!(ran);
}
#[tokio::test]
async fn nested() {
let res = tokio::select! {
x = async { 1 } => {
tokio::select! {
y = async { 2 } => x + y,
}
}
};
assert_eq!(res, 3);
}
#[tokio::test]
async fn struct_size() {
use futures::future;
use std::mem;
let fut = async {
let ready = future::ready(0i32);
tokio::select! {
_ = ready => {},
}
};
assert!(mem::size_of_val(&fut) <= 32);
let fut = async {
let ready1 = future::ready(0i32);
let ready2 = future::ready(0i32);
tokio::select! {
_ = ready1 => {},
_ = ready2 => {},
}
};
assert!(mem::size_of_val(&fut) <= 40);
let fut = async {
let ready1 = future::ready(0i32);
let ready2 = future::ready(0i32);
let ready3 = future::ready(0i32);
tokio::select! {
_ = ready1 => {},
_ = ready2 => {},
_ = ready3 => {},
}
};
assert!(mem::size_of_val(&fut) <= 48);
}
#[tokio::test]
async fn mutable_borrowing_future_with_same_borrow_in_block() {
let mut value = 234;
tokio::select! {
_ = require_mutable(&mut value) => { },
_ = async_noop() => {
value += 5;
},
}
assert!(value >= 234);
}
#[tokio::test]
async fn mutable_borrowing_future_with_same_borrow_in_block_and_else() {
let mut value = 234;
tokio::select! {
_ = require_mutable(&mut value) => { },
_ = async_noop() => {
value += 5;
},
else => {
value += 27;
},
}
assert!(value >= 234);
}
#[tokio::test]
async fn future_panics_after_poll() {
use tokio_test::task;
let (tx, rx) = oneshot::channel();
let mut polled = false;
let f = poll_fn(|_| {
assert!(!polled);
polled = true;
Ready(None::<()>)
});
let mut f = task::spawn(async {
tokio::select! {
Some(_) = f => unreachable!(),
ret = rx => ret.unwrap(),
}
});
assert_pending!(f.poll());
assert_pending!(f.poll());
assert_ok!(tx.send(1));
let res = assert_ready!(f.poll());
assert_eq!(1, res);
}
#[tokio::test]
async fn disable_with_if() {
use tokio_test::task;
let f = poll_fn(|_| panic!());
let (tx, rx) = oneshot::channel();
let mut f = task::spawn(async {
tokio::select! {
_ = f, if false => unreachable!(),
_ = rx => (),
}
});
assert_pending!(f.poll());
assert_ok!(tx.send(()));
assert!(f.is_woken());
assert_ready!(f.poll());
}
#[tokio::test]
async fn join_with_select() {
use tokio_test::task;
let (tx1, mut rx1) = oneshot::channel();
let (tx2, mut rx2) = oneshot::channel();
let mut f = task::spawn(async {
let mut a = None;
let mut b = None;
while a.is_none() || b.is_none() {
tokio::select! {
v1 = &mut rx1, if a.is_none() => a = Some(assert_ok!(v1)),
v2 = &mut rx2, if b.is_none() => b = Some(assert_ok!(v2))
}
}
(a.unwrap(), b.unwrap())
});
assert_pending!(f.poll());
assert_ok!(tx1.send(123));
assert!(f.is_woken());
assert_pending!(f.poll());
assert_ok!(tx2.send(456));
assert!(f.is_woken());
let (a, b) = assert_ready!(f.poll());
assert_eq!(a, 123);
assert_eq!(b, 456);
}
#[tokio::test]
async fn use_future_in_if_condition() {
use tokio::time::{self, Duration};
let mut delay = time::delay_for(Duration::from_millis(50));
tokio::select! {
_ = &mut delay, if !delay.is_elapsed() => {
}
_ = async { 1 } => {
}
}
}
#[tokio::test]
async fn many_branches() {
let num = tokio::select! {
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
x = async { 1 } => x,
};
assert_eq!(1, num);
}
async fn one() -> usize {
1
}
async fn require_mutable(_: &mut i32) {}
async fn async_noop() {}