use lazily::Context;
use std::cell::Cell;
use std::rc::Rc;
#[test]
fn computed_ripple_when_custom_significance_propagates_on_proxy_change() {
let ctx = Context::new();
let input = ctx.source(0u64);
let derived = ctx.computed_ripple_when(
move |c| {
let v = c.get(&input);
(v, v / 10) },
|old, new| old.1 != new.1, );
let recomputes = Rc::new(Cell::new(0u32));
let r = recomputes.clone();
let observer = ctx.computed(move |c| {
r.set(r.get() + 1);
c.get(&derived).0
});
assert_eq!(ctx.get(&observer), 0);
let base = recomputes.get();
ctx.set(&input, 3);
assert_eq!(ctx.get(&observer), 0, "suppressed: proxy bucket unchanged");
assert_eq!(
recomputes.get(),
base,
"no dependent recompute within a bucket"
);
ctx.set(&input, 12);
assert_eq!(ctx.get(&observer), 12, "propagated: bucket changed");
assert_eq!(recomputes.get(), base + 1);
}
#[test]
fn computed_ripple_when_propagate_every_n_via_value_carried_counter() {
let ctx = Context::new();
let input = ctx.source(0u64);
let sampled = ctx.computed_ripple_when(move |c| c.get(&input), |old, new| new / 3 != old / 3);
let seen = Rc::new(Cell::new(0u32));
let s = seen.clone();
let observer = ctx.computed(move |c| {
s.set(s.get() + 1);
c.get(&sampled)
});
assert_eq!(ctx.get(&observer), 0);
let base = seen.get();
ctx.set(&input, 1);
ctx.set(&input, 2);
assert_eq!(ctx.get(&observer), 0);
assert_eq!(seen.get(), base, "window not crossed yet");
ctx.set(&input, 3);
assert_eq!(ctx.get(&observer), 3);
assert_eq!(seen.get(), base + 1);
}
#[test]
fn computed_is_computed_ripple_when_not_equal() {
let ctx = Context::new();
let input = ctx.source(0i64);
let via_computed = ctx.computed(move |c| c.get(&input).min(1));
let via_when = ctx.computed_ripple_when(move |c| c.get(&input).min(1), |o, n| o != n);
let ca = Rc::new(Cell::new(0u32));
let cb = Rc::new(Cell::new(0u32));
let (a, b) = (ca.clone(), cb.clone());
let obs_a = ctx.computed(move |c| {
a.set(a.get() + 1);
c.get(&via_computed)
});
let obs_b = ctx.computed(move |c| {
b.set(b.get() + 1);
c.get(&via_when)
});
assert_eq!(ctx.get(&obs_a), 0);
assert_eq!(ctx.get(&obs_b), 0);
let (base_a, base_b) = (ca.get(), cb.get());
ctx.set(&input, 5);
assert_eq!(ctx.get(&obs_a), 1);
assert_eq!(ctx.get(&obs_b), 1);
assert_eq!(ca.get(), base_a + 1);
assert_eq!(cb.get(), base_b + 1);
ctx.set(&input, 9);
assert_eq!(ctx.get(&obs_a), 1);
assert_eq!(ctx.get(&obs_b), 1);
assert_eq!(ca.get(), base_a + 1, "computed suppressed equal recompute");
assert_eq!(
cb.get(),
base_b + 1,
"computed_ripple_when(!=) matches computed"
);
}
#[test]
fn slot_is_pass_through_always_propagates() {
let ctx = Context::new();
let input = ctx.source(0u64);
let passthrough = ctx.slot(move |c| {
let _ = c.get(&input); 0u64
});
let recomputes = Rc::new(Cell::new(0u32));
let r = recomputes.clone();
let observer = ctx.computed(move |c| {
r.set(r.get() + 1);
c.get(&passthrough)
});
assert_eq!(ctx.get(&observer), 0);
let base = recomputes.get();
ctx.set(&input, 5);
assert_eq!(ctx.get(&observer), 0);
assert!(
recomputes.get() > base,
"pass-through slot propagates even when the value is unchanged"
);
}