Update tests, examples, benches

This commit is contained in:
TechnoPorg committed 2026-02-11 22:01:50 +01:00
1 parent 0137296fb4
commit 86787b3a0d
71 files changed
+1791 -3547

No files matched your search

+49 -57
View File
@@ -15,7 +15,7 @@ async fn test_empty_dag() {
#[tokio::test]
async fn test_single_task() {
let dag = DagRunner::new();
let task = dag.add_task(task_fn(|_: ()| async { 42 }));
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
.await
.unwrap();
@@ -26,18 +26,18 @@ async fn test_single_task() {
async fn test_deep_chain() {
let dag = DagRunner::new();
let a = dag.add_task(task_fn(|_: ()| async { 1 }));
let a = dag.add_task(task_fn::<(), _, _>(|_: ()| 1));
let b = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(a);
let c = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(b);
let d = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(c);
let e = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(d);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -54,7 +54,7 @@ async fn test_wide_parallel() {
let dag = DagRunner::new();
let tasks: Vec<_> = (0..10)
.map(|i| dag.add_task(task_fn(move |_: ()| async move { i * 2 })))
.map(|i| dag.add_task(task_fn::<(), _, _>(move |_: ()| i * 2)))
.collect();
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -70,15 +70,15 @@ async fn test_wide_parallel() {
async fn test_diamond_dependency() {
let dag = DagRunner::new();
let a: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into();
let a: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 10)).into();
let b = dag
.add_task(task_fn(|x: i32| async move { x + 5 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(a);
let c = dag
.add_task(task_fn(|x: i32| async move { x * 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2))
.depends_on(a);
let d = dag
.add_task(task_fn(|(x, y): (i32, i32)| async move { x + y }))
.add_task(task_fn::<(i32, i32), _, _>(|(x, y): (&i32, &i32)| x + y))
.depends_on((&b, &c));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -100,13 +100,11 @@ struct User {
async fn test_different_output_types() {
let dag = DagRunner::new();
let string_task = dag.add_task(task_fn(|_: ()| async { "hello".to_string() }));
let vec_task = dag.add_task(task_fn(|_: ()| async { vec![1, 2, 3] }));
let struct_task = dag.add_task(task_fn(|_: ()| async {
User {
name: "Alice".to_string(),
age: 30,
}
let string_task = dag.add_task(task_fn::<(), _, _>(|_: ()| "hello".to_string()));
let vec_task = dag.add_task(task_fn::<(), _, _>(|_: ()| vec![1, 2, 3]));
let struct_task = dag.add_task(task_fn::<(), _, _>(|_: ()| User {
name: "Alice".to_string(),
age: 30,
}));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -124,22 +122,22 @@ async fn test_different_output_types() {
async fn test_multiple_sinks() {
let dag = DagRunner::new();
let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into();
let source: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 10)).into();
// Branch 1
let branch1 = dag
.add_task(task_fn(|x: i32| async move { x * 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2))
.depends_on(source);
let sink1 = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(branch1);
// Branch 2
let branch2 = dag
.add_task(task_fn(|x: i32| async move { x + 5 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(source);
let sink2 = dag
.add_task(task_fn(|x: i32| async move { x * 3 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 3))
.depends_on(branch2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -156,12 +154,12 @@ async fn test_single_task_inline_path() {
let dag = DagRunner::new();
// Single task in its own layer
let t1: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 10 })).into();
let t1: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 10)).into();
let t2 = dag
.add_task(task_fn(|x: i32| async move { x * 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2))
.depends_on(t1);
let t3 = dag
.add_task(task_fn(|x: i32| async move { x + 5 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(t2);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -176,17 +174,17 @@ async fn test_multi_task_spawn_path() {
// Test multi-task layer spawn path (line 411-456 in runner.rs)
let dag = DagRunner::new();
let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 100 })).into();
let source: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 100)).into();
// Create multiple tasks in the same layer (all depend on source)
let t1 = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(source);
let t2 = dag
.add_task(task_fn(|x: i32| async move { x + 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 2))
.depends_on(source);
let t3 = dag
.add_task(task_fn(|x: i32| async move { x + 3 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 3))
.depends_on(source);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -205,14 +203,14 @@ async fn test_producer_consumer_channels() {
// Producer
let producer: TaskHandle<_> = dag
.add_task(task_fn(|_: ()| async { vec![1, 2, 3, 4, 5] }))
.add_task(task_fn::<(), _, _>(|_: ()| vec![1, 2, 3, 4, 5]))
.into();
// Consumer
let consumer = dag
.add_task(task_fn(
|data: Vec<i32>| async move { data.iter().sum::<i32>() },
))
.add_task(task_fn::<Vec<_>, _, _>(|data: &Vec<i32>| {
data.iter().sum::<i32>()
}))
.depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -227,17 +225,17 @@ async fn test_multi_consumer_fanout() {
// Test fanout with multiple consumers from one producer
let dag = DagRunner::new();
let producer: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 42 })).into();
let producer: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 42)).into();
// Multiple consumers
let c1 = dag
.add_task(task_fn(|x: i32| async move { x * 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x * 2))
.depends_on(producer);
let c2 = dag
.add_task(task_fn(|x: i32| async move { x + 10 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 10))
.depends_on(producer);
let c3 = dag
.add_task(task_fn(|x: i32| async move { x - 5 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x - 5))
.depends_on(producer);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -255,17 +253,17 @@ async fn test_compute_layers_with_dependents_tracking() {
let dag = DagRunner::new();
// Create diamond pattern to ensure dependents are tracked correctly
let source: TaskHandle<_> = dag.add_task(task_fn(|_: ()| async { 1 })).into();
let source: TaskHandle<_> = dag.add_task(task_fn::<(), _, _>(|_: ()| 1)).into();
let left = dag
.add_task(task_fn(|x: i32| async move { x + 1 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 1))
.depends_on(source);
let right = dag
.add_task(task_fn(|x: i32| async move { x + 2 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 2))
.depends_on(source);
let sink = dag
.add_task(task_fn(|(l, r): (i32, i32)| async move { l + r }))
.add_task(task_fn::<(i32, i32), _, _>(|(l, r): (&i32, &i32)| l + r))
.depends_on((&left, &right));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -286,33 +284,27 @@ async fn test_layer_execution_order() {
let dag = DagRunner::new();
let order1 = execution_order.clone();
let t1 = dag.add_task(task_fn(move |_: ()| {
let t1 = dag.add_task(task_fn::<(), _, _>(move |_: ()| {
let order = order1.clone();
async move {
order.lock().push(1);
1
}
order.lock().push(1);
1
}));
let order2 = execution_order.clone();
let t2 = dag
.add_task(task_fn(move |x: i32| {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| {
let order = order2.clone();
async move {
order.lock().push(2);
x + 1
}
order.lock().push(2);
x + 1
}))
.depends_on(t1);
let order3 = execution_order.clone();
let t3 = dag
.add_task(task_fn(move |x: i32| {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| {
let order = order3.clone();
async move {
order.lock().push(3);
x + 1
}
order.lock().push(3);
x + 1
}))
.depends_on(t2);
-82
View File
@@ -1,82 +0,0 @@
// Example pattern tests for DagRunner
use crate::common::task_fn;
use crate::common::tasks::*;
use dagx::*;
use futures::FutureExt;
#[tokio::test]
async fn test_example_a_fan_out() {
let dag = DagRunner::new();
let base: TaskHandle<_> = dag.add_task(Seed::new(10)).into(); // Input=() → no depends_on, returns TaskHandle
let plus1 = dag.add_task(Inc::new()).depends_on(base); // 11
let plus2 = dag.add_task(Inc::new()).depends_on(base); // 11
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
.await
.unwrap(); // SPEC API with spawner
assert_eq!(dag.get(plus1).unwrap(), 11);
assert_eq!(dag.get(plus2).unwrap(), 11);
}
#[tokio::test]
async fn test_example_b_fan_in() {
let dag = DagRunner::new();
let s = dag.add_task(task_fn(|_: ()| async { "hi".to_owned() }));
let n = dag.add_task(task_fn(|_: ()| async { 42usize }));
let f = dag.add_task(task_fn(|_: ()| async { true }));
let output = dag.add_task(OutputResult::new()).depends_on((s, n, f));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
.await
.unwrap();
assert_eq!(&dag.get(output).unwrap(), "hi:42:true");
}
#[tokio::test]
async fn test_example_c_many_to_many() {
let dag = DagRunner::new();
let x = dag.add_task(Seed::new(2));
let y = dag.add_task(Seed::new(3)).into();
let z = dag.add_task(Seed::new(5));
let sum_xy = dag.add_task(Add::new()).depends_on((x, &y)); // 5
let prod_yz = dag.add_task(Mul::new()).depends_on((&y, z)); // 15
let total = dag.add_task(Add::new()).depends_on((&sum_xy, &prod_yz)); // 20
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
.await
.unwrap();
assert_eq!(dag.get(total).unwrap(), 20);
}
#[tokio::test]
async fn test_single_input_forms() {
let dag = DagRunner::new();
let s = dag
.add_task(task_fn(|_: ()| async { "hello".to_owned() }))
.into();
// Preferred form: &node
let upper1 = dag
.add_task(task_fn(|s: String| async move { s.to_uppercase() }))
.depends_on(s);
// Also allowed: (&node,)
let upper2 = dag
.add_task(task_fn(|s: String| async move { s.to_uppercase() }))
.depends_on((&s,));
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
.await
.unwrap();
assert_eq!(&dag.get(upper1).unwrap(), "HELLO");
assert_eq!(&dag.get(upper2).unwrap(), "HELLO");
}
+6 -6
View File
@@ -170,7 +170,7 @@ async fn integration_test_wide_and_deep() -> DagResult<()> {
for source in &sources {
let step1 = dag.add_task(Multiply::new(2)).depends_on(source);
let step2 = dag
.add_task(task_fn(|x: i32| async move { x + 5 }))
.add_task(task_fn::<i32, _, _>(|&x: &i32| x + 5))
.depends_on(step1);
let step3 = dag.add_task(Multiply::new(3)).depends_on(step2);
final_nodes.push(step3);
@@ -276,7 +276,7 @@ async fn integration_test_parallel_execution_timing() -> DagResult<()> {
// Create 5 independent tasks that each sleep for 100ms
let tasks: Vec<_> = (0..num_parallel_tasks)
.map(|i| {
dag.add_task(task_fn(move |_: ()| async move {
dag.add_task(task_fn::<(), _, _>(move |_: ()| {
sleep(sleep_duration).await;
i
}))
@@ -314,7 +314,7 @@ async fn integration_test_parallel_vs_sequential_timing() -> DagResult<()> {
// Layer 1: 4 parallel tasks (should take ~50ms)
let parallel_tasks: Vec<_> = (0..4)
.map(|i| {
dag.add_task(task_fn(move |_: ()| async move {
dag.add_task(task_fn::<(), _, _>(move |_: ()| {
sleep(sleep_duration).await;
i * 10
}))
@@ -324,21 +324,21 @@ async fn integration_test_parallel_vs_sequential_timing() -> DagResult<()> {
// Layer 2: Sequential chain of 3 tasks depending on the first parallel task
// (should add ~150ms)
let seq1 = dag
.add_task(task_fn(move |x: i32| async move {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| {
sleep(sleep_duration).await;
x + 1
}))
.depends_on(parallel_tasks[0]);
let seq2 = dag
.add_task(task_fn(move |x: i32| async move {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| {
sleep(sleep_duration).await;
x + 1
}))
.depends_on(seq1);
let seq3 = dag
.add_task(task_fn(move |x: i32| async move {
.add_task(task_fn::<i32, _, _>(move |&x: &i32| {
sleep(sleep_duration).await;
x + 1
}))
-1
View File
@@ -1,5 +1,4 @@
// Test module for execution tests
mod basic;
mod examples;
mod results;
+9 -9
View File
@@ -9,8 +9,8 @@ use futures::FutureExt;
async fn test_result_type() {
let dag = DagRunner::new();
let success_task = dag.add_task(task_fn(|_: ()| async { Ok::<i32, String>(42) }));
let error_task = dag.add_task(task_fn(|_: ()| async {
let success_task = dag.add_task(task_fn::<(), _, _>(|_: ()| Ok::<i32, String>(42)));
let error_task = dag.add_task(task_fn::<(), _, _>(|_: ()| {
Err::<i32, String>("error".to_string())
}));
@@ -25,7 +25,7 @@ async fn test_result_type() {
#[tokio::test]
async fn test_dag_result_type_works() {
let dag = DagRunner::new();
let task = dag.add_task(task_fn(|_: ()| async { 100 }));
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 100));
// Test that DagResult<()> works with ? operator pattern
async fn run_dag(dag: &DagRunner) -> DagResult<()> {
@@ -41,7 +41,7 @@ async fn test_dag_result_type_works() {
#[tokio::test]
async fn test_task_not_executed_error() {
let dag = DagRunner::new();
let task = dag.add_task(task_fn(|_: ()| async { 42 }));
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
// Try to get result before running - should error
let result = dag.get(task);
@@ -58,7 +58,7 @@ async fn test_task_not_executed_error() {
async fn test_error_messages_are_helpful() {
// Test ResultNotFound error message
let dag = DagRunner::new();
let task = dag.add_task(task_fn(|_: ()| async { 42 }));
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
let result = dag.get(task);
assert!(result.is_err());
let err_msg = format!("{}", result.unwrap_err());
@@ -70,7 +70,7 @@ async fn test_error_messages_are_helpful() {
#[tokio::test]
async fn test_successful_execution_returns_ok() {
let dag = DagRunner::new();
let task = dag.add_task(task_fn(|_: ()| async { 42 }));
let task = dag.add_task(task_fn::<(), _, _>(|_: ()| 42));
// Should return Ok(())
let result = dag.run(|fut| tokio::spawn(fut).map(Result::unwrap)).await;
@@ -84,7 +84,7 @@ async fn test_successful_execution_returns_ok() {
async fn test_stateful_tasks() {
let dag = DagRunner::new();
let input = dag.add_task(task_fn(|_: ()| async { 5 }));
let input = dag.add_task(task_fn::<(), _, _>(|_: ()| 5));
let counter = dag.add_task(Counter::new(10)).depends_on(input);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
@@ -102,9 +102,9 @@ async fn test_task_fn_with_captured_state() {
let dag = DagRunner::new();
let multiplier = 7;
let base = dag.add_task(task_fn(|_: ()| async { 5 }));
let base = dag.add_task(task_fn::<(), _, _>(|_: ()| 5));
let scaled = dag
.add_task(task_fn(move |x: i32| async move { x * multiplier }))
.add_task(task_fn::<i32, _, _>(move |&x: &i32| x * multiplier))
.depends_on(base);
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))