use crate::state::use_state;
use crate::test_utils::{with_component_id, with_hook_context, with_test_isolate};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::{Duration, Instant};
#[test]
fn test_use_state_thread_safety() {
with_test_isolate(|| {
with_hook_context(|_context| {
let (state_handle, setter) = use_state(|| 0i32);
assert_eq!(state_handle.get(), 0);
let setter1 = setter.clone();
let setter2 = setter.clone();
let setter3 = setter.clone();
let barrier = Arc::new(Barrier::new(4));
let barrier1 = barrier.clone();
let barrier2 = barrier.clone();
let barrier3 = barrier.clone();
let handle1 = thread::spawn(move || {
barrier1.wait();
for _i in 0..100 {
setter1.update(|prev| prev + 1);
thread::sleep(Duration::from_micros(10));
}
});
let handle2 = thread::spawn(move || {
barrier2.wait();
for _i in 0..100 {
setter2.update(|prev| prev + 2);
thread::sleep(Duration::from_micros(10));
}
});
let handle3 = thread::spawn(move || {
barrier3.wait();
for _i in 0..100 {
setter3.update(|prev| prev + 3);
thread::sleep(Duration::from_micros(10));
}
});
barrier.wait();
handle1.join().unwrap();
handle2.join().unwrap();
handle3.join().unwrap();
let final_value = state_handle.get();
assert!(
(580..=620).contains(&final_value),
"Expected final value to be around 600, got {}",
final_value
);
});
});
}
#[test]
fn test_use_state_performance() {
with_test_isolate(|| {
with_component_id("PerformanceTestComponent", |_context| {
let (state_handle, setter) = use_state(|| 0u64);
assert_eq!(state_handle.get(), 0);
let start = Instant::now();
let num_updates = 10_000;
for i in 0..num_updates {
setter.set(i);
}
let duration = start.elapsed();
println!("Time for {} updates: {:?}", num_updates, duration);
assert_eq!(state_handle.get(), num_updates - 1);
assert!(
duration < Duration::from_millis(100),
"Updates took too long: {:?}",
duration
);
});
});
}
#[test]
fn test_use_state_concurrent_reads() {
with_test_isolate(|| {
with_hook_context(|_context| {
let (state_handle, setter) = use_state(|| 0i32);
assert_eq!(state_handle.get(), 0);
let container = setter.container().clone();
let read_count = Arc::new(AtomicUsize::new(0));
let read_count1 = read_count.clone();
let read_count2 = read_count.clone();
let barrier = Arc::new(Barrier::new(3));
let barrier1 = barrier.clone();
let barrier2 = barrier.clone();
let writer_handle = thread::spawn(move || {
barrier.wait();
for i in 0..1000 {
setter.set(i);
thread::sleep(Duration::from_micros(1));
}
});
let container1 = container.clone();
let reader1_handle = thread::spawn(move || {
barrier1.wait();
for _ in 0..2000 {
let _value = container1.get();
read_count1.fetch_add(1, Ordering::Relaxed);
thread::sleep(Duration::from_micros(1));
}
});
let container2 = container.clone();
let reader2_handle = thread::spawn(move || {
barrier2.wait();
for _ in 0..2000 {
let _value = container2.get();
read_count2.fetch_add(1, Ordering::Relaxed);
thread::sleep(Duration::from_micros(1));
}
});
writer_handle.join().unwrap();
reader1_handle.join().unwrap();
reader2_handle.join().unwrap();
assert_eq!(read_count.load(Ordering::Relaxed), 4000);
});
});
}
#[test]
fn test_use_state_persistence() {
with_test_isolate(|| {
with_component_id("PersistenceTestComponent", |_context| {
let (state_handle1, setter1) = use_state(|| "initial".to_string());
assert_eq!(state_handle1.get(), "initial");
setter1.set("updated".to_string());
});
with_component_id("PersistenceTestComponent", |_context| {
let (state_handle2, setter2) = use_state(|| "default".to_string());
assert_eq!(state_handle2.get(), "updated"); setter2.update(|prev| format!("{}_again", prev));
});
with_component_id("PersistenceTestComponent", |_context| {
let (state_handle3, _) = use_state(|| "default".to_string());
assert_eq!(state_handle3.get(), "updated_again");
});
});
}
#[test]
fn test_use_state_memory_cleanup() {
for iteration in 0..100 {
with_hook_context(|_context| {
let large_data = vec![iteration; 1000];
let (_, setter) = use_state(|| large_data.clone());
for i in 0..10 {
let new_data = vec![iteration + i; 1000];
setter.set(new_data);
}
});
}
}
#[test]
fn test_use_state_version_tracking() {
with_test_isolate(|| {
with_hook_context(|_context| {
let (_, setter) = use_state(|| 0);
let container = setter.container().clone();
let initial_version = container.version();
assert_eq!(initial_version, 0);
setter.set(1);
assert_eq!(container.version(), 1);
setter.set(2);
assert_eq!(container.version(), 2);
setter.update(|prev| prev + 1);
assert_eq!(container.version(), 3);
});
});
}
#[test]
fn test_use_state_field_access() {
#[derive(Clone)]
struct ComplexState {
count: i32,
name: String,
nested: NestedState,
}
#[derive(Clone)]
struct NestedState {
value: f64,
}
with_test_isolate(|| {
with_hook_context(|_context| {
let initial_state = ComplexState {
count: 42,
name: "test".to_string(),
nested: NestedState {
value: std::f64::consts::PI,
},
};
let (state_handle, _) = use_state(|| initial_state);
let count = state_handle.field(|s| s.count);
assert_eq!(count, 42);
let name_length = state_handle.field(|s| s.name.len());
assert_eq!(name_length, 4);
let nested_value = state_handle.field(|s| s.nested.value);
assert_eq!(nested_value, std::f64::consts::PI);
let is_even = state_handle.map(|s| s.count % 2 == 0);
assert!(is_even);
});
});
}