use crate::state::use_state;
use crate::test_utils::{
with_async_component_id, with_async_test_isolate, with_component_id, with_hook_context,
with_test_isolate,
};
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
#[test]
fn test_use_effect_basic() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("BasicEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect::<(), _, Box<dyn FnOnce() + Send>>(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>> },
None,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("BasicEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect::<i32, _, _>(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
None,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
});
});
}
#[test]
fn test_use_effect_empty_deps() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("EmptyDepsEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("EmptyDepsEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
});
}
#[test]
fn test_use_effect_changing_deps() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("ChangingDepsEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
1,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("ChangingDepsEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
1,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("ChangingDepsEffectComponent", |_context| {
let effect_ran_clone3 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone3.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
2,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
});
});
}
#[test]
fn test_use_effect_cleanup() {
with_test_isolate(|| {
let cleanup_ran = Arc::new(AtomicUsize::new(0));
with_component_id("CleanupEffectComponent", |_context| {
let cleanup_ran_clone = cleanup_ran.clone();
use_effect(
move || {
Some(move || {
cleanup_ran_clone.fetch_add(1, Ordering::Relaxed);
})
},
1,
);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
});
with_component_id("CleanupEffectComponent", |_context| {
let cleanup_ran_clone2 = cleanup_ran.clone();
use_effect(
move || {
Some(move || {
cleanup_ran_clone2.fetch_add(1, Ordering::Relaxed);
})
},
2,
);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 1);
});
});
}
#[test]
fn test_use_effect_tuple_deps() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("TupleDepsEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(1, "hello"),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("TupleDepsEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(1, "hello"),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("TupleDepsEffectComponent", |_context| {
let effect_ran_clone3 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone3.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(2, "hello"),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
});
with_component_id("TupleDepsEffectComponent", |_context| {
let effect_ran_clone4 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone4.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
(2, "world"),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 3);
});
});
}
#[test]
fn test_use_effect_complex_deps() {
#[derive(Clone, PartialEq, Debug, Hash)]
struct CustomDeps {
id: u32,
name: String,
active: bool,
}
impl EffectDependencies for CustomDeps {
fn deps_eq(&self, other: &dyn EffectDependencies) -> bool {
if let Some(other_deps) = other.as_any().downcast_ref::<CustomDeps>() {
self == other_deps
} else {
false
}
}
fn clone_deps(&self) -> Box<dyn EffectDependencies> {
Box::new(self.clone())
}
fn debug_deps(&self) -> String {
format!("{:?}", self)
}
fn deps_hash(&self) -> u64 {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
self.hash(&mut hasher);
hasher.finish()
}
}
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
let deps1 = CustomDeps {
id: 1,
name: "test".to_string(),
active: true,
};
with_component_id("ComplexDepsEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
deps1.clone(),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("ComplexDepsEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
deps1.clone(),
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("ComplexDepsEffectComponent", |_context| {
let effect_ran_clone3 = effect_ran.clone();
let deps2 = CustomDeps {
id: 1,
name: "test".to_string(),
active: false, };
use_effect(
move || {
effect_ran_clone3.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
deps2,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
});
});
}
#[test]
fn test_use_effect_execution_order() {
with_test_isolate(|| {
with_hook_context(|_context| {
let execution_order = Arc::new(Mutex::new(Vec::new()));
let order_clone1 = execution_order.clone();
use_effect(
move || {
order_clone1.lock().unwrap().push(1);
None::<Box<dyn FnOnce() + Send>>
},
(),
);
let order_clone2 = execution_order.clone();
use_effect(
move || {
order_clone2.lock().unwrap().push(2);
None::<Box<dyn FnOnce() + Send>>
},
(),
);
let order_clone3 = execution_order.clone();
use_effect(
move || {
order_clone3.lock().unwrap().push(3);
None::<Box<dyn FnOnce() + Send>>
},
(),
);
let order = execution_order.lock().unwrap();
assert_eq!(*order, vec![1, 2, 3]);
});
});
}
#[test]
fn test_use_effect_cleanup_timing() {
with_test_isolate(|| {
let events = Arc::new(std::sync::Mutex::new(Vec::new()));
with_component_id("CleanupTimingEffectComponent", |_context| {
let events_clone1 = events.clone();
let events_clone1_cleanup = events.clone();
use_effect(
move || {
events_clone1.lock().unwrap().push("effect1".to_string());
Some(move || {
events_clone1_cleanup
.lock()
.unwrap()
.push("cleanup1".to_string());
})
},
1,
);
{
let events_vec = events.lock().unwrap();
assert_eq!(*events_vec, vec!["effect1"]);
}
});
with_component_id("CleanupTimingEffectComponent", |_context| {
let events_clone2 = events.clone();
let events_clone2_cleanup = events.clone();
use_effect(
move || {
events_clone2.lock().unwrap().push("effect2".to_string());
Some(move || {
events_clone2_cleanup
.lock()
.unwrap()
.push("cleanup2".to_string());
})
},
2,
);
{
let events_vec = events.lock().unwrap();
assert_eq!(*events_vec, vec!["effect1", "cleanup1", "effect2"]);
}
});
});
}
#[test]
fn test_use_effect_multiple_cleanups() {
with_test_isolate(|| {
let cleanup1_ran = Arc::new(AtomicUsize::new(0));
let cleanup2_ran = Arc::new(AtomicUsize::new(0));
with_component_id("MultipleCleanupEffectComponent", |_context| {
let cleanup1_clone = cleanup1_ran.clone();
use_effect(
move || {
Some(move || {
cleanup1_clone.fetch_add(1, Ordering::Relaxed);
})
},
1,
);
let cleanup2_clone = cleanup2_ran.clone();
use_effect(
move || {
Some(move || {
cleanup2_clone.fetch_add(1, Ordering::Relaxed);
})
},
"test",
);
assert_eq!(cleanup1_ran.load(Ordering::Relaxed), 0);
assert_eq!(cleanup2_ran.load(Ordering::Relaxed), 0);
});
with_component_id("MultipleCleanupEffectComponent", |_context| {
let cleanup1_clone2 = cleanup1_ran.clone();
use_effect(
move || {
Some(move || {
cleanup1_clone2.fetch_add(1, Ordering::Relaxed);
})
},
2, );
let cleanup2_clone2 = cleanup2_ran.clone();
use_effect(
move || {
Some(move || {
cleanup2_clone2.fetch_add(1, Ordering::Relaxed);
})
},
"test", );
assert_eq!(cleanup1_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup2_ran.load(Ordering::Relaxed), 0);
});
});
}
#[test]
fn test_use_effect_with_use_state() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("StateIntegrationEffectComponent", |_context| {
let (count_handle, set_count) = use_state(|| 0);
let count = count_handle.get();
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
count,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
set_count.set(1);
});
with_component_id("StateIntegrationEffectComponent", |_context| {
let (count_handle2, _) = use_state(|| 0); let count2 = count_handle2.get();
let effect_ran_clone2 = effect_ran.clone();
use_effect(
move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
count2,
);
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
});
});
}
#[test]
#[should_panic(expected = "with_hook_context must be called within a hook context")]
fn test_use_effect_outside_context() {
use_effect::<(), _, _>(|| None::<Box<dyn FnOnce() + Send>>, None);
}
#[test]
fn test_use_effect_rapid_changes() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
let cleanup_ran = Arc::new(AtomicUsize::new(0));
for i in 0..100 {
with_component_id("RapidChangesEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
let cleanup_ran_clone = cleanup_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
Some(move || {
cleanup_ran_clone.fetch_add(1, Ordering::Relaxed);
})
},
i,
);
});
}
assert_eq!(effect_ran.load(Ordering::Relaxed), 100);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 99);
});
}
#[test]
fn test_use_effect_thread_safety() {
use std::sync::Barrier;
use std::thread;
let effect_count = Arc::new(AtomicUsize::new(0));
let barrier = Arc::new(Barrier::new(4));
let mut handles = vec![];
for i in 0..3 {
let effect_count_clone = effect_count.clone();
let barrier_clone = barrier.clone();
let handle = thread::spawn(move || {
with_hook_context(|_context| {
barrier_clone.wait();
use_effect(
move || {
effect_count_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
i,
);
});
});
handles.push(handle);
}
barrier.wait();
for handle in handles {
handle.join().unwrap();
}
assert_eq!(effect_count.load(Ordering::Relaxed), 3);
}
#[test]
fn test_use_effect_dependency_performance() {
use std::time::Instant;
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
let large_deps = (1, 2, 3, 4, 5, 6, 7, 8);
let start = Instant::now();
for _ in 0..1000 {
with_component_id("DependencyPerformanceEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect(
move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
None::<Box<dyn FnOnce() + Send>>
},
large_deps,
);
});
}
let duration = start.elapsed();
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert!(
duration < std::time::Duration::from_millis(100),
"Dependency comparison took too long: {:?}",
duration
);
});
}
#[test]
fn test_use_effect_memory_cleanup() {
for iteration in 0..100 {
with_hook_context(|_context| {
let large_data = vec![iteration; 1000];
use_effect(
move || {
let _data = large_data; Some(move || {
let _cleanup_data = vec![iteration; 1000];
})
},
iteration,
);
for i in 0..10 {
let data = vec![i; 100];
use_effect(
move || {
let _data = data;
None::<Box<dyn FnOnce() + Send>>
},
i,
);
}
});
}
}
#[test]
fn test_use_effect_scheduling_overhead() {
use std::time::Instant;
with_test_isolate(|| {
with_hook_context(|_context| {
let start = Instant::now();
for i in 0..1000 {
use_effect(
move || {
None::<Box<dyn FnOnce() + Send>>
},
i,
);
}
let duration = start.elapsed();
assert!(
duration < std::time::Duration::from_millis(100),
"Effect creation took too long: {:?}",
duration
);
});
});
}
#[test]
fn test_use_effect_cleanup_management() {
with_test_isolate(|| {
let cleanup_count = Arc::new(AtomicUsize::new(0));
with_component_id("CleanupManagementEffectComponent", |_context| {
let cleanup_count_clone = cleanup_count.clone();
use_effect(
move || {
Some(move || {
cleanup_count_clone.fetch_add(1, Ordering::Relaxed);
})
},
1,
);
});
for i in 2..=100 {
with_component_id("CleanupManagementEffectComponent", |_context| {
let cleanup_count_clone = cleanup_count.clone();
use_effect(
move || {
Some(move || {
cleanup_count_clone.fetch_add(1, Ordering::Relaxed);
})
},
i,
);
});
}
assert_eq!(cleanup_count.load(Ordering::Relaxed), 99);
});
}
#[tokio::test]
async fn test_use_async_effect_basic() {
with_async_test_isolate(|| async {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_async_component_id("BasicAsyncEffectComponent", |_context| async {
let effect_ran_clone = effect_ran.clone();
use_async_effect::<(), _, _, _, _>(
move || {
let effect_ran_inner = effect_ran_clone.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
None,
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
with_async_component_id("BasicAsyncEffectComponent", |_context| async {
let effect_ran_clone2 = effect_ran.clone();
use_async_effect::<(), _, _, _, _>(
move || {
let effect_ran_inner = effect_ran_clone2.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
None,
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_use_async_effect_empty_deps() {
with_async_test_isolate(|| async {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_async_component_id("EmptyDepsAsyncEffectComponent", |_context| async {
let effect_ran_clone = effect_ran.clone();
use_async_effect(
move || {
let effect_ran_inner = effect_ran_clone.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
(),
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
with_async_component_id("EmptyDepsAsyncEffectComponent", |_context| async {
let effect_ran_clone2 = effect_ran.clone();
use_async_effect(
move || {
let effect_ran_inner = effect_ran_clone2.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
(),
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_use_async_effect_changing_deps() {
with_async_test_isolate(|| async {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_async_component_id("ChangingDepsAsyncEffectComponent", |_context| async {
let effect_ran_clone = effect_ran.clone();
use_async_effect(
move || {
let effect_ran_inner = effect_ran_clone.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
1,
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
with_async_component_id("ChangingDepsAsyncEffectComponent", |_context| async {
let effect_ran_clone2 = effect_ran.clone();
use_async_effect(
move || {
let effect_ran_inner = effect_ran_clone2.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
1,
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
with_async_component_id("ChangingDepsAsyncEffectComponent", |_context| async {
let effect_ran_clone3 = effect_ran.clone();
use_async_effect(
move || {
let effect_ran_inner = effect_ran_clone3.clone();
async move {
effect_ran_inner.fetch_add(1, Ordering::Relaxed);
None::<
fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,
>
}
},
2,
);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
})
.await;
})
.await;
}
#[test]
fn test_use_effect_once() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
let cleanup_ran = Arc::new(AtomicUsize::new(0));
with_component_id("OnceEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
let cleanup_ran_clone = cleanup_ran.clone();
use_effect_once(move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
move || {
cleanup_ran_clone.fetch_add(1, Ordering::Relaxed);
}
});
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
});
with_component_id("OnceEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
let cleanup_ran_clone2 = cleanup_ran.clone();
use_effect_once(move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
move || {
cleanup_ran_clone2.fetch_add(1, Ordering::Relaxed);
}
});
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
});
});
}
#[test]
fn test_use_effect_always() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
let cleanup_ran = Arc::new(AtomicUsize::new(0));
with_component_id("AlwaysEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
let cleanup_ran_clone = cleanup_ran.clone();
use_effect_always(move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
move || {
cleanup_ran_clone.fetch_add(1, Ordering::Relaxed);
}
});
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
});
with_component_id("AlwaysEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
let cleanup_ran_clone2 = cleanup_ran.clone();
use_effect_always(move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
move || {
cleanup_ran_clone2.fetch_add(1, Ordering::Relaxed);
}
});
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 1);
});
with_component_id("AlwaysEffectComponent", |_context| {
let effect_ran_clone3 = effect_ran.clone();
let cleanup_ran_clone3 = cleanup_ran.clone();
use_effect_always(move || {
effect_ran_clone3.fetch_add(1, Ordering::Relaxed);
move || {
cleanup_ran_clone3.fetch_add(1, Ordering::Relaxed);
}
});
assert_eq!(effect_ran.load(Ordering::Relaxed), 3);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 2);
});
});
}
#[tokio::test]
async fn test_use_async_effect_once() {
with_async_test_isolate(|| async {
let effect_ran = Arc::new(AtomicUsize::new(0));
let cleanup_ran = Arc::new(AtomicUsize::new(0));
with_async_component_id("AsyncOnceEffectComponent", |_context| async {
let effect_ran_clone = effect_ran.clone();
let cleanup_ran_clone = cleanup_ran.clone();
use_async_effect_once(move || async move {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
move || async move {
cleanup_ran_clone.fetch_add(1, Ordering::Relaxed);
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
})
.await;
with_async_component_id("AsyncOnceEffectComponent", |_context| async {
let effect_ran_clone2 = effect_ran.clone();
let cleanup_ran_clone2 = cleanup_ran.clone();
use_async_effect_once(move || async move {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
move || async move {
cleanup_ran_clone2.fetch_add(1, Ordering::Relaxed);
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
assert_eq!(cleanup_ran.load(Ordering::Relaxed), 0);
})
.await;
})
.await;
}
#[tokio::test]
async fn test_use_async_effect_always() {
with_async_test_isolate(|| async {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_async_component_id("AsyncAlwaysEffectComponent", |_context| async {
let effect_ran_clone = effect_ran.clone();
use_async_effect_always(move || async move {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
|| async move {
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
})
.await;
with_async_component_id("AsyncAlwaysEffectComponent", |_context| async {
let effect_ran_clone2 = effect_ran.clone();
use_async_effect_always(move || async move {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
|| async move {
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 2);
})
.await;
with_async_component_id("AsyncAlwaysEffectComponent", |_context| async {
let effect_ran_clone3 = effect_ran.clone();
use_async_effect_always(move || async move {
effect_ran_clone3.fetch_add(1, Ordering::Relaxed);
|| async move {
}
});
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
assert_eq!(effect_ran.load(Ordering::Relaxed), 3);
})
.await;
})
.await;
}
#[test]
fn test_use_effect_once_empty_cleanup() {
with_test_isolate(|| {
let effect_ran = Arc::new(AtomicUsize::new(0));
with_component_id("OnceEmptyCleanupEffectComponent", |_context| {
let effect_ran_clone = effect_ran.clone();
use_effect_once(move || {
effect_ran_clone.fetch_add(1, Ordering::Relaxed);
|| {} });
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
with_component_id("OnceEmptyCleanupEffectComponent", |_context| {
let effect_ran_clone2 = effect_ran.clone();
use_effect_once(move || {
effect_ran_clone2.fetch_add(1, Ordering::Relaxed);
|| {} });
assert_eq!(effect_ran.load(Ordering::Relaxed), 1);
});
});
}