Update tests, examples, benches
This commit is contained in:
1 parent
0137296fb4
commit
86787b3a0d
71 files changed
+1791
-3547
No files matched your search
+6
-19
@@ -1,6 +1,5 @@
|
||||
//! Unit tests for builder module
|
||||
|
||||
use crate::builder::IsUnitType;
|
||||
use crate::runner::DagRunner;
|
||||
use crate::types::TaskHandle;
|
||||
|
||||
@@ -52,24 +51,12 @@ fn test_task_builder_from_conversion() {
|
||||
let builder = dag.add_task(TestTask { value: 42 });
|
||||
|
||||
// Convert builder to TaskHandle
|
||||
let handle: TaskHandle<i32> = builder.into();
|
||||
let handle: TaskHandle<_> = builder.into();
|
||||
|
||||
// Check that the ID is preserved
|
||||
assert_eq!(handle.id.0, 0); // First task should have ID 0
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_unit_type_trait() {
|
||||
// Test that IsUnitType is correctly implemented for ()
|
||||
fn assert_is_unit_type<T: IsUnitType>() {}
|
||||
|
||||
// This should compile - () implements IsUnitType
|
||||
assert_is_unit_type::<()>();
|
||||
|
||||
// We can't test the negative case (non-unit types don't implement it)
|
||||
// because that would be a compile error
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task_builder_depends_on_returns_handle() {
|
||||
init_tracing();
|
||||
@@ -79,7 +66,7 @@ fn test_task_builder_depends_on_returns_handle() {
|
||||
let dependent = dag.add_task(TestTaskWithInput).depends_on(source);
|
||||
|
||||
// depends_on should return a TaskHandle
|
||||
let _handle: TaskHandle<i32> = dependent;
|
||||
let _handle: TaskHandle<_> = dependent;
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -92,9 +79,9 @@ fn test_task_builder_chain() {
|
||||
let t3 = dag.add_task(TestTaskWithInput).depends_on(t2);
|
||||
|
||||
// All should return TaskHandles
|
||||
let _: TaskHandle<i32> = t1;
|
||||
let _: TaskHandle<i32> = t2;
|
||||
let _: TaskHandle<i32> = t3;
|
||||
let _: TaskHandle<_> = t1;
|
||||
let _: TaskHandle<_> = t2;
|
||||
let _: TaskHandle<_> = t3;
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -118,7 +105,7 @@ fn test_multiple_dependencies() {
|
||||
let sum = dag.add_task(AddTask).depends_on((a, b));
|
||||
|
||||
// Should return a TaskHandle
|
||||
let _: TaskHandle<i32> = sum;
|
||||
let _: TaskHandle<_> = sum;
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+1
-1
@@ -207,7 +207,7 @@ fn test_deps_handle_ref_explicit() {
|
||||
|
||||
// Create a reference and explicitly call to_node_ids
|
||||
let handle_ref = &handle;
|
||||
let node_ids = DepsTuple::<i32>::to_node_ids(handle_ref);
|
||||
let node_ids = DepsTuple::<(i32,)>::to_node_ids(handle_ref);
|
||||
|
||||
assert_eq!(node_ids.len(), 1);
|
||||
assert_eq!(node_ids[0], NodeId(77));
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
//! Coverage tests for uncovered error paths in extract.rs
|
||||
//!
|
||||
//! These tests specifically target type mismatch error messages that aren't hit
|
||||
//! in normal usage because the #[task] macro generates type-safe code.
|
||||
//! We directly call extract_from_deps with mismatched types.
|
||||
|
||||
use crate::extract::ExtractInput;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_result_type_mismatch_coverage() {
|
||||
// Tests line 95 in extract.rs - Result<T,E> type mismatch error message
|
||||
// Create a dependency that provides the WRONG type (String instead of Result<i32, String>)
|
||||
// Try to extract as Result<i32, String> - this will fail with type mismatch
|
||||
let deps = vec![Arc::new("hello") as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
|
||||
// Verify the error message contains the expected type information
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
|
||||
// The error should mention Result type mismatch (line 95)
|
||||
assert!(
|
||||
err_msg.contains("Result"),
|
||||
"Expected type mismatch error mentioning Result, got: {}",
|
||||
err_msg
|
||||
);
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected 'Type mismatch' in error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_option_type_mismatch_coverage() {
|
||||
// Tests line 124 in extract.rs - Option<T> type mismatch error message
|
||||
// Create a dependency that provides the WRONG type (i32 instead of Option<i32>)
|
||||
// Try to extract as Option<i32> - this will fail with type mismatch
|
||||
let deps = vec![Arc::new(42) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Option::<i32>::extract_from_deps(deps).await;
|
||||
|
||||
// Verify the error message contains the expected type information
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
|
||||
// The error should mention Option type mismatch (line 124)
|
||||
assert!(
|
||||
err_msg.contains("Option"),
|
||||
"Expected type mismatch error mentioning Option, got: {}",
|
||||
err_msg
|
||||
);
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected 'Type mismatch' in error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_vec_type_mismatch_coverage() {
|
||||
// Tests line 152 in extract.rs - Vec<T> type mismatch error message
|
||||
// Create a dependency that provides the WRONG type (String instead of Vec<u8>)
|
||||
// Try to extract as Vec<u8> - this will fail with type mismatch
|
||||
let deps = vec![Arc::new("not a vec".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Vec::<u8>::extract_from_deps(deps).await;
|
||||
|
||||
// Verify the error message contains the expected type information
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
|
||||
// The error should mention Vec type mismatch (line 152)
|
||||
assert!(
|
||||
err_msg.contains("Vec"),
|
||||
"Expected type mismatch error mentioning Vec, got: {}",
|
||||
err_msg
|
||||
);
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected 'Type mismatch' in error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hashmap_type_mismatch_coverage() {
|
||||
// Tests line 181 in extract.rs - HashMap<K,V> type mismatch error message
|
||||
// Create a dependency that provides the WRONG type (Vec<i32> instead of HashMap)
|
||||
// Try to extract as HashMap<String, i32> - this will fail with type mismatch
|
||||
let deps = vec![Arc::new(vec![1, 2, 3]) as Arc<dyn Any + Send + Sync>];
|
||||
let result = HashMap::<String, i32>::extract_from_deps(deps).await;
|
||||
|
||||
// Verify the error message contains the expected type information
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
|
||||
// The error should mention HashMap type mismatch (line 181)
|
||||
assert!(
|
||||
err_msg.contains("HashMap"),
|
||||
"Expected type mismatch error mentioning HashMap, got: {}",
|
||||
err_msg
|
||||
);
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected 'Type mismatch' in error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_arc_type_mismatch_coverage() {
|
||||
// Tests line 211 in extract.rs - Arc<T> type mismatch error message
|
||||
// Arc is special: it expects Arc<Arc<T>> from channel
|
||||
// Create a dependency that provides Arc<String> instead of Arc<Arc<String>>
|
||||
let deps = vec![Arc::new("not double arc".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
|
||||
// Try to extract as Arc<String> - this will fail with type mismatch
|
||||
// because it expects Arc<Arc<String>> in the channel
|
||||
let result = Arc::<String>::extract_from_deps(deps).await;
|
||||
|
||||
// Verify the error message contains the expected type information
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
|
||||
// The error should mention Arc type mismatch (line 211)
|
||||
assert!(
|
||||
err_msg.contains("Arc"),
|
||||
"Expected type mismatch error mentioning Arc, got: {}",
|
||||
err_msg
|
||||
);
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected 'Type mismatch' in error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
// Additional tests for better coverage of complex scenarios
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_result_with_wrong_ok_type() {
|
||||
// Test Result with wrong Ok type
|
||||
// Try to extract as Result<i32, String> - wrong Ok type
|
||||
let deps = vec![Arc::new(Ok::<_, String>("test".to_string())) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Result") && err_msg.contains("Type mismatch"),
|
||||
"Expected Result type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_result_with_wrong_err_type() {
|
||||
// Test Result with wrong Err type
|
||||
// Try to extract as Result<i32, String> - wrong Err type
|
||||
let deps = vec![Arc::new(Err::<i32, i32>(42)) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Result") && err_msg.contains("Type mismatch"),
|
||||
"Expected Result type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_option_with_wrong_inner_type() {
|
||||
// Test Option with wrong inner type
|
||||
// Try to extract as Option<i32> - wrong inner type
|
||||
let deps = vec![Arc::new(Some("test".to_string())) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Option::<i32>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Option") && err_msg.contains("Type mismatch"),
|
||||
"Expected Option type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_vec_with_wrong_element_type() {
|
||||
// Test Vec with wrong element type
|
||||
// Try to extract as Vec<i32> - wrong element type
|
||||
let deps = vec![Arc::new(vec!["a".to_string(), "b".to_string()]) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Vec::<i32>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Vec") && err_msg.contains("Type mismatch"),
|
||||
"Expected Vec type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hashmap_with_wrong_key_type() {
|
||||
// Test HashMap with wrong key type
|
||||
let mut map = HashMap::new();
|
||||
map.insert(1, "one".to_string());
|
||||
// Try to extract as HashMap<String, String> - wrong key type
|
||||
let deps = vec![Arc::new(map) as Arc<dyn Any + Send + Sync>];
|
||||
let result = HashMap::<String, String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("HashMap") && err_msg.contains("Type mismatch"),
|
||||
"Expected HashMap type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hashmap_with_wrong_value_type() {
|
||||
// Test HashMap with wrong value type
|
||||
let mut map = HashMap::new();
|
||||
map.insert("key".to_string(), 42);
|
||||
// Try to extract as HashMap<String, String> - wrong value type
|
||||
let deps = vec![Arc::new(map) as Arc<dyn Any + Send + Sync>];
|
||||
let result = HashMap::<String, String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("HashMap") && err_msg.contains("Type mismatch"),
|
||||
"Expected HashMap type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_arc_with_wrong_inner_type() {
|
||||
// Test Arc with completely wrong inner type
|
||||
// Send Arc<i32> but expect Arc<String>
|
||||
// Try to extract as Arc<String> - wrong inner type
|
||||
let deps = vec![Arc::new(Arc::new(Arc::new(42))) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Arc::<String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Arc") && err_msg.contains("Type mismatch"),
|
||||
"Expected Arc type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_primitive_type_mismatch_for_completeness() {
|
||||
// Test primitive type mismatch (already covered in existing tests but good for completeness)
|
||||
// Try to extract as i32 - type mismatch
|
||||
let deps = vec![Arc::new("not an i32".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = i32::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Type mismatch"),
|
||||
"Expected type mismatch error, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_complex_nested_result_option() {
|
||||
// Test complex nested type: send Result<String, String>, expect Result<Option<i32>, String>
|
||||
// Try to extract as Result<Option<i32>, String> - nested type mismatch
|
||||
let deps =
|
||||
vec![Arc::new(Ok::<String, String>("test".to_string())) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<Option<i32>, String>::extract_from_deps(deps).await;
|
||||
|
||||
assert!(result.is_err());
|
||||
let err_msg = result.unwrap_err();
|
||||
assert!(
|
||||
err_msg.contains("Result") && err_msg.contains("Type mismatch"),
|
||||
"Expected Result type mismatch, got: {}",
|
||||
err_msg
|
||||
);
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
//! Unit tests for extract module
|
||||
|
||||
#![allow(dead_code)] // Test helpers generate unused code via macro
|
||||
|
||||
use crate::extract::ExtractInput;
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Test task for error scenarios
|
||||
#[allow(dead_code)]
|
||||
struct TestTask {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[crate::task]
|
||||
#[allow(dead_code)]
|
||||
impl TestTask {
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
async fn run(&self) -> i32 {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct TestTaskWithInput;
|
||||
|
||||
#[crate::task]
|
||||
#[allow(dead_code)]
|
||||
impl TestTaskWithInput {
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
async fn run(input: &i32) -> i32 {
|
||||
input * 2
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_result_type_single_dependency_error() {
|
||||
// Test Result<T,E> with wrong dependency count
|
||||
let deps = vec![
|
||||
Arc::new(Ok::<i32, String>(5)) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(Err::<i32, String>("test".to_string())) as Arc<dyn Any + Send + Sync>,
|
||||
]; // Two dependencies when expecting 1
|
||||
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 2"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_result_type_success() {
|
||||
// Test Result<T,E> successful extraction
|
||||
|
||||
let deps = vec![Arc::new(Ok::<i32, String>(42)) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), Ok(42));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_option_type_single_dependency_error() {
|
||||
// Test Option<T> with wrong dependency count
|
||||
let deps = vec![
|
||||
Arc::new(None::<String>) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(None::<String>) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(None::<String>) as Arc<dyn Any + Send + Sync>,
|
||||
]; // Three dependencies when expecting 1
|
||||
|
||||
let result = Option::<String>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 3"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_option_type_success() {
|
||||
// Test Option<T> successful extraction
|
||||
let deps = vec![Arc::new(Some(99)) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Option::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), Some(99));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_vec_type_single_dependency_error() {
|
||||
// Test Vec<T> with wrong dependency count
|
||||
let deps = vec![]; // Zero dependencies when expecting 1
|
||||
|
||||
let result = Vec::<u8>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 0"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_vec_type_success() {
|
||||
// Test Vec<T> successful extraction
|
||||
let deps = vec![Arc::new(vec![1, 2, 3]) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Vec::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_primitive_single_dependency_error() {
|
||||
// Test primitive types with wrong dependency count
|
||||
let deps = vec![
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
]; // Two dependencies when expecting 1
|
||||
|
||||
let result = i32::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 2"));
|
||||
|
||||
// Test with String
|
||||
let deps = vec![
|
||||
Arc::new(String::default()) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(String::default()) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
let result = String::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 2"));
|
||||
|
||||
// Test with f64
|
||||
let deps = vec![
|
||||
Arc::new(0.0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(0.0) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
let result = f64::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 2"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_unit_type() {
|
||||
// Test that unit type always succeeds regardless of dependencies
|
||||
let deps = vec![];
|
||||
let result = <()>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Even with dependencies (ignored), unit type succeeds
|
||||
let deps = vec![
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
let result = <()>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_tuple_basic() {
|
||||
// Test tuple extraction
|
||||
let deps = vec![
|
||||
Arc::new(42) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(100) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
|
||||
// Extract a tuple (i32, i32)
|
||||
let result = <(i32, i32)>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), (42, 100));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_type_mismatch() {
|
||||
// Test type mismatch during downcast
|
||||
// Try to extract as wrong type - put wrong receiver type in deps
|
||||
let deps = vec![Arc::new("hello".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = i32::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_all_primitive_types() {
|
||||
// Test that all primitive types in impl_extract_single! work correctly
|
||||
macro_rules! test_type {
|
||||
($t:ty, $val:expr) => {
|
||||
let deps = vec![Arc::new($val) as Arc<dyn Any + Send + Sync>];
|
||||
let result = <$t>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), $val);
|
||||
};
|
||||
}
|
||||
|
||||
test_type!(i8, 42i8);
|
||||
test_type!(i16, 42i16);
|
||||
test_type!(i32, 42i32);
|
||||
test_type!(i64, 42i64);
|
||||
test_type!(String, "test".to_string());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_larger_tuples() {
|
||||
// Test extraction for larger tuple sizes
|
||||
let deps = vec![
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(1) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(2) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(3) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(4) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
|
||||
// Extract a 5-element tuple
|
||||
let result = <(i32, i32, i32, i32, i32)>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), (0, 1, 2, 3, 4));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_extract_arc_type() {
|
||||
// Test Arc<T> extraction
|
||||
let test_arc = Arc::new("test".to_string());
|
||||
let test_arc_clone = test_arc.clone();
|
||||
|
||||
let deps = vec![Arc::new(test_arc) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Arc::<String>::extract_from_deps(deps).await;
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(*result.unwrap(), *test_arc_clone);
|
||||
}
|
||||
|
||||
// Error path tests for ExtractInput implementations
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hashmap_extract_wrong_dependency_count() {
|
||||
let deps = vec![
|
||||
Arc::new(HashMap::<String, i32>::default()) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(HashMap::<String, i32>::default()) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
|
||||
let result = HashMap::<String, i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 2"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_hashmap_extract_type_mismatch() {
|
||||
let deps = vec![Arc::new("wrong type".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = HashMap::<String, i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_result_extract_downcast_failure() {
|
||||
let deps = vec![Arc::new("wrong".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Result::<i32, String>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_option_extract_downcast_failure() {
|
||||
let deps = vec![Arc::new("wrong".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Option::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_vec_extract_downcast_failure() {
|
||||
let deps = vec![Arc::new("wrong".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Vec::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_arc_extract_wrong_dependency_count() {
|
||||
let deps = vec![];
|
||||
let result = Arc::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Expected 1 dependency, got 0"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_arc_extract_downcast_failure() {
|
||||
let deps = vec![Arc::new("wrong".to_string()) as Arc<dyn Any + Send + Sync>];
|
||||
let result = Arc::<i32>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("Type mismatch"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_tuple_wrong_dependency_count() {
|
||||
let deps = vec![
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
Arc::new(0) as Arc<dyn Any + Send + Sync>,
|
||||
];
|
||||
|
||||
let result = <(i32, i32)>::extract_from_deps(deps).await;
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.contains("Expected 2 dependencies, got 3"));
|
||||
}
|
||||
+4
-23
@@ -3,7 +3,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::node::{ExecutableNode, TypedNode};
|
||||
use crate::types::NodeId;
|
||||
|
||||
// Simple test task
|
||||
struct TestTask {
|
||||
@@ -26,29 +25,11 @@ impl TaskWithDependency {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_execute_with_deps_missing_input() {
|
||||
// Test when task expects input but doesn't receive it
|
||||
let node = Box::new(TypedNode::new(NodeId(0), TaskWithDependency));
|
||||
|
||||
// TaskWithDependency expects an i32 input, but we provide no dependencies
|
||||
let dependencies = vec![];
|
||||
|
||||
let result = node.execute_with_deps(dependencies).await;
|
||||
assert!(result.is_err());
|
||||
|
||||
if let Err(crate::error::DagError::InvalidDependency { task_id }) = result {
|
||||
assert_eq!(task_id, 0);
|
||||
} else {
|
||||
panic!("Expected InvalidDependency error, got: {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_execute_with_deps_success() {
|
||||
// Test successful execution with channels
|
||||
let dependency_node = Box::new(TypedNode::new(NodeId(0), TestTask { value: 21 }));
|
||||
let dependent_node = Box::new(TypedNode::new(NodeId(1), TaskWithDependency));
|
||||
let dependency_node = Box::new(TypedNode::new(TestTask { value: 21 }));
|
||||
let dependent_node = Box::new(TypedNode::new(TaskWithDependency));
|
||||
|
||||
// Execute dependency node with sender
|
||||
let dep_dependencies = vec![];
|
||||
@@ -71,7 +52,7 @@ async fn test_execute_with_deps_success() {
|
||||
#[tokio::test]
|
||||
async fn test_execute_with_deps_sink_node() {
|
||||
// Test that sink nodes (no dependents) return their output
|
||||
let node = Box::new(TypedNode::new(NodeId(0), TestTask { value: 42 }));
|
||||
let node = Box::new(TypedNode::new(TestTask { value: 42 }));
|
||||
|
||||
// No senders means this is a sink node
|
||||
let dependencies = vec![];
|
||||
@@ -88,7 +69,7 @@ async fn test_execute_with_deps_sink_node() {
|
||||
#[tokio::test]
|
||||
async fn test_execute_with_deps_non_sink_node() {
|
||||
// Test that non-sink nodes send output via channels
|
||||
let node = TypedNode::new(NodeId(0), TestTask { value: 42 });
|
||||
let node = TypedNode::new(TestTask { value: 42 });
|
||||
|
||||
// Execute with senders (non-sink node)
|
||||
let node = Box::new(node);
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
//! Coverage tests for runner module - specifically targeting uncovered error paths
|
||||
//!
|
||||
//! These tests ensure we hit the type mismatch error path in get() (line 601)
|
||||
|
||||
use crate::error::DagError;
|
||||
use crate::runner::DagRunner;
|
||||
use crate::types::TaskHandle;
|
||||
use futures::FutureExt;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_type_mismatch_error() {
|
||||
// Test the type mismatch error path in get() - line 601 in runner.rs
|
||||
// This occurs when Arc downcast fails due to type mismatch
|
||||
|
||||
use crate::task_fn;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Task outputs i32
|
||||
let source = dag.add_task(task_fn(|_: ()| async { 42i32 }));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get as String - TYPE MISMATCH!
|
||||
// Create a handle with the same ID but wrong type
|
||||
let wrong_handle: TaskHandle<String> = TaskHandle {
|
||||
id: source.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let result = dag.get(wrong_handle);
|
||||
|
||||
assert!(result.is_err());
|
||||
let err = result.unwrap_err();
|
||||
match err {
|
||||
DagError::TypeMismatch { expected, found } => {
|
||||
assert_eq!(expected, std::any::type_name::<String>());
|
||||
assert_eq!(found, "unknown"); // This covers line 601!
|
||||
}
|
||||
_ => panic!("Expected TypeMismatch error, got: {:?}", err),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_type_mismatch_i32_to_vec() {
|
||||
// Different type mismatch: i32 to Vec<u8>
|
||||
use crate::task_fn;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Task outputs i32
|
||||
let int_task = dag.add_task(task_fn(|_: ()| async { 123i32 }));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get as Vec<u8>
|
||||
let wrong_handle: TaskHandle<Vec<u8>> = TaskHandle {
|
||||
id: int_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let result = dag.get(wrong_handle);
|
||||
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
DagError::TypeMismatch { expected, found } => {
|
||||
assert_eq!(expected, std::any::type_name::<Vec<u8>>());
|
||||
assert_eq!(found, "unknown");
|
||||
}
|
||||
_ => panic!("Expected TypeMismatch error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_type_mismatch_struct_to_hashmap() {
|
||||
// Complex type mismatch: custom struct to HashMap
|
||||
|
||||
#[derive(Clone)]
|
||||
#[allow(dead_code)]
|
||||
struct CustomOutput {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
struct CustomTask;
|
||||
|
||||
#[crate::task]
|
||||
impl CustomTask {
|
||||
async fn run(&self) -> CustomOutput {
|
||||
CustomOutput { value: 42 }
|
||||
}
|
||||
}
|
||||
|
||||
let dag = DagRunner::new();
|
||||
let task_handle = dag.add_task(CustomTask);
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get as HashMap
|
||||
let wrong_handle: TaskHandle<HashMap<String, i32>> = TaskHandle {
|
||||
id: task_handle.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let result = dag.get(wrong_handle);
|
||||
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
DagError::TypeMismatch { expected, found } => {
|
||||
assert!(expected.contains("HashMap"));
|
||||
assert_eq!(found, "unknown");
|
||||
}
|
||||
_ => panic!("Expected TypeMismatch error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_type_mismatch_vec_different_types() {
|
||||
// Type mismatch between Vec<i32> and Vec<String>
|
||||
use crate::task_fn;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Task outputs Vec<i32>
|
||||
let vec_task = dag.add_task(task_fn(|_: ()| async { vec![1, 2, 3] }));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get as Vec<String>
|
||||
let wrong_handle: TaskHandle<Vec<String>> = TaskHandle {
|
||||
id: vec_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let result = dag.get(wrong_handle);
|
||||
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
DagError::TypeMismatch { expected, found } => {
|
||||
assert_eq!(expected, std::any::type_name::<Vec<String>>());
|
||||
assert_eq!(found, "unknown");
|
||||
}
|
||||
_ => panic!("Expected TypeMismatch error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_type_mismatch_option_types() {
|
||||
// Type mismatch with Option types
|
||||
use crate::task_fn;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Task outputs Option<i32>
|
||||
let opt_task = dag.add_task(task_fn(|_: ()| async { Some(42) }));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get as Option<String>
|
||||
let wrong_handle: TaskHandle<Option<String>> = TaskHandle {
|
||||
id: opt_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
|
||||
let result = dag.get(wrong_handle);
|
||||
|
||||
assert!(result.is_err());
|
||||
match result.unwrap_err() {
|
||||
DagError::TypeMismatch { expected, found } => {
|
||||
assert_eq!(expected, std::any::type_name::<Option<String>>());
|
||||
assert_eq!(found, "unknown");
|
||||
}
|
||||
_ => panic!("Expected TypeMismatch error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_multiple_type_mismatches_same_dag() {
|
||||
// Test multiple type mismatches in the same DAG
|
||||
use crate::task_fn;
|
||||
|
||||
let dag = DagRunner::new();
|
||||
|
||||
// Create tasks with different output types
|
||||
let int_task = dag.add_task(task_fn(|_: ()| async { 100i32 }));
|
||||
let string_task = dag.add_task(task_fn(|_: ()| async { "hello".to_string() }));
|
||||
let bool_task = dag.add_task(task_fn(|_: ()| async { true }));
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Try to get int_task as String
|
||||
let wrong_int_handle: TaskHandle<String> = TaskHandle {
|
||||
id: int_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
assert!(matches!(
|
||||
dag.get(wrong_int_handle).unwrap_err(),
|
||||
DagError::TypeMismatch { found, .. } if found == "unknown"
|
||||
));
|
||||
|
||||
// Try to get string_task as bool
|
||||
let wrong_string_handle: TaskHandle<bool> = TaskHandle {
|
||||
id: string_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
assert!(matches!(
|
||||
dag.get(wrong_string_handle).unwrap_err(),
|
||||
DagError::TypeMismatch { found, .. } if found == "unknown"
|
||||
));
|
||||
|
||||
// Try to get bool_task as i32
|
||||
let wrong_bool_handle: TaskHandle<i32> = TaskHandle {
|
||||
id: bool_task.id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
assert!(matches!(
|
||||
dag.get(wrong_bool_handle).unwrap_err(),
|
||||
DagError::TypeMismatch { found, .. } if found == "unknown"
|
||||
));
|
||||
|
||||
// Verify correct types still work
|
||||
assert_eq!(dag.get(int_task).unwrap(), 100);
|
||||
assert_eq!(dag.get(string_task).unwrap(), "hello");
|
||||
assert!(dag.get(bool_task).unwrap());
|
||||
}
|
||||
@@ -185,27 +185,6 @@ fn test_add_task_increments_id() {
|
||||
assert_eq!(dag.nodes.lock().len(), 3);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_multiple_get_calls() {
|
||||
init_tracing();
|
||||
// Test that get() can be called multiple times for the same handle
|
||||
let dag = DagRunner::new();
|
||||
let handle: TaskHandle<_> = dag.add_task(TestTask { value: 100 }).into();
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Multiple get calls should all return the same value
|
||||
let result1 = dag.get(handle).unwrap();
|
||||
let result2 = dag.get(handle).unwrap();
|
||||
let result3 = dag.get(handle).unwrap();
|
||||
|
||||
assert_eq!(result1, 100);
|
||||
assert_eq!(result2, 100);
|
||||
assert_eq!(result3, 100);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_invalid_node_id_in_get() {
|
||||
init_tracing();
|
||||
|
||||
+84
-43
@@ -1,6 +1,7 @@
|
||||
//! Unit tests for task module
|
||||
|
||||
use crate::task::{task_fn, Task};
|
||||
use crate::task::{task_fn, Task, TaskInput};
|
||||
use std::any::Any;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
@@ -11,50 +12,74 @@ async fn test_task_fn_creation_and_execution() {
|
||||
// Test line 111 in task.rs - Task implementation for TaskFn
|
||||
|
||||
// Create a simple task function
|
||||
let task = task_fn(|input: i32| async move { input * 2 });
|
||||
let task = task_fn::<i32, _, _>(|input: &i32| input * 2);
|
||||
|
||||
// Test the Task trait implementation
|
||||
let result = task.run(42).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(42) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, 84);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_unit_input() {
|
||||
// Test task_fn with unit input
|
||||
let task = task_fn(|_: ()| async { 100 });
|
||||
let task = task_fn::<(), _, _>(|_: ()| 100);
|
||||
|
||||
let result = task.run(()).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(()) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, 100);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_tuple_input() {
|
||||
// Test task_fn with tuple input
|
||||
let task = task_fn(|(a, b): (i32, i32)| async move { a + b });
|
||||
let task = task_fn::<(i32, i32), _, _>(|(a, b): (&i32, &i32)| a + b);
|
||||
|
||||
let result = task.run((10, 20)).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![
|
||||
Arc::new(10) as Arc<dyn Any + Send + Sync + 'static>,
|
||||
Arc::new(20) as Arc<dyn Any + Send + Sync + 'static>,
|
||||
]
|
||||
.iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, 30);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_string_input() {
|
||||
// Test task_fn with String input
|
||||
let task = task_fn(|input: String| {
|
||||
let task = task_fn::<String, _, _>(|input: &String| {
|
||||
let len = input.len();
|
||||
async move { len }
|
||||
len
|
||||
});
|
||||
|
||||
let test_string = String::from("hello");
|
||||
let result = task.run(test_string).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(test_string) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, 5);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_complex_output() {
|
||||
// Test task_fn with complex output type
|
||||
let task = task_fn(|input: i32| async move { vec![input, input * 2, input * 3] });
|
||||
let task = task_fn::<i32, _, _>(|&input: &i32| vec![input, input * 2, input * 3]);
|
||||
|
||||
let result = task.run(5).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(5) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, vec![5, 10, 15]);
|
||||
}
|
||||
|
||||
@@ -62,9 +87,13 @@ async fn test_task_fn_with_complex_output() {
|
||||
async fn test_task_fn_stateful_closure() {
|
||||
// Test that task_fn can capture state
|
||||
let multiplier = 3;
|
||||
let task = task_fn(move |input: i32| async move { input * multiplier });
|
||||
let task = task_fn::<i32, _, _>(move |input: &i32| input * multiplier);
|
||||
|
||||
let result = task.run(7).await;
|
||||
let result = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(7) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result, 21);
|
||||
}
|
||||
|
||||
@@ -74,34 +103,30 @@ struct CustomTask {
|
||||
}
|
||||
|
||||
impl Task for CustomTask {
|
||||
type Input = i32;
|
||||
type Input = (i32,);
|
||||
type Output = i32;
|
||||
|
||||
#[allow(refining_impl_trait)]
|
||||
fn run(mut self, input: Self::Input) -> Pin<Box<dyn Future<Output = Self::Output> + Send>> {
|
||||
fn run(
|
||||
mut self,
|
||||
input: TaskInput<'_, Self::Input>,
|
||||
) -> Pin<Box<dyn Future<Output = Self::Output> + Send + '_>> {
|
||||
Box::pin(async move {
|
||||
self.state += input;
|
||||
self.state += input.next().0;
|
||||
self.state
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(refining_impl_trait)]
|
||||
fn extract_and_run(
|
||||
self,
|
||||
_dependencies: Vec<Arc<dyn std::any::Any + Send + Sync>>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Output, String>> + Send>> {
|
||||
Box::pin(async move {
|
||||
// This is a test helper - just return an error
|
||||
Err("extract_and_run not implemented for CustomTask (test helper)".to_string())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_custom_task_implementation() {
|
||||
let task = CustomTask { state: 10 };
|
||||
|
||||
let result1 = task.run(5).await;
|
||||
let result1 = task
|
||||
.run(TaskInput::new(
|
||||
vec![Arc::new(5) as Arc<dyn Any + Send + Sync + 'static>].iter(),
|
||||
))
|
||||
.await;
|
||||
assert_eq!(result1, 15);
|
||||
|
||||
// Can't call run again since task was consumed
|
||||
@@ -131,15 +156,21 @@ fn test_task_trait_bounds() {
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_single_call() {
|
||||
// Test that task_fn works (can only call once due to ownership)
|
||||
let task = task_fn(|x: i32| async move { x + 1 });
|
||||
let task = task_fn::<i32, _, _>(|x: &i32| x + 1);
|
||||
|
||||
assert_eq!(task.run(1).await, 2);
|
||||
assert_eq!(
|
||||
task.run(TaskInput::new(
|
||||
vec![Arc::new(1) as Arc<dyn Any + Send + Sync + 'static>].iter()
|
||||
))
|
||||
.await,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_result_type() {
|
||||
// Test task_fn returning Result
|
||||
let task = task_fn(|x: i32| async move {
|
||||
let task = task_fn::<i32, _, _>(|&x: &i32| {
|
||||
if x > 0 {
|
||||
Ok(x * 2)
|
||||
} else {
|
||||
@@ -147,30 +178,40 @@ async fn test_task_fn_with_result_type() {
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(task.run(5).await, Ok(10));
|
||||
assert_eq!(
|
||||
task.run(TaskInput::new(
|
||||
vec![Arc::new(5) as Arc<dyn Any + Send + Sync + 'static>].iter()
|
||||
))
|
||||
.await,
|
||||
Ok(10)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_with_option_type() {
|
||||
// Test task_fn returning Option
|
||||
let task = task_fn(|x: i32| async move {
|
||||
if x > 0 {
|
||||
Some(x * 2)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let task = task_fn::<i32, _, _>(|&x: &i32| if x > 0 { Some(x * 2) } else { None });
|
||||
|
||||
assert_eq!(task.run(5).await, Some(10));
|
||||
assert_eq!(
|
||||
task.run(TaskInput::new(
|
||||
vec![Arc::new(5) as Arc<dyn Any + Send + Sync + 'static>].iter()
|
||||
))
|
||||
.await,
|
||||
Some(10)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_task_fn_explicit_trait_call() {
|
||||
// Test explicit Task trait method call to cover line 121
|
||||
|
||||
let task = task_fn(|x: i32| async move { x * 3 });
|
||||
let task = task_fn::<i32, _, _>(|x: &i32| x * 3);
|
||||
|
||||
// Explicitly call the Task trait's run method
|
||||
let result = Task::run(task, 10).await;
|
||||
let result = Task::run(
|
||||
task,
|
||||
TaskInput::new(vec![Arc::new(10) as Arc<dyn Any + Send + Sync + 'static>].iter()),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(result, 30);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ async fn test_unit_type_taskbuilder_to_handle_conversion() {
|
||||
// Explicitly convert to TaskHandle using From implementation
|
||||
// This triggers the From<TaskBuilder> implementation at line 69-74,
|
||||
// specifically covering line 71
|
||||
let handle: TaskHandle<i32> = builder.into();
|
||||
let handle: TaskHandle<_> = builder.into();
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
@@ -76,7 +76,7 @@ async fn test_unit_type_conversion_with_multiple_tasks() {
|
||||
|
||||
// Convert each builder to handle explicitly
|
||||
let first_handle: TaskHandle<String> = first_builder.into();
|
||||
let second_handle: TaskHandle<i32> = second_builder.into();
|
||||
let second_handle: TaskHandle<_> = second_builder.into();
|
||||
let third_handle: TaskHandle<bool> = third_builder.into();
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
@@ -116,7 +116,7 @@ async fn test_unit_struct_with_state() {
|
||||
let builder = dag.add_task(StatefulTask::new(21));
|
||||
|
||||
// Explicit conversion - triggers line 71
|
||||
let handle: TaskHandle<i32> = builder.into();
|
||||
let handle: TaskHandle<_> = builder.into();
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
@@ -143,7 +143,6 @@ async fn test_taskbuilder_conversion_assignment() {
|
||||
// Conversion through type annotation and assignment
|
||||
// This also uses From<TaskBuilder> implementation
|
||||
let handle: TaskHandle<Vec<i32>> = builder.into();
|
||||
let id = handle.id;
|
||||
|
||||
dag.run(|fut| tokio::spawn(fut).map(Result::unwrap))
|
||||
.await
|
||||
@@ -151,13 +150,6 @@ async fn test_taskbuilder_conversion_assignment() {
|
||||
|
||||
let result = dag.get(handle).unwrap();
|
||||
assert_eq!(result, vec![1, 2, 3]);
|
||||
|
||||
// Verify the ID was preserved correctly through conversion
|
||||
let another_handle = TaskHandle::<Vec<i32>> {
|
||||
id,
|
||||
_phantom: std::marker::PhantomData,
|
||||
};
|
||||
assert_eq!(dag.get(another_handle).unwrap(), vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -184,7 +176,7 @@ async fn test_mixed_unit_and_dependent_tasks() {
|
||||
|
||||
// Source is unit-type, can be converted
|
||||
let source_builder = dag.add_task(Source);
|
||||
let source_handle: TaskHandle<i32> = source_builder.into(); // Covers line 71
|
||||
let source_handle: TaskHandle<_> = source_builder.into(); // Covers line 71
|
||||
|
||||
// Doubler needs dependencies, so we use it differently
|
||||
let doubler = dag.add_task(Doubler).depends_on(source_handle);
|
||||
@@ -260,9 +252,9 @@ fn test_multiple_conversions_preserve_ids() {
|
||||
let id3 = builder3.id;
|
||||
|
||||
// Convert all builders
|
||||
let handle1: TaskHandle<i32> = builder1.into();
|
||||
let handle2: TaskHandle<i32> = builder2.into();
|
||||
let handle3: TaskHandle<i32> = builder3.into();
|
||||
let handle1: TaskHandle<_> = builder1.into();
|
||||
let handle2: TaskHandle<_> = builder2.into();
|
||||
let handle3: TaskHandle<_> = builder3.into();
|
||||
|
||||
// Verify IDs are preserved and sequential
|
||||
assert_eq!(handle1.id, id1);
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ fn test_node_id_operations() {
|
||||
|
||||
#[test]
|
||||
fn test_task_handle_clone() {
|
||||
let handle: TaskHandle<i32> = TaskHandle {
|
||||
let handle: TaskHandle<(i32,)> = TaskHandle {
|
||||
id: NodeId(42),
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
@@ -129,7 +129,7 @@ fn test_task_builder_from_conversion() {
|
||||
let builder_id = builder.id;
|
||||
|
||||
// This conversion uses the From implementation
|
||||
let handle: TaskHandle<i32> = builder.into();
|
||||
let handle: TaskHandle<_> = builder.into();
|
||||
assert_eq!(handle.id, builder_id);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user