use super::*;
use crate::test_utils::{
with_async_component_id, with_async_hook_context, with_async_test_isolate,
};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_basic_future_success() {
with_async_test_isolate(|| async {
with_async_component_id("BasicFutureComponent", |_context| async {
let handle = use_future(
|| async { Ok::<i32, String>(42) },
(), );
assert!(handle.is_pending());
assert_eq!(handle.state(), FutureState::Pending);
sleep(Duration::from_millis(50)).await;
assert!(
handle.is_resolved(),
"Future should be resolved after waiting"
);
assert_eq!(handle.value(), Some(42));
assert_eq!(handle.state(), FutureState::Resolved(42));
})
.await;
})
.await;
}
#[tokio::test]
async fn test_basic_future_error() {
with_async_test_isolate(|| async {
with_async_component_id("ErrorFutureComponent", |_context| async {
let handle = use_future(
|| async { Err::<i32, String>("Test error".to_string()) },
(),
);
assert!(handle.is_pending());
sleep(Duration::from_millis(50)).await;
assert!(
handle.is_error(),
"Future should be in error state after waiting"
);
assert_eq!(handle.error(), Some("Test error".to_string()));
assert_eq!(handle.state(), FutureState::Error("Test error".to_string()));
})
.await;
})
.await;
}
#[tokio::test]
async fn test_future_with_dependencies() {
with_async_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_async_component_id("DependencyFutureComponent", |_context| async {
let counter_clone = counter.clone();
let handle1 = use_future(
move || {
let counter = counter_clone.clone();
async move {
counter.fetch_add(1, Ordering::SeqCst);
Ok::<usize, String>(42)
}
},
1, );
sleep(Duration::from_millis(10)).await;
assert_eq!(counter.load(Ordering::SeqCst), 1);
assert!(handle1.is_resolved());
})
.await;
with_async_component_id("DependencyFutureComponent", |_context| async {
let counter_clone2 = counter.clone();
let _handle2 = use_future(
move || {
let counter = counter_clone2.clone();
async move {
counter.fetch_add(1, Ordering::SeqCst);
Ok::<usize, String>(42)
}
},
1, );
sleep(Duration::from_millis(10)).await;
assert_eq!(counter.load(Ordering::SeqCst), 1);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_future_dependency_change() {
with_async_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
let results = Arc::new(Mutex::new(Vec::new()));
with_async_hook_context(|_context| async {
let counter_clone = counter.clone();
let results_clone = results.clone();
let handle = use_future(
move || {
let counter = counter_clone.clone();
let results = results_clone.clone();
async move {
let count = counter.fetch_add(1, Ordering::SeqCst);
let result = format!("execution_{}", count);
results.lock().unwrap().push(result.clone());
Ok::<String, String>(result)
}
},
1, );
sleep(Duration::from_millis(10)).await;
assert!(handle.is_resolved());
})
.await;
with_async_hook_context(|_context| async {
let counter_clone = counter.clone();
let results_clone = results.clone();
let handle = use_future(
move || {
let counter = counter_clone.clone();
let results = results_clone.clone();
async move {
let count = counter.fetch_add(1, Ordering::SeqCst);
let result = format!("execution_{}", count);
results.lock().unwrap().push(result.clone());
Ok::<String, String>(result)
}
},
2, );
sleep(Duration::from_millis(10)).await;
assert!(handle.is_resolved());
})
.await;
assert_eq!(counter.load(Ordering::SeqCst), 2);
let results_vec = results.lock().unwrap();
assert_eq!(results_vec.len(), 2);
assert_eq!(results_vec[0], "execution_0");
assert_eq!(results_vec[1], "execution_1");
})
.await;
}
#[tokio::test]
async fn test_future_state_methods() {
let pending: FutureState<i32, String> = FutureState::Pending;
assert!(pending.is_pending());
assert!(!pending.is_resolved());
assert!(!pending.is_error());
assert_eq!(pending.error(), None);
let resolved: FutureState<i32, String> = FutureState::Resolved(42);
assert!(!resolved.is_pending());
assert!(resolved.is_resolved());
assert!(!resolved.is_error());
assert_eq!(resolved.value(), Some(&42));
assert_eq!(resolved.error(), None);
let error: FutureState<i32, String> = FutureState::Error("test error".to_string());
assert!(!error.is_pending());
assert!(!error.is_resolved());
assert!(error.is_error());
assert_eq!(error.value(), None);
assert_eq!(error.error(), Some(&"test error".to_string()));
}
#[tokio::test]
async fn test_future_state_map() {
let resolved: FutureState<i32, String> = FutureState::Resolved(42);
let mapped = resolved.map(|x| x * 2);
assert_eq!(mapped, FutureState::Resolved(84));
let pending: FutureState<i32, String> = FutureState::Pending;
let mapped_pending = pending.map(|x| x * 2);
assert_eq!(mapped_pending, FutureState::Pending);
let error: FutureState<i32, String> = FutureState::Error("test".to_string());
let mapped_error = error.map(|x: i32| x * 2);
assert_eq!(mapped_error, FutureState::Error("test".to_string()));
}
#[tokio::test]
async fn test_future_state_map_err() {
let error: FutureState<i32, String> = FutureState::Error("test".to_string());
let mapped = error.map_err(|e| format!("Error: {}", e));
assert_eq!(mapped, FutureState::Error("Error: test".to_string()));
let resolved: FutureState<i32, String> = FutureState::Resolved(42);
let mapped_resolved = resolved.map_err(|e: String| format!("Error: {}", e));
assert_eq!(mapped_resolved, FutureState::Resolved(42));
}
#[tokio::test]
async fn test_future_handle_clone() {
with_async_test_isolate(|| async {
with_async_component_id("CloneFutureComponent", |_context| async {
let handle = use_future(|| async { Ok::<i32, String>(42) }, ());
let handle_clone = handle.clone();
sleep(Duration::from_millis(50)).await;
assert_eq!(handle.state(), handle_clone.state());
assert_eq!(handle.value(), handle_clone.value());
assert!(handle.is_resolved(), "Original handle should be resolved");
assert!(
handle_clone.is_resolved(),
"Cloned handle should be resolved"
);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_optimized_state_access() {
with_async_test_isolate(|| async {
with_async_component_id("OptimizedStateComponent", |_context| async {
let handle = use_future(
|| async { Ok::<String, String>("test_value".to_string()) },
(),
);
sleep(Duration::from_millis(50)).await;
assert!(
handle.is_resolved(),
"Future should be resolved after waiting"
);
assert!(!handle.is_pending());
assert!(!handle.is_error());
assert_eq!(handle.value(), Some("test_value".to_string()));
assert_eq!(handle.error(), None);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_memory_cleanup_on_drop() {
static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone)]
struct DropTracker;
impl Drop for DropTracker {
fn drop(&mut self) {
DROP_COUNT.fetch_add(1, Ordering::SeqCst);
}
}
with_async_test_isolate(|| async {
let _initial_count = DROP_COUNT.load(Ordering::SeqCst);
{
let _handle = with_async_hook_context(|_context| async {
use_future(
|| async {
let _tracker = DropTracker;
Ok::<String, String>("test".to_string())
},
(),
)
})
.await;
sleep(Duration::from_millis(10)).await;
}
sleep(Duration::from_millis(10)).await;
})
.await;
}
#[tokio::test]
async fn test_cancellation_cleanup() {
with_async_test_isolate(|| async {
let handle = with_async_hook_context(|_context| async {
use_future(
|| async {
sleep(Duration::from_secs(10)).await;
Ok::<String, String>("should_not_complete".to_string())
},
(),
)
})
.await;
assert!(handle.is_pending());
handle.cancel();
sleep(Duration::from_millis(10)).await;
assert!(handle.is_pending());
})
.await;
}
#[tokio::test]
async fn test_concurrent_state_access_performance() {
with_async_test_isolate(|| async {
with_async_component_id("ConcurrentStateComponent", |_context| async {
let handle = use_future(|| async { Ok::<i32, String>(42) }, ());
sleep(Duration::from_millis(50)).await;
let handle = Arc::new(handle);
let mut tasks = Vec::new();
for _ in 0..100 {
let handle_clone = handle.clone();
tasks.push(tokio::spawn(async move {
for _ in 0..10 {
let _ = handle_clone.is_resolved();
let _ = handle_clone.is_pending();
let _ = handle_clone.is_error();
let _ = handle_clone.value();
let _ = handle_clone.error();
}
}));
}
for task in tasks {
task.await.expect("Task should complete successfully");
}
assert!(handle.is_resolved());
assert_eq!(handle.value(), Some(42));
})
.await;
})
.await;
}
#[test]
fn test_state_access_performance_comparison() {
use std::time::Instant;
let handle = FutureHandle::<String, String>::new();
handle.set_state(FutureState::Resolved("test_value".to_string()));
let iterations = 10000;
let start = Instant::now();
for _ in 0..iterations {
let _ = handle.is_resolved();
let _ = handle.is_pending();
let _ = handle.is_error();
let _ = handle.value();
let _ = handle.error();
}
let optimized_duration = start.elapsed();
println!(
"Optimized state access for {} iterations: {:?}",
iterations, optimized_duration
);
assert!(
optimized_duration.as_millis() < 100,
"Optimized access should be fast"
);
}
#[tokio::test]
async fn test_resource_exhaustion_protection() {
with_async_test_isolate(|| async {
with_async_component_id("ResourceTestComponent", |_context| async {
let handle = use_future(|| async { Ok::<String, String>("test".to_string()) }, ());
sleep(Duration::from_millis(50)).await;
assert!(
handle.is_resolved(),
"Normal future should complete successfully"
);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_error_handling_security() {
with_async_test_isolate(|| async {
with_async_component_id("ErrorTestComponent", |_context| async {
let handle = use_future(
|| async {
Err::<String, String>("Security violation: unauthorized access".to_string())
},
(),
);
sleep(Duration::from_millis(50)).await;
assert!(handle.is_error(), "Failed future should be in error state");
if let Some(error) = handle.error() {
assert!(
error.contains("Security violation"),
"Error should contain detailed security information, got: {}",
error
);
} else {
panic!("Expected error information from failed future");
}
})
.await;
})
.await;
}