use super::*;
use crate::state::use_state;
use crate::test_utils::{with_component_id, with_test_isolate};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::test]
async fn test_use_interval_basic() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("BasicIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(20),
);
});
sleep(Duration::from_millis(70)).await;
let count = counter.load(Ordering::Relaxed);
assert!(count >= 2, "Expected at least 2 executions, got {}", count);
assert!(count <= 6, "Expected at most 6 executions, got {}", count); })
.await;
}
#[tokio::test]
async fn test_use_interval_cleanup() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("CleanupIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(20), );
});
sleep(Duration::from_millis(50)).await;
let count_first = counter.load(Ordering::Relaxed);
with_component_id("CleanupIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(10, Ordering::Relaxed); },
Duration::from_millis(30), );
});
sleep(Duration::from_millis(80)).await;
let count_second = counter.load(Ordering::Relaxed);
let new_increments = count_second - count_first;
assert!(
new_increments >= 20, "Should see new interval pattern after cleanup. New increments: {}",
new_increments
);
})
.await;
}
#[tokio::test]
async fn test_use_interval_duration_change() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("DurationChangeIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(20),
);
});
sleep(Duration::from_millis(45)).await;
let count_first = counter.load(Ordering::Relaxed);
with_component_id("DurationChangeIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(5),
);
});
sleep(Duration::from_millis(25)).await;
let count_second = counter.load(Ordering::Relaxed);
let first_period_executions = count_first;
let second_period_executions = count_second - count_first;
assert!(
second_period_executions > first_period_executions,
"Faster interval should produce more executions. First: {}, Second: {}",
first_period_executions,
second_period_executions
);
})
.await;
}
#[tokio::test]
async fn test_use_interval_with_state() {
with_test_isolate(|| async {
with_component_id("StateIntervalComponent", |_context| {
let (count, set_count) = use_state(|| 0);
use_interval(
move || {
set_count.update(|prev| prev + 1);
},
Duration::from_millis(10),
);
assert_eq!(count.get(), 0);
});
sleep(Duration::from_millis(35)).await;
with_component_id("StateIntervalComponent", |_context| {
let (count, _) = use_state(|| 0);
let current_count = count.get();
assert!(
current_count >= 3,
"Expected at least 3 state updates, got {}",
current_count
);
});
})
.await;
}
#[tokio::test]
async fn test_multiple_intervals() {
with_test_isolate(|| async {
let counter1 = Arc::new(AtomicUsize::new(0));
let counter2 = Arc::new(AtomicUsize::new(0));
with_component_id("MultipleIntervalsComponent", |_context| {
let counter1_clone = counter1.clone();
let counter2_clone = counter2.clone();
use_interval(
move || {
counter1_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(10),
);
use_interval(
move || {
counter2_clone.fetch_add(2, Ordering::Relaxed);
},
Duration::from_millis(15),
);
});
sleep(Duration::from_millis(35)).await;
let count1 = counter1.load(Ordering::Relaxed);
let count2 = counter2.load(Ordering::Relaxed);
assert!(
count1 >= 3,
"First interval should have executed at least 3 times, got {}",
count1
);
assert!(
count2 >= 4,
"Second interval should have executed at least 2 times (2 per execution), got {}",
count2
);
assert!(
count1 > count2 / 2,
"First interval should execute more frequently"
);
})
.await;
}
#[tokio::test]
async fn test_use_interval_zero_duration() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("ZeroDurationIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(0),
);
});
sleep(Duration::from_millis(10)).await;
let count = counter.load(Ordering::Relaxed);
assert!(count > 0, "Zero duration interval should still execute");
})
.await;
}
#[tokio::test]
async fn test_use_interval_performance() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("PerformanceIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_interval(
move || {
counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(1),
);
});
sleep(Duration::from_millis(50)).await;
let count = counter.load(Ordering::Relaxed);
assert!(count >= 30, "Should handle rapid executions, got {}", count);
assert!(count <= 70, "Should not execute excessively, got {}", count);
})
.await;
}
#[tokio::test]
async fn test_use_async_interval_basic() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("BasicAsyncIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_async_interval(
move || {
let counter = counter_clone.clone();
async move {
counter.fetch_add(1, Ordering::Relaxed);
}
},
Duration::from_millis(10),
);
});
sleep(Duration::from_millis(35)).await;
let count = counter.load(Ordering::Relaxed);
assert!(count >= 3, "Expected at least 3 executions, got {}", count);
assert!(count <= 5, "Expected at most 5 executions, got {}", count); })
.await;
}
#[tokio::test]
async fn test_use_async_interval_with_async_work() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("AsyncWorkIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_async_interval(
move || {
let counter = counter_clone.clone();
async move {
sleep(Duration::from_millis(5)).await;
counter.fetch_add(1, Ordering::Relaxed);
}
},
Duration::from_millis(15),
);
});
sleep(Duration::from_millis(70)).await;
let count = counter.load(Ordering::Relaxed);
assert!(
count >= 3,
"Expected at least 3 executions with async work, got {}",
count
);
assert!(
count <= 6,
"Expected at most 6 executions with async work, got {}",
count
);
})
.await;
}
#[tokio::test]
async fn test_use_async_interval_cleanup() {
with_test_isolate(|| async {
let counter = Arc::new(AtomicUsize::new(0));
with_component_id("CleanupAsyncIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_async_interval(
move || {
let counter = counter_clone.clone();
async move {
counter.fetch_add(1, Ordering::Relaxed);
}
},
Duration::from_millis(10),
);
});
sleep(Duration::from_millis(25)).await;
let count_first = counter.load(Ordering::Relaxed);
with_component_id("CleanupAsyncIntervalComponent", |_context| {
let counter_clone = counter.clone();
use_async_interval(
move || {
let counter = counter_clone.clone();
async move {
counter.fetch_add(10, Ordering::Relaxed); }
},
Duration::from_millis(20), );
});
sleep(Duration::from_millis(45)).await;
let count_second = counter.load(Ordering::Relaxed);
let new_increments = count_second - count_first;
assert!(
new_increments >= 20, "Should see new async interval pattern after cleanup. New increments: {}",
new_increments
);
})
.await;
}
#[tokio::test]
async fn test_mixed_sync_and_async_intervals() {
with_test_isolate(|| async {
let sync_counter = Arc::new(AtomicUsize::new(0));
let async_counter = Arc::new(AtomicUsize::new(0));
with_component_id("MixedIntervalsComponent", |_context| {
let sync_counter_clone = sync_counter.clone();
let async_counter_clone = async_counter.clone();
use_interval(
move || {
sync_counter_clone.fetch_add(1, Ordering::Relaxed);
},
Duration::from_millis(20),
);
use_async_interval(
move || {
let counter = async_counter_clone.clone();
async move {
sleep(Duration::from_millis(1)).await; counter.fetch_add(2, Ordering::Relaxed);
}
},
Duration::from_millis(25),
);
});
sleep(Duration::from_millis(60)).await;
let sync_count = sync_counter.load(Ordering::Relaxed);
let async_count = async_counter.load(Ordering::Relaxed);
assert!(
sync_count >= 2,
"Sync interval should have executed at least 2 times, got {}",
sync_count
);
assert!(
async_count >= 4,
"Async interval should have executed at least 2 times (2 per execution), got {}",
async_count
);
assert!(
sync_count >= async_count / 2,
"Sync interval should execute at least as frequently as async interval (accounting for 2x multiplier), sync: {}, async: {}",
sync_count, async_count
);
})
.await;
}