#![no_main] use libfuzzer_sys::fuzz_target; use dagx::{task, DagRunner}; fuzz_target!(|data: &[u8]| { // Only fuzz with reasonable data sizes to avoid timeouts if data.is_empty() || data.len() > 1000 { return; } // Convert bytes to values for tasks let value1 = data.get(0).copied().unwrap_or(0) as i32; let value2 = data.get(1).copied().unwrap_or(0) as i32; let value3 = data.get(2).copied().unwrap_or(0) as i32; // Test simple linear DAG execution { struct Source1 { val: i32 } #[task] impl Source1 { async fn run(&self) -> i32 { self.val } } struct Source2 { val: i32 } #[task] impl Source2 { async fn run(&self) -> i32 { self.val } } struct Compute; #[task] impl Compute { async fn run(a: &i32, b: &i32) -> i32 { a.wrapping_add(*b) } } let dag = DagRunner::new(); let s1 = dag.add_task(Source1 { val: value1 }); let s2 = dag.add_task(Source2 { val: value2 }); let compute = dag.add_task(Compute).depends_on((&s1, &s2)); let rt = tokio::runtime::Runtime::new().unwrap(); if let Ok(()) = rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }) { // Verify output if let Ok(result) = dag.get(compute) { assert_eq!(result, value1.wrapping_add(value2)); } } } // Test fan-out pattern { struct Source { val: i32 } #[task] impl Source { async fn run(&self) -> i32 { self.val } } struct Double; #[task] impl Double { async fn run(input: &i32) -> i32 { input.wrapping_mul(2) } } struct Triple; #[task] impl Triple { async fn run(input: &i32) -> i32 { input.wrapping_mul(3) } } let dag = DagRunner::new(); let source = dag.add_task(Source { val: value3 }); let double = dag.add_task(Double).depends_on(&source); let triple = dag.add_task(Triple).depends_on(&source); let rt = tokio::runtime::Runtime::new().unwrap(); if let Ok(()) = rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }) { // Verify outputs if let (Ok(d), Ok(t)) = (dag.get(double), dag.get(triple)) { assert_eq!(d, value3.wrapping_mul(2)); assert_eq!(t, value3.wrapping_mul(3)); } } } // Test error-free execution with various data if data.len() >= 4 { struct DataTask { data: Vec } #[task] impl DataTask { async fn run(&self) -> Vec { self.data.clone() } } let dag = DagRunner::new(); let task = dag.add_task(DataTask { data: data[..4.min(data.len())].to_vec() }); let rt = tokio::runtime::Runtime::new().unwrap(); if let Ok(()) = rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }) { if let Ok(result) = dag.get(task) { assert_eq!(result.len(), 4.min(data.len())); } } } });