Files
announcement/fuzz/fuzz_targets/fuzz_close.rs
T
swaits e8e55b7676 chore: initial release v0.1.0
Runtime-agnostic oneshot broadcast channel for Rust.
2025-10-13 19:36:37 -06:00

85 lines
2.4 KiB
Rust

#![no_main]
use libfuzzer_sys::fuzz_target;
use announcement::Announcement;
fuzz_target!(|data: &[u8]| {
if data.is_empty() {
return;
}
let action = data[0] % 4;
match action {
0 => {
// Test drop without announce
let (announcer, announcement) = Announcement::<u32>::new();
let listener = announcement.listener();
assert!(!announcement.is_closed());
drop(announcer);
// Should be closed now
assert!(announcement.is_closed());
assert!(listener.is_closed());
}
1 => {
// Test explicit close
let (announcer, announcement) = Announcement::<u32>::new();
let listener = announcement.listener();
assert!(!announcement.is_closed());
announcer.close();
// Should be closed now
assert!(announcement.is_closed());
assert!(listener.is_closed());
}
2 => {
// Test announce then drop (should not be closed)
let (announcer, announcement) = Announcement::new();
let listener = announcement.listener();
let _ = announcer.announce(42u32);
// announcer is consumed by announce(), no need to drop
// Should NOT be closed (announced successfully)
assert!(!announcement.is_closed());
assert!(!listener.is_closed());
// Listener should get value
assert_eq!(listener.try_listen(), Some(42u32));
}
_ => {
// Test listener created after close
let (announcer, announcement) = Announcement::<u32>::new();
announcer.close();
// Create listener after close
let listener = announcement.listener();
// Should immediately know it's closed
assert!(listener.is_closed());
}
}
// Test with multiple listeners
if data.len() >= 2 {
let num_listeners = (data[1] % 10) as usize + 1; // 1-10 listeners
let (announcer, announcement) = Announcement::<u32>::new();
let listeners: Vec<_> = (0..num_listeners)
.map(|_| announcement.listener())
.collect();
// Drop announcer
drop(announcer);
// All should see closed state
for listener in listeners {
assert!(listener.is_closed());
}
}
});