// Skip all smol tests under Miri - it doesn't support timerfd_create syscall #![cfg_attr(miri, allow(dead_code))] use announcement::Announcement; use std::sync::Arc; use std::time::Duration; // ============================================================================= // Smol runtime tests // ============================================================================= #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol runtime basic operations /// /// Verifies: Basic announcement and listening works on Smol runtime /// Category: runtime fn test_smol_basic() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); let listener = announcement.listener(); smol::spawn(async move { smol::Timer::after(Duration::from_millis(10)).await; announcer.announce(42).unwrap(); }) .detach(); let result = listener.listen().await.unwrap(); assert_eq!(result, 42); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: multiple concurrent listeners /// /// Verifies: Multiple listeners all receive the same announced value on the runtime /// Category: runtime fn test_smol_multiple_listeners() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); let l1 = announcement.listener(); let l2 = announcement.listener(); let l3 = announcement.listener(); let h1 = smol::spawn(async move { l1.listen().await.unwrap() }); let h2 = smol::spawn(async move { l2.listen().await.unwrap() }); let h3 = smol::spawn(async move { l3.listen().await.unwrap() }); // Small delay before announcing smol::Timer::after(Duration::from_millis(10)).await; announcer.announce(42).unwrap(); assert_eq!(h1.await, 42); assert_eq!(h2.await, 42); assert_eq!(h3.await, 42); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol concurrent announce and listen /// /// Verifies: Concurrent announce and listen operations work on Smol runtime /// Category: runtime fn test_smol_concurrent_announce_and_listen() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); // Create many listeners concurrently let mut handles = Vec::new(); for i in 0..50 { let listener = announcement.listener(); handles.push(smol::spawn( async move { (i, listener.listen().await.unwrap()) }, )); } // Announce value concurrently smol::spawn(async move { smol::Timer::after(Duration::from_millis(5)).await; announcer.announce(999).unwrap(); }) .detach(); // Verify all listeners get the value for handle in handles { let (_, value) = handle.await; assert_eq!(value, 999); } }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol listen after announce /// /// Verifies: Listening after announce returns immediately on Smol runtime /// Category: runtime fn test_smol_listen_after_announce() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); // Announce first announcer.announce(42).unwrap(); // Create listeners after let l1 = announcement.listener(); let l2 = announcement.listener(); // Should return immediately assert_eq!(l1.listen().await.unwrap(), 42); assert_eq!(l2.listen().await.unwrap(), 42); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol with Arc-wrapped data /// /// Verifies: Arc-wrapped data is handled correctly on Smol runtime /// Category: runtime fn test_smol_with_arc() { smol::block_on(async { #[derive(Clone, Debug, PartialEq)] struct Data { value: Vec, } let (announcer, announcement) = Announcement::new(); let data = Arc::new(Data { value: vec![1, 2, 3, 4, 5], }); let l1 = announcement.listener(); let l2 = announcement.listener(); announcer.announce(data.clone()).unwrap(); let r1 = l1.listen().await.unwrap(); let r2 = l2.listen().await.unwrap(); assert_eq!(r1, data); assert_eq!(r2, data); // Verify Arc refcount assert_eq!(Arc::strong_count(&r1), 4); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol race condition protection /// /// Verifies: Race conditions are properly handled on Smol runtime /// Category: runtime fn test_smol_race_condition_protection() { smol::block_on(async { // Run multiple times to catch any race conditions for i in 0..100 { let (announcer, announcement) = Announcement::new(); let listener = announcement.listener(); let handle = smol::spawn(async move { listener.listen().await.unwrap() }); // Announce immediately (potential race) announcer.announce(i).unwrap(); assert_eq!(handle.await, i); } }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol many concurrent tasks /// /// Verifies: Many concurrent tasks all receive values correctly on Smol runtime /// Category: runtime fn test_smol_many_concurrent_tasks() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); // Create 100 concurrent listeners let mut handles = Vec::new(); for _ in 0..100 { let listener = announcement.listener(); handles.push(smol::spawn(async move { listener.listen().await.unwrap() })); } // Wait a bit to ensure all are waiting smol::Timer::after(Duration::from_millis(10)).await; // Announce announcer.announce(12345).unwrap(); // All should receive the same value for handle in handles { assert_eq!(handle.await, 12345); } }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol dropped listener handling /// /// Verifies: System works correctly when listeners are dropped on Smol runtime /// Category: runtime fn test_smol_listener_dropped() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); // Create and immediately drop a listener { let _listener = announcement.listener(); // Dropped here } // Should still work with new listeners let listener = announcement.listener(); announcer.announce(42).unwrap(); assert_eq!(listener.listen().await.unwrap(), 42); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol announcement cloning /// /// Verifies: Cloned announcements work correctly on Smol runtime /// Category: runtime fn test_smol_clone_announcement() { smol::block_on(async { let (announcer, announcement) = Announcement::new(); let announcement2 = announcement.clone(); let l1 = announcement.listener(); let l2 = announcement2.listener(); announcer.announce(42).unwrap(); assert_eq!(l1.listen().await.unwrap(), 42); assert_eq!(l2.listen().await.unwrap(), 42); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: timeout behavior /// /// Verifies: Runtime timeout mechanisms work correctly with announcements /// Category: runtime fn test_smol_timeout_behavior() { use announcement::ListenError; smol::block_on(async { let (_, announcement) = Announcement::::new(); // Note: Announcer dropped immediately via _ pattern - sets closed flag let listener = announcement.listener(); // With closed detection, listen() returns Closed immediately let result = listener.listen().await; assert_eq!(result, Err(ListenError::Closed)); assert!(announcement.is_closed()); }); } #[test] #[cfg_attr( miri, ignore = "Miri doesn't support timerfd_create syscall used by smol" )] /// Test: Runtime test: Smol complex data types /// /// Verifies: Complex data types work correctly on Smol runtime /// Category: runtime fn test_smol_complex_types() { smol::block_on(async { #[derive(Clone, Debug, PartialEq)] struct ComplexData { name: String, values: Vec, nested: Option>, } let (announcer, announcement) = Announcement::new(); let listener = announcement.listener(); let data = ComplexData { name: "test".to_string(), values: vec![1, 2, 3, 4, 5], nested: None, }; announcer.announce(data.clone()).unwrap(); let result = listener.listen().await.unwrap(); assert_eq!(result, data); }); }