803 lines
23 KiB
Rust
803 lines
23 KiB
Rust
//! Runtime comparison tests for the announcement crate.
|
|
//! Verifies identical behavior across different async runtimes and blocking mode.
|
|
|
|
use announcement::Announcement;
|
|
use std::sync::Arc;
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
// === TOKIO TESTS ===
|
|
|
|
/// Test: Runtime test: basic announce and listen
|
|
///
|
|
/// Verifies: Basic announcement and listening works correctly on the runtime
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_basic_announce_listen() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
announcer.announce(42).unwrap();
|
|
assert_eq!(listener.listen().await.unwrap(), 42);
|
|
}
|
|
|
|
/// Test: Runtime test: listen initiated before announce
|
|
///
|
|
/// Verifies: Listener waiting before announce receives value correctly on the runtime
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_listen_before_announce() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
let handle = tokio::spawn(async move { listener.listen().await.unwrap() });
|
|
|
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
|
announcer.announce(42).unwrap();
|
|
|
|
assert_eq!(handle.await.unwrap(), 42);
|
|
}
|
|
|
|
/// Test: Runtime test: multiple concurrent listeners
|
|
///
|
|
/// Verifies: Multiple listeners all receive the same announced value on the runtime
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_multiple_listeners() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..10 {
|
|
let listener = announcement.listener();
|
|
handles.push(tokio::spawn(async move {
|
|
(i, listener.listen().await.unwrap())
|
|
}));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.await.unwrap();
|
|
assert_eq!(value, 42);
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: multi-threaded execution
|
|
///
|
|
/// Verifies: Multi-threaded runtime executes announcements correctly
|
|
/// Category: runtime
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
async fn tokio_multi_threaded() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..20 {
|
|
let listener = announcement.listener();
|
|
handles.push(tokio::spawn(async move {
|
|
(i, listener.listen().await.unwrap())
|
|
}));
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.await.unwrap();
|
|
assert_eq!(value, 42);
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: current-thread execution
|
|
///
|
|
/// Verifies: Current-thread runtime executes announcements correctly
|
|
/// Category: runtime
|
|
#[tokio::test(flavor = "current_thread")]
|
|
async fn tokio_current_thread() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..20 {
|
|
let listener = announcement.listener();
|
|
handles.push(tokio::spawn(async move {
|
|
(i, listener.listen().await.unwrap())
|
|
}));
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.await.unwrap();
|
|
assert_eq!(value, 42);
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: select/race pattern
|
|
///
|
|
/// Verifies: Runtime select patterns work correctly with multiple announcements
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_select_pattern() {
|
|
let (announcer1, announcement1) = Announcement::new();
|
|
let (announcer2, announcement2) = Announcement::new();
|
|
|
|
let listener1 = announcement1.listener();
|
|
let listener2 = announcement2.listener();
|
|
|
|
tokio::spawn(async move {
|
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
|
announcer2.announce(2).unwrap();
|
|
});
|
|
|
|
tokio::spawn(async move {
|
|
tokio::time::sleep(Duration::from_millis(20)).await;
|
|
announcer1.announce(1).unwrap();
|
|
});
|
|
|
|
tokio::select! {
|
|
val = listener1.listen() => assert_eq!(val, Ok(1)),
|
|
val = listener2.listen() => assert_eq!(val, Ok(2)),
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: timeout behavior
|
|
///
|
|
/// Verifies: Runtime timeout mechanisms work correctly with announcements
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_timeout_behavior() {
|
|
let (_announcer, announcement) = Announcement::<i32>::new();
|
|
let listener = announcement.listener();
|
|
|
|
let result = tokio::time::timeout(Duration::from_millis(100), listener.listen()).await;
|
|
|
|
assert!(result.is_err()); // Should timeout
|
|
}
|
|
|
|
/// Test: Runtime test: blocking task interoperability
|
|
///
|
|
/// Verifies: Runtime blocking task spawning interoperates correctly with async
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_spawn_blocking_interop() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
let blocking_handle = tokio::task::spawn_blocking(move || {
|
|
// Blocking thread operation
|
|
thread::sleep(Duration::from_millis(10));
|
|
announcer.announce(42).unwrap();
|
|
});
|
|
|
|
let value = listener.listen().await.unwrap();
|
|
assert_eq!(value, 42);
|
|
|
|
blocking_handle.await.unwrap();
|
|
}
|
|
|
|
/// Test: Runtime test: mixed async and sync listeners
|
|
///
|
|
/// Verifies: Mix of async and synchronous listeners work correctly on the runtime
|
|
/// Category: runtime
|
|
#[tokio::test]
|
|
async fn tokio_mixed_async_sync() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
// Async listeners
|
|
let mut async_handles = vec![];
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
async_handles.push(tokio::spawn(
|
|
async move { listener.listen().await.unwrap() },
|
|
));
|
|
}
|
|
|
|
// Sync listeners in blocking threads
|
|
let mut sync_handles = vec![];
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
sync_handles.push(tokio::task::spawn_blocking(move || loop {
|
|
if let Some(val) = listener.try_listen() {
|
|
return val;
|
|
}
|
|
thread::sleep(Duration::from_millis(1));
|
|
}));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in async_handles {
|
|
assert_eq!(handle.await.unwrap(), 42);
|
|
}
|
|
|
|
for handle in sync_handles {
|
|
assert_eq!(handle.await.unwrap(), 42);
|
|
}
|
|
}
|
|
|
|
// === SMOL TESTS (replacing async-std) ===
|
|
|
|
/// Test: Runtime test: basic announce and listen
|
|
///
|
|
/// Verifies: Basic announcement and listening works correctly on the runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_basic_announce_listen() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
announcer.announce(42).unwrap();
|
|
assert_eq!(listener.listen().await.unwrap(), 42);
|
|
});
|
|
}
|
|
|
|
/// Test: Runtime test: listen initiated before announce
|
|
///
|
|
/// Verifies: Listener waiting before announce receives value correctly on the runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_listen_before_announce() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
let handle = smol::spawn(async move { listener.listen().await.unwrap() });
|
|
|
|
smol::Timer::after(Duration::from_millis(10)).await;
|
|
announcer.announce(42).unwrap();
|
|
|
|
assert_eq!(handle.await, 42);
|
|
});
|
|
}
|
|
|
|
/// Test: Runtime test: multiple concurrent listeners
|
|
///
|
|
/// Verifies: Multiple listeners all receive the same announced value on the runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_multiple_listeners() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..10 {
|
|
let listener = announcement.listener();
|
|
handles.push(smol::spawn(
|
|
async move { (i, listener.listen().await.unwrap()) },
|
|
));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.await;
|
|
assert_eq!(value, 42);
|
|
}
|
|
});
|
|
}
|
|
|
|
/// Test: Runtime test: timeout behavior
|
|
///
|
|
/// Verifies: Runtime timeout mechanisms work correctly with announcements
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_timeout_behavior() {
|
|
smol::block_on(async {
|
|
let (_announcer, announcement) = Announcement::<i32>::new();
|
|
let listener = announcement.listener();
|
|
|
|
let result = smol::future::or(
|
|
async {
|
|
listener.listen().await?;
|
|
Ok(())
|
|
},
|
|
async {
|
|
smol::Timer::after(Duration::from_millis(100)).await;
|
|
Err::<(), _>(announcement::ListenError::Timeout)
|
|
},
|
|
)
|
|
.await;
|
|
|
|
assert!(result.is_err()); // Should timeout
|
|
});
|
|
}
|
|
|
|
/// Test: Runtime test: blocking task interoperability
|
|
///
|
|
/// Verifies: Runtime blocking task spawning interoperates correctly with async
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_spawn_blocking_interop() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
let blocking_handle = smol::unblock(move || {
|
|
// Blocking thread operation
|
|
thread::sleep(Duration::from_millis(10));
|
|
announcer.announce(42).unwrap();
|
|
});
|
|
|
|
let value = listener.listen().await.unwrap();
|
|
assert_eq!(value, 42);
|
|
|
|
blocking_handle.await;
|
|
});
|
|
}
|
|
|
|
// === SMOL TESTS (already in smol_runtime.rs, adding comparisons) ===
|
|
|
|
/// Test: Runtime test: Smol runtime basic operations
|
|
///
|
|
/// Verifies: Basic announcement and listening works on Smol runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_basic_operations() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
announcer.announce(42).unwrap();
|
|
assert_eq!(listener.listen().await.unwrap(), 42);
|
|
});
|
|
}
|
|
|
|
/// Test: Runtime test: concurrent tasks
|
|
///
|
|
/// Verifies: Concurrent tasks work correctly on the runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn smol_concurrent_tasks() {
|
|
smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..10 {
|
|
let listener = announcement.listener();
|
|
handles.push(smol::spawn(
|
|
async move { (i, listener.listen().await.unwrap()) },
|
|
));
|
|
}
|
|
|
|
smol::Timer::after(Duration::from_millis(10)).await;
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.await;
|
|
assert_eq!(value, 42);
|
|
}
|
|
});
|
|
}
|
|
|
|
// === BLOCKING TESTS ===
|
|
|
|
/// Test: Runtime test: blocking mode basic operations
|
|
///
|
|
/// Verifies: Basic announcement and listen operations work in blocking mode
|
|
/// Category: runtime
|
|
#[cfg(feature = "std")]
|
|
#[test]
|
|
fn blocking_basic_operations() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
announcer.announce(42).unwrap();
|
|
assert_eq!(
|
|
listener.listen_timeout_blocking(Duration::from_millis(100)),
|
|
Ok(42)
|
|
);
|
|
}
|
|
|
|
/// Test: Runtime test: blocking mode timeout
|
|
///
|
|
/// Verifies: Timeout behavior works correctly in blocking mode
|
|
/// Category: runtime
|
|
#[cfg(feature = "std")]
|
|
#[test]
|
|
fn blocking_timeout() {
|
|
let (_announcer, announcement) = Announcement::<i32>::new();
|
|
let listener = announcement.listener();
|
|
|
|
let result = listener.listen_timeout_blocking(Duration::from_millis(100));
|
|
assert_eq!(result, Err(announcement::ListenError::Timeout));
|
|
}
|
|
|
|
/// Test: Runtime test: blocking mode multiple threads
|
|
///
|
|
/// Verifies: Multiple blocking threads receive announced values correctly
|
|
/// Category: runtime
|
|
#[cfg(feature = "std")]
|
|
#[test]
|
|
fn blocking_multiple_threads() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let mut handles = vec![];
|
|
|
|
for i in 0..10 {
|
|
let listener = announcement.listener();
|
|
handles.push(thread::spawn(move || {
|
|
(
|
|
i,
|
|
listener.listen_timeout_blocking(Duration::from_millis(100)),
|
|
)
|
|
}));
|
|
}
|
|
|
|
thread::sleep(Duration::from_millis(10));
|
|
announcer.announce(42).unwrap();
|
|
|
|
for handle in handles {
|
|
let (_, value) = handle.join().unwrap();
|
|
assert_eq!(value, Ok(42));
|
|
}
|
|
}
|
|
|
|
// === COMPARISON TESTS ===
|
|
|
|
// Test that verifies identical behavior across all runtimes
|
|
|
|
/// Test: Runtime test: all runtimes basic comparison
|
|
///
|
|
/// Verifies: All runtimes produce identical results for basic operations
|
|
/// Category: runtime
|
|
#[test]
|
|
fn compare_all_runtimes_basic() {
|
|
// Tokio multi-thread
|
|
let tokio_multi_result = tokio::runtime::Builder::new_multi_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
announcer.announce(42).unwrap();
|
|
listener.listen().await.unwrap()
|
|
});
|
|
|
|
// Tokio current-thread
|
|
let tokio_current_result = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
announcer.announce(42).unwrap();
|
|
listener.listen().await.unwrap()
|
|
});
|
|
|
|
// Smol
|
|
let smol_result2 = smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
announcer.announce(42).unwrap();
|
|
listener.listen().await.unwrap()
|
|
});
|
|
|
|
// Smol
|
|
let smol_result = smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
announcer.announce(42).unwrap();
|
|
listener.listen().await.unwrap()
|
|
});
|
|
|
|
// Blocking
|
|
#[cfg(feature = "std")]
|
|
let blocking_result = {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
announcer.announce(42).unwrap();
|
|
listener.listen_timeout_blocking(Duration::from_millis(100))
|
|
};
|
|
|
|
// All should be identical
|
|
assert_eq!(tokio_multi_result, 42);
|
|
assert_eq!(tokio_current_result, 42);
|
|
assert_eq!(smol_result2, 42);
|
|
assert_eq!(smol_result, 42);
|
|
#[cfg(feature = "std")]
|
|
assert_eq!(blocking_result, Ok(42));
|
|
}
|
|
|
|
/// Test: Runtime test: all runtimes concurrent comparison
|
|
///
|
|
/// Verifies: All runtimes produce identical results for concurrent operations
|
|
/// Category: runtime
|
|
#[test]
|
|
fn compare_all_runtimes_concurrent() {
|
|
let test_concurrent = |runtime: &str| -> Vec<i32> {
|
|
match runtime {
|
|
"tokio-multi" => tokio::runtime::Builder::new_multi_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let mut handles = vec![];
|
|
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
handles.push(tokio::spawn(
|
|
async move { listener.listen().await.unwrap() },
|
|
));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
let mut results = vec![];
|
|
for handle in handles {
|
|
results.push(handle.await.unwrap());
|
|
}
|
|
results
|
|
}),
|
|
"tokio-current" => tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let mut handles = vec![];
|
|
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
handles.push(tokio::spawn(
|
|
async move { listener.listen().await.unwrap() },
|
|
));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
let mut results = vec![];
|
|
for handle in handles {
|
|
results.push(handle.await.unwrap());
|
|
}
|
|
results
|
|
}),
|
|
"smol2" => smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let mut handles = vec![];
|
|
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
handles.push(smol::spawn(async move { listener.listen().await.unwrap() }));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
let mut results = vec![];
|
|
for handle in handles {
|
|
results.push(handle.await);
|
|
}
|
|
results
|
|
}),
|
|
"smol" => smol::block_on(async {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let mut handles = vec![];
|
|
|
|
for _ in 0..5 {
|
|
let listener = announcement.listener();
|
|
handles.push(smol::spawn(async move { listener.listen().await.unwrap() }));
|
|
}
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
let mut results = vec![];
|
|
for handle in handles {
|
|
results.push(handle.await);
|
|
}
|
|
results
|
|
}),
|
|
_ => panic!("Unknown runtime"),
|
|
}
|
|
};
|
|
|
|
let tokio_multi = test_concurrent("tokio-multi");
|
|
let tokio_current = test_concurrent("tokio-current");
|
|
let smol2 = test_concurrent("smol2");
|
|
let smol = test_concurrent("smol");
|
|
|
|
// All should produce same results
|
|
assert_eq!(tokio_multi, vec![42; 5]);
|
|
assert_eq!(tokio_current, vec![42; 5]);
|
|
assert_eq!(smol2, vec![42; 5]);
|
|
assert_eq!(smol, vec![42; 5]);
|
|
}
|
|
|
|
// === CROSS-RUNTIME TESTS ===
|
|
|
|
/// Test: Runtime test: cross-runtime announcement
|
|
///
|
|
/// Verifies: Announcement works correctly when components use different runtimes
|
|
/// Category: runtime
|
|
#[test]
|
|
fn cross_runtime_announcement() {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let announcement = Arc::new(announcement);
|
|
|
|
// Create listener in one runtime
|
|
let ann1 = announcement.clone();
|
|
let tokio_listener = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async move { ann1.listener() });
|
|
|
|
// Create listener in another runtime
|
|
let ann2 = announcement.clone();
|
|
let smol_listener = smol::block_on(async move { ann2.listener() });
|
|
|
|
// Announce in yet another runtime
|
|
smol::block_on(async {
|
|
announcer.announce(42).unwrap();
|
|
});
|
|
|
|
// Verify in original runtimes
|
|
let tokio_result = tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
.block_on(async { tokio_listener.listen().await.unwrap() });
|
|
|
|
let smol_result = smol::block_on(async { smol_listener.listen().await.unwrap() });
|
|
|
|
assert_eq!(tokio_result, 42);
|
|
assert_eq!(smol_result, 42);
|
|
}
|
|
|
|
// === BEHAVIOR CONSISTENCY TESTS ===
|
|
|
|
/// Test: Runtime test: consistent is_announced behavior
|
|
///
|
|
/// Verifies: is_announced() returns consistent results across invocations
|
|
/// Category: runtime
|
|
#[test]
|
|
fn verify_consistent_is_announced() {
|
|
let test_is_announced = || {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let before = announcement.is_announced();
|
|
announcer.announce(42).unwrap();
|
|
let after = announcement.is_announced();
|
|
|
|
(before, after)
|
|
};
|
|
|
|
// Run multiple times to ensure consistency
|
|
for _ in 0..10 {
|
|
let (before, after) = test_is_announced();
|
|
assert!(!before);
|
|
assert!(after);
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: consistent try_listen behavior
|
|
///
|
|
/// Verifies: try_listen() returns consistent results across invocations
|
|
/// Category: runtime
|
|
#[test]
|
|
fn verify_consistent_try_listen() {
|
|
let test_try_listen = || {
|
|
let (announcer, announcement) = Announcement::new();
|
|
let listener = announcement.listener();
|
|
|
|
let before = listener.try_listen();
|
|
announcer.announce(42).unwrap();
|
|
let after = listener.try_listen();
|
|
|
|
(before, after)
|
|
};
|
|
|
|
// Run multiple times to ensure consistency
|
|
for _ in 0..10 {
|
|
let (before, after) = test_try_listen();
|
|
assert_eq!(before, None);
|
|
assert_eq!(after, Some(42));
|
|
}
|
|
}
|
|
|
|
/// Test: Runtime test: multiple concurrent listeners
|
|
///
|
|
/// Verifies: Multiple listeners all receive the same announced value on the runtime
|
|
/// Category: runtime
|
|
#[test]
|
|
fn verify_consistent_multiple_listeners() {
|
|
let test_multiple = || {
|
|
let (announcer, announcement) = Announcement::new();
|
|
|
|
let listeners: Vec<_> = (0..5).map(|_| announcement.listener()).collect();
|
|
|
|
announcer.announce(42).unwrap();
|
|
|
|
listeners.iter().map(|l| l.try_listen()).collect::<Vec<_>>()
|
|
};
|
|
|
|
// Run multiple times
|
|
for _ in 0..10 {
|
|
let results = test_multiple();
|
|
assert_eq!(results, vec![Some(42); 5]);
|
|
}
|
|
}
|
|
|
|
// === FINAL COMPARISON SUMMARY ===
|
|
|
|
/// Test: Runtime test: comparison summary
|
|
///
|
|
/// Verifies: All runtime comparison tests pass and produce consistent results
|
|
/// Category: runtime
|
|
#[test]
|
|
fn runtime_comparison_summary() {
|
|
println!("Runtime Comparison Test Summary:");
|
|
println!("================================");
|
|
|
|
let mut all_passed = true;
|
|
|
|
// Test each runtime
|
|
|
|
{
|
|
// Tokio
|
|
let tokio_ok = std::panic::catch_unwind(|| {
|
|
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
|
let (ann, announcement) = Announcement::new();
|
|
let l = announcement.listener();
|
|
ann.announce(1).unwrap();
|
|
assert_eq!(l.listen().await.unwrap(), 1);
|
|
});
|
|
})
|
|
.is_ok();
|
|
|
|
println!("Tokio: {}", if tokio_ok { "✓ PASS" } else { "✗ FAIL" });
|
|
all_passed = all_passed && tokio_ok;
|
|
|
|
// Smol
|
|
let smol_ok = std::panic::catch_unwind(|| {
|
|
smol::block_on(async {
|
|
let (ann, announcement) = Announcement::new();
|
|
let l = announcement.listener();
|
|
ann.announce(3).unwrap();
|
|
assert_eq!(l.listen().await.unwrap(), 3);
|
|
});
|
|
})
|
|
.is_ok();
|
|
|
|
println!("Smol: {}", if smol_ok { "✓ PASS" } else { "✗ FAIL" });
|
|
all_passed = all_passed && smol_ok;
|
|
}
|
|
|
|
// Blocking
|
|
#[cfg(feature = "std")]
|
|
{
|
|
let blocking_ok = std::panic::catch_unwind(|| {
|
|
let (ann, announcement) = Announcement::new();
|
|
let l = announcement.listener();
|
|
ann.announce(4).unwrap();
|
|
assert_eq!(l.listen_timeout_blocking(Duration::from_millis(100)), Ok(4));
|
|
})
|
|
.is_ok();
|
|
|
|
println!(
|
|
"Blocking: {}",
|
|
if blocking_ok { "✓ PASS" } else { "✗ FAIL" }
|
|
);
|
|
all_passed = all_passed && blocking_ok;
|
|
}
|
|
|
|
println!("================================");
|
|
println!(
|
|
"Overall: {}",
|
|
if all_passed {
|
|
"✓ ALL PASS"
|
|
} else {
|
|
"✗ SOME FAILED"
|
|
}
|
|
);
|
|
|
|
assert!(all_passed, "Not all runtime tests passed");
|
|
}
|