use std::cell::Cell;
use std::rc::Rc;
use tincan::Scope;
#[test]
fn test_scope_isolation() {
let cx1 = Scope::new();
let cx2 = Scope::new();
let signal1 = cx1.signal(1);
let signal2 = cx2.signal(2);
assert_eq!(signal1.get(), 1);
assert_eq!(signal2.get(), 2);
signal1.set(10);
signal2.set(20);
assert_eq!(signal1.get(), 10);
assert_eq!(signal2.get(), 20);
}
#[test]
fn test_scope_cleanup() {
let run_count = Rc::new(Cell::new(0));
{
let cx = Scope::new();
let count = cx.signal(0);
let count_clone = count.clone();
let run_count_clone = Rc::clone(&run_count);
let _effect = cx.effect(move || {
let _ = count_clone.get();
run_count_clone.set(run_count_clone.get() + 1);
});
assert_eq!(run_count.get(), 1);
count.set(5);
assert_eq!(run_count.get(), 2);
}
assert_eq!(run_count.get(), 2);
}
#[test]
fn test_scope_clear() {
let cx = Scope::new();
let signal = cx.signal(42);
assert_eq!(signal.get(), 42);
cx.clear();
signal.set(100);
assert_eq!(signal.get(), 100);
}
#[test]
fn test_scope_default() {
let cx = Scope::default();
let signal = cx.signal(42);
assert_eq!(signal.get(), 42);
}
#[test]
fn test_nested_scopes() {
let outer_cx = Scope::new();
let outer_signal = outer_cx.signal(1);
{
let inner_cx = Scope::new();
let inner_signal = inner_cx.signal(2);
assert_eq!(outer_signal.get(), 1);
assert_eq!(inner_signal.get(), 2);
inner_signal.set(20);
assert_eq!(inner_signal.get(), 20);
}
assert_eq!(outer_signal.get(), 1);
outer_signal.set(10);
assert_eq!(outer_signal.get(), 10);
}
#[test]
fn test_scope_with_many_signals() {
let cx = Scope::new();
let signals: Vec<_> = (0..100).map(|i| cx.signal(i)).collect();
for (i, signal) in signals.iter().enumerate() {
assert_eq!(signal.get(), i);
}
for (i, signal) in signals.iter().enumerate() {
signal.set(i * 2);
}
for (i, signal) in signals.iter().enumerate() {
assert_eq!(signal.get(), i * 2);
}
}
#[test]
fn test_scope_with_many_effects() {
let cx = Scope::new();
let signal = cx.signal(0);
let counters: Vec<_> = (0..10).map(|_| Rc::new(Cell::new(0))).collect();
let _effects: Vec<_> = counters
.iter()
.map(|counter| {
let signal_clone = signal.clone();
let counter_clone = Rc::clone(counter);
cx.effect(move || {
let _ = signal_clone.get();
counter_clone.set(counter_clone.get() + 1);
})
})
.collect();
for counter in &counters {
assert_eq!(counter.get(), 1);
}
signal.set(5);
for counter in &counters {
assert_eq!(counter.get(), 2);
}
}
#[test]
fn test_complex_dependency_graph() {
let cx = Scope::new();
let root = cx.signal(1);
let left = cx.memo({
let root = root.clone();
move || root.get() * 2
});
let right = cx.memo({
let root = root.clone();
move || root.get() * 3
});
let bottom = cx.memo({
let left = left.clone();
let right = right.clone();
move || left.get() + right.get()
});
assert_eq!(bottom.get(), 5);
root.set(2);
assert_eq!(bottom.get(), 10);
root.set(10);
assert_eq!(bottom.get(), 50); }
#[test]
fn test_deep_dependency_chain() {
let cx = Scope::new();
let input = cx.signal(1);
let mut current = input.clone().map(|x| *x);
for _ in 0..10 {
current = current.map(|x| *x + 1);
}
assert_eq!(current.get(), 11);
input.set(5);
assert_eq!(current.get(), 15); }
#[test]
fn test_wide_dependency_graph() {
let cx = Scope::new();
let root = cx.signal(10);
let derived: Vec<_> = (0..20)
.map(|i| {
let root = root.clone();
cx.memo(move || root.get() + i)
})
.collect();
for (i, memo) in derived.iter().enumerate() {
assert_eq!(memo.get(), 10 + i);
}
root.set(100);
for (i, memo) in derived.iter().enumerate() {
assert_eq!(memo.get(), 100 + i);
}
}
#[test]
fn test_memo_deduplication() {
let cx = Scope::new();
let a = cx.signal(1);
let b = cx.signal(1);
let compute_count = Rc::new(Cell::new(0));
let sum = cx.memo({
let a = a.clone();
let b = b.clone();
let compute_count = Rc::clone(&compute_count);
move || {
compute_count.set(compute_count.get() + 1);
a.get() + b.get()
}
});
assert_eq!(sum.get(), 2);
assert_eq!(compute_count.get(), 1);
a.set(1);
assert_eq!(sum.get(), 2);
assert_eq!(compute_count.get(), 2);
a.set(5);
assert_eq!(sum.get(), 6);
assert_eq!(compute_count.get(), 3);
}
#[test]
fn test_circular_update_prevention() {
let cx = Scope::new();
let a = cx.signal(0);
let b = cx.signal(0);
let update_count = Rc::new(Cell::new(0));
let a_clone = a.clone();
let b_clone = b.clone();
let update_count_clone = Rc::clone(&update_count);
let _effect = cx.effect(move || {
let count = update_count_clone.get();
update_count_clone.set(count + 1);
if count < 10 {
let val_a = a_clone.get();
if val_a < 5 {
b_clone.set(val_a + 1);
}
}
});
a.set(1);
assert!(update_count.get() > 1);
assert!(update_count.get() <= 10);
}
#[test]
fn test_signal_map_propagation() {
let cx = Scope::new();
let base = cx.signal(10);
let doubled = base.map(|x| x * 2);
let tripled = doubled.map(|x| x + 10);
assert_eq!(tripled.get(), 30);
base.set(20);
assert_eq!(tripled.get(), 50); }
#[test]
fn test_multiple_watchers() {
let cx = Scope::new();
let signal = cx.signal(0);
let count1 = Rc::new(Cell::new(0));
let count2 = Rc::new(Cell::new(0));
let count3 = Rc::new(Cell::new(0));
let count1_clone = Rc::clone(&count1);
let _guard1 = signal.watch(move |_| {
count1_clone.set(count1_clone.get() + 1);
});
let count2_clone = Rc::clone(&count2);
let _guard2 = signal.watch(move |_| {
count2_clone.set(count2_clone.get() + 1);
});
let count3_clone = Rc::clone(&count3);
let _guard3 = signal.watch(move |_| {
count3_clone.set(count3_clone.get() + 1);
});
assert_eq!(count1.get(), 1);
assert_eq!(count2.get(), 1);
assert_eq!(count3.get(), 1);
signal.set(5);
assert_eq!(count1.get(), 2);
assert_eq!(count2.get(), 2);
assert_eq!(count3.get(), 2);
}
#[test]
fn test_scope_stress_test() {
let cx = Scope::new();
let inputs: Vec<_> = (0..10).map(|i| cx.signal(i)).collect();
let memos: Vec<_> = inputs
.iter()
.map(|input| {
let input = input.clone();
cx.memo(move || input.get() * 2)
})
.collect();
let sum = cx.memo({
let memos = memos.clone();
move || memos.iter().map(|m| m.get()).sum::<i32>()
});
assert_eq!(sum.get(), 90);
for (i, input) in inputs.iter().enumerate() {
input.set((i * 2) as i32);
}
assert_eq!(sum.get(), 180); }
#[test]
fn test_empty_scope() {
let cx = Scope::new();
drop(cx);
}
#[test]
fn test_signal_with_large_value() {
let cx = Scope::new();
let large_vec: Vec<i32> = (0..10000).collect();
let signal = cx.signal(large_vec.clone());
assert_eq!(signal.get(), large_vec);
let new_vec: Vec<i32> = (0..10000).map(|x| x * 2).collect();
signal.set(new_vec.clone());
assert_eq!(signal.get(), new_vec);
}
#[test]
fn test_concurrent_scope_independence() {
let cx1 = Scope::new();
let cx2 = Scope::new();
let sig1 = cx1.signal(1);
let sig2 = cx2.signal(2);
let run1 = Rc::new(Cell::new(0));
let run2 = Rc::new(Cell::new(0));
let sig1_clone = sig1.clone();
let run1_clone = Rc::clone(&run1);
let _effect1 = cx1.effect(move || {
let _ = sig1_clone.get();
run1_clone.set(run1_clone.get() + 1);
});
let sig2_clone = sig2.clone();
let run2_clone = Rc::clone(&run2);
let _effect2 = cx2.effect(move || {
let _ = sig2_clone.get();
run2_clone.set(run2_clone.get() + 1);
});
assert_eq!(run1.get(), 1);
assert_eq!(run2.get(), 1);
sig1.set(10);
assert_eq!(run1.get(), 2);
assert_eq!(run2.get(), 1);
sig2.set(20);
assert_eq!(run1.get(), 2); assert_eq!(run2.get(), 2);
}