summaryrefslogtreecommitdiffstats
path: root/third_party/rust/oneshot-uniffi/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/oneshot-uniffi/tests
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/oneshot-uniffi/tests')
-rw-r--r--third_party/rust/oneshot-uniffi/tests/assert_mem.rs37
-rw-r--r--third_party/rust/oneshot-uniffi/tests/async.rs128
-rw-r--r--third_party/rust/oneshot-uniffi/tests/future.rs65
-rw-r--r--third_party/rust/oneshot-uniffi/tests/helpers/mod.rs63
-rw-r--r--third_party/rust/oneshot-uniffi/tests/helpers/waker.rs64
-rw-r--r--third_party/rust/oneshot-uniffi/tests/loom.rs223
-rw-r--r--third_party/rust/oneshot-uniffi/tests/sync.rs343
7 files changed, 923 insertions, 0 deletions
diff --git a/third_party/rust/oneshot-uniffi/tests/assert_mem.rs b/third_party/rust/oneshot-uniffi/tests/assert_mem.rs
new file mode 100644
index 0000000000..a993ad715a
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/assert_mem.rs
@@ -0,0 +1,37 @@
+use oneshot::{Receiver, Sender};
+use std::mem;
+
+/// Just sanity check that both channel endpoints stay the size of a single pointer.
+#[test]
+fn channel_endpoints_single_pointer() {
+ const PTR_SIZE: usize = mem::size_of::<*const ()>();
+
+ assert_eq!(mem::size_of::<Sender<()>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<Receiver<()>>(), PTR_SIZE);
+
+ assert_eq!(mem::size_of::<Sender<u8>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<Receiver<u8>>(), PTR_SIZE);
+
+ assert_eq!(mem::size_of::<Sender<[u8; 1024]>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<Receiver<[u8; 1024]>>(), PTR_SIZE);
+
+ assert_eq!(mem::size_of::<Option<Sender<[u8; 1024]>>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<Option<Receiver<[u8; 1024]>>>(), PTR_SIZE);
+}
+
+/// Check that the `SendError` stays small. Useful to automatically detect if it is refactored
+/// to become large. We do not want the stack requirement for calling `Sender::send` to grow.
+#[test]
+fn error_sizes() {
+ const PTR_SIZE: usize = mem::size_of::<usize>();
+
+ assert_eq!(mem::size_of::<oneshot::SendError<()>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<oneshot::SendError<u8>>(), PTR_SIZE);
+ assert_eq!(mem::size_of::<oneshot::SendError<[u8; 1024]>>(), PTR_SIZE);
+
+ // The type returned from `Sender::send` is also just pointer sized
+ assert_eq!(
+ mem::size_of::<Result<(), oneshot::SendError<[u8; 1024]>>>(),
+ PTR_SIZE
+ );
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/async.rs b/third_party/rust/oneshot-uniffi/tests/async.rs
new file mode 100644
index 0000000000..e7633aad82
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/async.rs
@@ -0,0 +1,128 @@
+#![cfg(all(feature = "async", not(loom)))]
+
+use core::mem;
+use core::time::Duration;
+
+mod helpers;
+use helpers::DropCounter;
+
+#[tokio::test]
+async fn send_before_await_tokio() {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+ assert_eq!(receiver.await, Ok(19i128));
+}
+
+#[async_std::test]
+async fn send_before_await_async_std() {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+ assert_eq!(receiver.await, Ok(19i128));
+}
+
+#[tokio::test]
+async fn await_with_dropped_sender_tokio() {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.await.unwrap_err();
+}
+
+#[async_std::test]
+async fn await_with_dropped_sender_async_std() {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.await.unwrap_err();
+}
+
+#[tokio::test]
+async fn await_before_send_tokio() {
+ let (sender, receiver) = oneshot::channel();
+ let (message, counter) = DropCounter::new(79u128);
+ let t = tokio::spawn(async move {
+ tokio::time::sleep(Duration::from_millis(10)).await;
+ sender.send(message)
+ });
+ let returned_message = receiver.await.unwrap();
+ assert_eq!(counter.count(), 0);
+ assert_eq!(*returned_message.value(), 79u128);
+ mem::drop(returned_message);
+ assert_eq!(counter.count(), 1);
+ t.await.unwrap().unwrap();
+}
+
+#[async_std::test]
+async fn await_before_send_async_std() {
+ let (sender, receiver) = oneshot::channel();
+ let (message, counter) = DropCounter::new(79u128);
+ let t = async_std::task::spawn(async move {
+ async_std::task::sleep(Duration::from_millis(10)).await;
+ sender.send(message)
+ });
+ let returned_message = receiver.await.unwrap();
+ assert_eq!(counter.count(), 0);
+ assert_eq!(*returned_message.value(), 79u128);
+ mem::drop(returned_message);
+ assert_eq!(counter.count(), 1);
+ t.await.unwrap();
+}
+
+#[tokio::test]
+async fn await_before_send_then_drop_sender_tokio() {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = tokio::spawn(async {
+ tokio::time::sleep(Duration::from_millis(10)).await;
+ mem::drop(sender);
+ });
+ assert!(receiver.await.is_err());
+ t.await.unwrap();
+}
+
+#[async_std::test]
+async fn await_before_send_then_drop_sender_async_std() {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = async_std::task::spawn(async {
+ async_std::task::sleep(Duration::from_millis(10)).await;
+ mem::drop(sender);
+ });
+ assert!(receiver.await.is_err());
+ t.await;
+}
+
+// Tests that the Receiver handles being used synchronously even after being polled
+#[tokio::test]
+async fn poll_future_and_then_try_recv() {
+ use core::future::Future;
+ use core::pin::Pin;
+ use core::task::{self, Poll};
+
+ struct StupidReceiverFuture(oneshot::Receiver<()>);
+
+ impl Future for StupidReceiverFuture {
+ type Output = Result<(), oneshot::RecvError>;
+
+ fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
+ let poll_result = Future::poll(Pin::new(&mut self.0), cx);
+ self.0.try_recv().expect_err("Should never be a message");
+ poll_result
+ }
+ }
+
+ let (sender, receiver) = oneshot::channel();
+ let t = tokio::spawn(async {
+ tokio::time::sleep(Duration::from_millis(20)).await;
+ mem::drop(sender);
+ });
+ StupidReceiverFuture(receiver).await.unwrap_err();
+ t.await.unwrap();
+}
+
+#[tokio::test]
+async fn poll_receiver_then_drop_it() {
+ let (sender, receiver) = oneshot::channel::<()>();
+ // This will poll the receiver and then give up after 100 ms.
+ tokio::time::timeout(Duration::from_millis(100), receiver)
+ .await
+ .unwrap_err();
+ // Make sure the receiver has been dropped by the runtime.
+ assert!(sender.send(()).is_err());
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/future.rs b/third_party/rust/oneshot-uniffi/tests/future.rs
new file mode 100644
index 0000000000..3895946bec
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/future.rs
@@ -0,0 +1,65 @@
+#![cfg(feature = "async")]
+
+use core::{future, mem, pin, task};
+
+#[cfg(loom)]
+pub use loom::sync::{Arc, Mutex};
+#[cfg(not(loom))]
+pub use std::sync::{Arc, Mutex};
+
+mod helpers;
+use helpers::maybe_loom_model;
+
+#[test]
+fn multiple_receiver_polls_keeps_only_latest_waker() {
+ #[derive(Default)]
+ struct MockWaker {
+ cloned: usize,
+ dropped: usize,
+ }
+
+ fn clone_mock_waker(waker: *const ()) -> task::RawWaker {
+ let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex<MockWaker>) };
+ mock_waker.lock().unwrap().cloned += 1;
+ let new_waker =
+ task::RawWaker::new(Arc::into_raw(mock_waker.clone()) as *const (), &VTABLE);
+ mem::forget(mock_waker);
+ new_waker
+ }
+
+ fn drop_mock_waker(waker: *const ()) {
+ let mock_waker = unsafe { Arc::from_raw(waker as *const Mutex<MockWaker>) };
+ mock_waker.lock().unwrap().dropped += 1;
+ }
+
+ const VTABLE: task::RawWakerVTable =
+ task::RawWakerVTable::new(clone_mock_waker, |_| (), |_| (), drop_mock_waker);
+
+ maybe_loom_model(|| {
+ let mock_waker1 = Arc::new(Mutex::new(MockWaker::default()));
+ let raw_waker1 =
+ task::RawWaker::new(Arc::into_raw(mock_waker1.clone()) as *const (), &VTABLE);
+ let waker1 = unsafe { task::Waker::from_raw(raw_waker1) };
+ let mut context1 = task::Context::from_waker(&waker1);
+
+ let (_sender, mut receiver) = oneshot::channel::<()>();
+
+ let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context1);
+ assert_eq!(poll_result, task::Poll::Pending);
+ assert_eq!(mock_waker1.lock().unwrap().cloned, 1);
+ assert_eq!(mock_waker1.lock().unwrap().dropped, 0);
+
+ let mock_waker2 = Arc::new(Mutex::new(MockWaker::default()));
+ let raw_waker2 =
+ task::RawWaker::new(Arc::into_raw(mock_waker2.clone()) as *const (), &VTABLE);
+ let waker2 = unsafe { task::Waker::from_raw(raw_waker2) };
+ let mut context2 = task::Context::from_waker(&waker2);
+
+ let poll_result = future::Future::poll(pin::Pin::new(&mut receiver), &mut context2);
+ assert_eq!(poll_result, task::Poll::Pending);
+ assert_eq!(mock_waker2.lock().unwrap().cloned, 1);
+ assert_eq!(mock_waker2.lock().unwrap().dropped, 0);
+ assert_eq!(mock_waker1.lock().unwrap().cloned, 1);
+ assert_eq!(mock_waker1.lock().unwrap().dropped, 1);
+ });
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/helpers/mod.rs b/third_party/rust/oneshot-uniffi/tests/helpers/mod.rs
new file mode 100644
index 0000000000..1b145396e7
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/helpers/mod.rs
@@ -0,0 +1,63 @@
+#![allow(dead_code)]
+
+extern crate alloc;
+
+#[cfg(not(loom))]
+use alloc::sync::Arc;
+#[cfg(not(loom))]
+use core::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+#[cfg(loom)]
+use loom::sync::{
+ atomic::{AtomicUsize, Ordering::SeqCst},
+ Arc,
+};
+
+#[cfg(loom)]
+pub mod waker;
+
+pub fn maybe_loom_model(test: impl Fn() + Sync + Send + 'static) {
+ #[cfg(loom)]
+ loom::model(test);
+ #[cfg(not(loom))]
+ test();
+}
+
+pub struct DropCounter<T> {
+ drop_count: Arc<AtomicUsize>,
+ value: Option<T>,
+}
+
+pub struct DropCounterHandle(Arc<AtomicUsize>);
+
+impl<T> DropCounter<T> {
+ pub fn new(value: T) -> (Self, DropCounterHandle) {
+ let drop_count = Arc::new(AtomicUsize::new(0));
+ (
+ Self {
+ drop_count: drop_count.clone(),
+ value: Some(value),
+ },
+ DropCounterHandle(drop_count),
+ )
+ }
+
+ pub fn value(&self) -> &T {
+ self.value.as_ref().unwrap()
+ }
+
+ pub fn into_value(mut self) -> T {
+ self.value.take().unwrap()
+ }
+}
+
+impl DropCounterHandle {
+ pub fn count(&self) -> usize {
+ self.0.load(SeqCst)
+ }
+}
+
+impl<T> Drop for DropCounter<T> {
+ fn drop(&mut self) {
+ self.drop_count.fetch_add(1, SeqCst);
+ }
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/helpers/waker.rs b/third_party/rust/oneshot-uniffi/tests/helpers/waker.rs
new file mode 100644
index 0000000000..2e3f1bee19
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/helpers/waker.rs
@@ -0,0 +1,64 @@
+//! Creates a Waker that can be observed from tests.
+
+use std::mem::forget;
+use std::sync::atomic::{AtomicU32, Ordering};
+use std::sync::Arc;
+use std::task::{RawWaker, RawWakerVTable, Waker};
+
+#[derive(Default)]
+pub struct WakerHandle {
+ clone_count: AtomicU32,
+ drop_count: AtomicU32,
+ wake_count: AtomicU32,
+}
+
+impl WakerHandle {
+ pub fn clone_count(&self) -> u32 {
+ self.clone_count.load(Ordering::Relaxed)
+ }
+
+ pub fn drop_count(&self) -> u32 {
+ self.drop_count.load(Ordering::Relaxed)
+ }
+
+ pub fn wake_count(&self) -> u32 {
+ self.wake_count.load(Ordering::Relaxed)
+ }
+}
+
+pub fn waker() -> (Waker, Arc<WakerHandle>) {
+ let waker_handle = Arc::new(WakerHandle::default());
+ let waker_handle_ptr = Arc::into_raw(waker_handle.clone());
+ let raw_waker = RawWaker::new(waker_handle_ptr as *const _, waker_vtable());
+ (unsafe { Waker::from_raw(raw_waker) }, waker_handle)
+}
+
+pub(super) fn waker_vtable() -> &'static RawWakerVTable {
+ &RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw)
+}
+
+unsafe fn clone_raw(data: *const ()) -> RawWaker {
+ let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
+ handle.clone_count.fetch_add(1, Ordering::Relaxed);
+ forget(handle.clone());
+ forget(handle);
+ RawWaker::new(data, waker_vtable())
+}
+
+unsafe fn wake_raw(data: *const ()) {
+ let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
+ handle.wake_count.fetch_add(1, Ordering::Relaxed);
+ handle.drop_count.fetch_add(1, Ordering::Relaxed);
+}
+
+unsafe fn wake_by_ref_raw(data: *const ()) {
+ let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
+ handle.wake_count.fetch_add(1, Ordering::Relaxed);
+ forget(handle)
+}
+
+unsafe fn drop_raw(data: *const ()) {
+ let handle: Arc<WakerHandle> = Arc::from_raw(data as *const _);
+ handle.drop_count.fetch_add(1, Ordering::Relaxed);
+ drop(handle)
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/loom.rs b/third_party/rust/oneshot-uniffi/tests/loom.rs
new file mode 100644
index 0000000000..a7625a494d
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/loom.rs
@@ -0,0 +1,223 @@
+#![cfg(loom)]
+
+use oneshot::TryRecvError;
+
+use loom::hint;
+use loom::thread;
+#[cfg(feature = "async")]
+use std::future::Future;
+#[cfg(feature = "async")]
+use std::pin::Pin;
+#[cfg(feature = "async")]
+use std::task::{self, Poll};
+#[cfg(feature = "std")]
+use std::time::Duration;
+
+mod helpers;
+
+#[test]
+fn try_recv() {
+ loom::model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+
+ let t = thread::spawn(move || loop {
+ match receiver.try_recv() {
+ Ok(msg) => break msg,
+ Err(TryRecvError::Empty) => hint::spin_loop(),
+ Err(TryRecvError::Disconnected) => panic!("Should not be disconnected"),
+ }
+ });
+
+ assert!(sender.send(19).is_ok());
+ assert_eq!(t.join().unwrap(), 19);
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_recv_different_threads() {
+ loom::model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let t2 = thread::spawn(move || {
+ assert_eq!(receiver.recv_timeout(Duration::from_millis(1)), Ok(9));
+ });
+ let t1 = thread::spawn(move || {
+ sender.send(9u128).unwrap();
+ });
+ t1.join().unwrap();
+ t2.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_drop_sender_different_threads() {
+ loom::model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t2 = thread::spawn(move || {
+ assert!(receiver.recv_timeout(Duration::from_millis(0)).is_err());
+ });
+ let t1 = thread::spawn(move || {
+ drop(sender);
+ });
+ t1.join().unwrap();
+ t2.join().unwrap();
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn async_recv() {
+ loom::model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t1 = thread::spawn(move || {
+ sender.send(987).unwrap();
+ });
+ assert_eq!(loom::future::block_on(receiver), Ok(987));
+ t1.join().unwrap();
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn send_then_poll() {
+ loom::model(|| {
+ let (sender, mut receiver) = oneshot::channel::<u128>();
+ sender.send(1234).unwrap();
+
+ let (waker, waker_handle) = helpers::waker::waker();
+ let mut context = task::Context::from_waker(&waker);
+
+ assert_eq!(
+ Pin::new(&mut receiver).poll(&mut context),
+ Poll::Ready(Ok(1234))
+ );
+ assert_eq!(waker_handle.clone_count(), 0);
+ assert_eq!(waker_handle.drop_count(), 0);
+ assert_eq!(waker_handle.wake_count(), 0);
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn poll_then_send() {
+ loom::model(|| {
+ let (sender, mut receiver) = oneshot::channel::<u128>();
+
+ let (waker, waker_handle) = helpers::waker::waker();
+ let mut context = task::Context::from_waker(&waker);
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 0);
+ assert_eq!(waker_handle.wake_count(), 0);
+
+ sender.send(1234).unwrap();
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 1);
+ assert_eq!(waker_handle.wake_count(), 1);
+
+ assert_eq!(
+ Pin::new(&mut receiver).poll(&mut context),
+ Poll::Ready(Ok(1234))
+ );
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 1);
+ assert_eq!(waker_handle.wake_count(), 1);
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn poll_with_different_wakers() {
+ loom::model(|| {
+ let (sender, mut receiver) = oneshot::channel::<u128>();
+
+ let (waker1, waker_handle1) = helpers::waker::waker();
+ let mut context1 = task::Context::from_waker(&waker1);
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context1), Poll::Pending);
+ assert_eq!(waker_handle1.clone_count(), 1);
+ assert_eq!(waker_handle1.drop_count(), 0);
+ assert_eq!(waker_handle1.wake_count(), 0);
+
+ let (waker2, waker_handle2) = helpers::waker::waker();
+ let mut context2 = task::Context::from_waker(&waker2);
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context2), Poll::Pending);
+ assert_eq!(waker_handle1.clone_count(), 1);
+ assert_eq!(waker_handle1.drop_count(), 1);
+ assert_eq!(waker_handle1.wake_count(), 0);
+
+ assert_eq!(waker_handle2.clone_count(), 1);
+ assert_eq!(waker_handle2.drop_count(), 0);
+ assert_eq!(waker_handle2.wake_count(), 0);
+
+ // Sending should cause the waker from the latest poll to be woken up
+ sender.send(1234).unwrap();
+ assert_eq!(waker_handle1.clone_count(), 1);
+ assert_eq!(waker_handle1.drop_count(), 1);
+ assert_eq!(waker_handle1.wake_count(), 0);
+
+ assert_eq!(waker_handle2.clone_count(), 1);
+ assert_eq!(waker_handle2.drop_count(), 1);
+ assert_eq!(waker_handle2.wake_count(), 1);
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn poll_then_try_recv() {
+ loom::model(|| {
+ let (_sender, mut receiver) = oneshot::channel::<u128>();
+
+ let (waker, waker_handle) = helpers::waker::waker();
+ let mut context = task::Context::from_waker(&waker);
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 0);
+ assert_eq!(waker_handle.wake_count(), 0);
+
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
+ assert_eq!(waker_handle.clone_count(), 2);
+ assert_eq!(waker_handle.drop_count(), 1);
+ assert_eq!(waker_handle.wake_count(), 0);
+ })
+}
+
+#[cfg(feature = "async")]
+#[test]
+fn poll_then_try_recv_while_sending() {
+ loom::model(|| {
+ let (sender, mut receiver) = oneshot::channel::<u128>();
+
+ let (waker, waker_handle) = helpers::waker::waker();
+ let mut context = task::Context::from_waker(&waker);
+
+ assert_eq!(Pin::new(&mut receiver).poll(&mut context), Poll::Pending);
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 0);
+ assert_eq!(waker_handle.wake_count(), 0);
+
+ let t = thread::spawn(move || {
+ sender.send(1234).unwrap();
+ });
+
+ let msg = loop {
+ match receiver.try_recv() {
+ Ok(msg) => break msg,
+ Err(TryRecvError::Empty) => hint::spin_loop(),
+ Err(TryRecvError::Disconnected) => panic!("Should not be disconnected"),
+ }
+ };
+ assert_eq!(msg, 1234);
+ assert_eq!(waker_handle.clone_count(), 1);
+ assert_eq!(waker_handle.drop_count(), 1);
+ assert_eq!(waker_handle.wake_count(), 1);
+
+ t.join().unwrap();
+ })
+}
diff --git a/third_party/rust/oneshot-uniffi/tests/sync.rs b/third_party/rust/oneshot-uniffi/tests/sync.rs
new file mode 100644
index 0000000000..c6ba081c66
--- /dev/null
+++ b/third_party/rust/oneshot-uniffi/tests/sync.rs
@@ -0,0 +1,343 @@
+use core::mem;
+use oneshot::TryRecvError;
+
+#[cfg(feature = "std")]
+use oneshot::{RecvError, RecvTimeoutError};
+#[cfg(feature = "std")]
+use std::time::{Duration, Instant};
+
+#[cfg(feature = "std")]
+mod thread {
+ #[cfg(loom)]
+ pub use loom::thread::spawn;
+ #[cfg(not(loom))]
+ pub use std::thread::{sleep, spawn};
+
+ #[cfg(loom)]
+ pub fn sleep(_timeout: core::time::Duration) {
+ loom::thread::yield_now()
+ }
+}
+
+mod helpers;
+use helpers::{maybe_loom_model, DropCounter};
+
+#[test]
+fn send_before_try_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ assert_eq!(receiver.try_recv(), Ok(19i128));
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
+ #[cfg(feature = "std")]
+ {
+ assert_eq!(receiver.recv_ref(), Err(RecvError));
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ }
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<()>();
+ assert!(sender.send(()).is_ok());
+ assert_eq!(receiver.recv(), Ok(()));
+ });
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u8>();
+ assert!(sender.send(19).is_ok());
+ assert_eq!(receiver.recv(), Ok(19));
+ });
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u64>();
+ assert!(sender.send(21).is_ok());
+ assert_eq!(receiver.recv(), Ok(21));
+ });
+ // FIXME: This test does not work with loom. There is something that happens after the
+ // channel object becomes larger than ~500 bytes and that makes an atomic read from the state
+ // result in "signal: 10, SIGBUS: access to undefined memory"
+ #[cfg(not(loom))]
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<[u8; 4096]>();
+ assert!(sender.send([0b10101010; 4096]).is_ok());
+ assert!(receiver.recv().unwrap()[..] == [0b10101010; 4096][..]);
+ });
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv_ref() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ assert_eq!(receiver.recv_ref(), Ok(19i128));
+ assert_eq!(receiver.recv_ref(), Err(RecvError));
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Disconnected));
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn send_before_recv_timeout() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+
+ let start = Instant::now();
+ let timeout = Duration::from_secs(1);
+ assert_eq!(receiver.recv_timeout(timeout), Ok(19i128));
+ assert!(start.elapsed() < Duration::from_millis(100));
+
+ assert!(receiver.recv_timeout(timeout).is_err());
+ assert!(receiver.try_recv().is_err());
+ assert!(receiver.recv().is_err());
+ })
+}
+
+#[test]
+fn send_then_drop_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ assert!(sender.send(19i128).is_ok());
+ mem::drop(receiver);
+ })
+}
+
+#[test]
+fn send_with_dropped_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ mem::drop(receiver);
+ let send_error = sender.send(5u128).unwrap_err();
+ assert_eq!(*send_error.as_inner(), 5);
+ assert_eq!(send_error.into_inner(), 5);
+ })
+}
+
+#[test]
+fn try_recv_with_dropped_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.try_recv().unwrap_err();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_with_dropped_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ mem::drop(sender);
+ receiver.recv().unwrap_err();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_before_send() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(2));
+ sender.send(9u128).unwrap();
+ });
+ assert_eq!(receiver.recv(), Ok(9));
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_timeout_before_send() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(2));
+ sender.send(9u128).unwrap();
+ });
+ assert_eq!(receiver.recv_timeout(Duration::from_secs(1)), Ok(9));
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_before_send_then_drop_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(10));
+ mem::drop(sender);
+ });
+ assert!(receiver.recv().is_err());
+ t.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_timeout_before_send_then_drop_sender() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t = thread::spawn(move || {
+ thread::sleep(Duration::from_millis(10));
+ mem::drop(sender);
+ });
+ assert!(receiver.recv_timeout(Duration::from_secs(1)).is_err());
+ t.join().unwrap();
+ })
+}
+
+#[test]
+fn try_recv() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ assert_eq!(receiver.try_recv(), Err(TryRecvError::Empty));
+ mem::drop(sender)
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn try_recv_then_drop_receiver() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel::<u128>();
+ let t1 = thread::spawn(move || {
+ let _ = sender.send(42);
+ });
+ let t2 = thread::spawn(move || {
+ assert!(matches!(
+ receiver.try_recv(),
+ Ok(42) | Err(TryRecvError::Empty)
+ ));
+ mem::drop(receiver);
+ });
+ t1.join().unwrap();
+ t2.join().unwrap();
+ })
+}
+
+#[cfg(feature = "std")]
+#[test]
+fn recv_deadline_and_timeout_no_time() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ assert_eq!(
+ receiver.recv_deadline(start),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() < Duration::from_millis(200));
+
+ let start = Instant::now();
+ assert_eq!(
+ receiver.recv_timeout(Duration::from_millis(0)),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() < Duration::from_millis(200));
+ })
+}
+
+// This test doesn't give meaningful results when run with oneshot_test_delay and loom
+#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
+#[test]
+fn recv_deadline_time_should_elapse() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ #[cfg(not(loom))]
+ let timeout = Duration::from_millis(100);
+ #[cfg(loom)]
+ let timeout = Duration::from_millis(1);
+ assert_eq!(
+ receiver.recv_deadline(start + timeout),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() > timeout);
+ assert!(start.elapsed() < timeout * 3);
+ })
+}
+
+#[cfg(all(feature = "std", not(all(oneshot_test_delay, loom))))]
+#[test]
+fn recv_timeout_time_should_elapse() {
+ maybe_loom_model(|| {
+ let (_sender, receiver) = oneshot::channel::<u128>();
+
+ let start = Instant::now();
+ #[cfg(not(loom))]
+ let timeout = Duration::from_millis(100);
+ #[cfg(loom)]
+ let timeout = Duration::from_millis(1);
+
+ assert_eq!(
+ receiver.recv_timeout(timeout),
+ Err(RecvTimeoutError::Timeout)
+ );
+ assert!(start.elapsed() > timeout);
+ assert!(start.elapsed() < timeout * 3);
+ })
+}
+
+#[cfg(not(loom))]
+#[test]
+fn non_send_type_can_be_used_on_same_thread() {
+ use std::ptr;
+
+ #[derive(Debug, Eq, PartialEq)]
+ struct NotSend(*mut ());
+
+ let (sender, receiver) = oneshot::channel();
+ sender.send(NotSend(ptr::null_mut())).unwrap();
+ let reply = receiver.try_recv().unwrap();
+ assert_eq!(reply, NotSend(ptr::null_mut()));
+}
+
+#[test]
+fn message_in_channel_dropped_on_receiver_drop() {
+ maybe_loom_model(|| {
+ let (sender, receiver) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+ assert_eq!(counter.count(), 0);
+ sender.send(message).unwrap();
+ assert_eq!(counter.count(), 0);
+ mem::drop(receiver);
+ assert_eq!(counter.count(), 1);
+ })
+}
+
+#[test]
+fn send_error_drops_message_correctly() {
+ maybe_loom_model(|| {
+ let (sender, _) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+
+ let send_error = sender.send(message).unwrap_err();
+ assert_eq!(counter.count(), 0);
+ mem::drop(send_error);
+ assert_eq!(counter.count(), 1);
+ });
+}
+
+#[test]
+fn send_error_drops_message_correctly_on_into_inner() {
+ maybe_loom_model(|| {
+ let (sender, _) = oneshot::channel();
+ let (message, counter) = DropCounter::new(());
+
+ let send_error = sender.send(message).unwrap_err();
+ assert_eq!(counter.count(), 0);
+ let message = send_error.into_inner();
+ assert_eq!(counter.count(), 0);
+ mem::drop(message);
+ assert_eq!(counter.count(), 1);
+ });
+}