use crate::expert::{AnchorExt, AnchorSplit};
#[test]
fn test_cutoff_simple_observed() {
let mut engine = crate::singlethread::Engine::new();
let (v, v_setter) = crate::expert::Var::new(100i32);
let mut old_val = 0i32;
let post_cutoff = v
.cutoff(move |new_val| {
if (old_val - *new_val).abs() < 50 {
false
} else {
old_val = *new_val;
true
}
})
.map(|v| *v + 10);
engine.mark_observed(&post_cutoff);
assert_eq!(engine.get(&post_cutoff), 110);
v_setter.set(125);
assert_eq!(engine.get(&post_cutoff), 110);
v_setter.set(151);
assert_eq!(engine.get(&post_cutoff), 161);
v_setter.set(125);
assert_eq!(engine.get(&post_cutoff), 161);
}
#[test]
fn test_cutoff_simple_unobserved() {
let mut engine = crate::singlethread::Engine::new();
let (v, v_setter) = crate::expert::Var::new(100i32);
let mut old_val = 0i32;
let post_cutoff = v
.cutoff(move |new_val| {
if (old_val - *new_val).abs() < 50 {
false
} else {
old_val = *new_val;
true
}
})
.map(|v| *v + 10);
assert_eq!(engine.get(&post_cutoff), 110);
v_setter.set(125);
assert_eq!(engine.get(&post_cutoff), 110);
v_setter.set(151);
assert_eq!(engine.get(&post_cutoff), 161);
v_setter.set(125);
assert_eq!(engine.get(&post_cutoff), 161);
}
#[test]
fn test_refmap_simple() {
#[derive(PartialEq, Debug)]
struct NoClone(usize);
let mut engine = crate::singlethread::Engine::new();
let (v, _) = crate::expert::Var::new((NoClone(1), NoClone(2)));
let a = v.refmap(|(a, _)| a);
let b = v.refmap(|(_, b)| b);
let a_correct = a.map(|a| a == &NoClone(1));
let b_correct = b.map(|b| b == &NoClone(2));
assert!(engine.get(&a_correct));
assert!(engine.get(&b_correct));
}
#[test]
fn test_split_simple() {
let mut engine = crate::singlethread::Engine::new();
let (v, _) = crate::expert::Var::new((1usize, 2usize, 3usize));
let (a, b, c) = v.split();
assert_eq!(engine.get(&a), 1);
assert_eq!(engine.get(&b), 2);
assert_eq!(engine.get(&c), 3);
}
#[test]
fn test_map_simple() {
let mut engine = crate::singlethread::Engine::new();
let (v1, _v1_setter) = crate::expert::Var::new(1usize);
let (v2, _v2_setter) = crate::expert::Var::new(123usize);
let _a2 = v1.map(|num1| {
println!("a: adding to {:?}", num1);
*num1
});
let a = AnchorExt::map((&v1, &v2), |num1, num2| num1 + num2);
let b = AnchorExt::map((&v1, &a, &v2), |num1, num2, num3| num1 + num2 + num3);
engine.mark_observed(&b);
engine.stabilize();
assert_eq!(engine.get(&b), 248);
}
#[test]
fn test_then_simple() {
let mut engine = crate::singlethread::Engine::new();
let (v1, v1_setter) = crate::expert::Var::new(true);
let (v2, _v2_setter) = crate::expert::Var::new(10usize);
let (v3, _v3_setter) = crate::expert::Var::new(20usize);
let a = v1.then(move |val| if *val { v2.clone() } else { v3.clone() });
engine.mark_observed(&a);
engine.stabilize();
assert_eq!(engine.get(&a), 10);
v1_setter.set(false);
engine.stabilize();
assert_eq!(engine.get(&a), 20);
}
#[test]
fn test_observed_marking() {
use crate::singlethread::ObservedState;
let mut engine = crate::singlethread::Engine::new();
let (v1, _v1_setter) = crate::expert::Var::new(1usize);
let a = v1.map(|num1| *num1 + 1);
let b = a.map(|num1| *num1 + 2);
let c = b.map(|num1| *num1 + 3);
engine.mark_observed(&a);
engine.mark_observed(&c);
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&v1));
assert_eq!(ObservedState::Observed, engine.check_observed(&a));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&b));
assert_eq!(ObservedState::Observed, engine.check_observed(&c));
engine.stabilize();
assert_eq!(ObservedState::Necessary, engine.check_observed(&v1));
assert_eq!(ObservedState::Observed, engine.check_observed(&a));
assert_eq!(ObservedState::Necessary, engine.check_observed(&b));
assert_eq!(ObservedState::Observed, engine.check_observed(&c));
engine.mark_unobserved(&c);
assert_eq!(ObservedState::Necessary, engine.check_observed(&v1));
assert_eq!(ObservedState::Observed, engine.check_observed(&a));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&b));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&c));
engine.mark_unobserved(&a);
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&v1));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&a));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&b));
assert_eq!(ObservedState::Unnecessary, engine.check_observed(&c));
}
#[test]
fn test_garbage_collection_wont_panic() {
let mut engine = crate::singlethread::Engine::new();
let (v1, _v1_setter) = crate::expert::Var::new(1usize);
engine.get(&v1);
std::mem::drop(v1);
engine.stabilize();
}
#[test]
fn test_readme_example() {
use crate::{expert::AnchorExt, expert::Var, singlethread::Engine};
let mut engine = Engine::new();
let (my_name, my_name_updater) = Var::new("Bob".to_string());
let (my_unread, my_unread_updater) = Var::new(999usize);
assert_eq!(&engine.get(&my_name), "Bob");
assert_eq!(engine.get(&my_unread), 999);
let my_greeting = my_name.clone().map(|name| {
println!("calculating name!");
format!("Hello, {}!", name)
});
assert_eq!(engine.get(&my_greeting), "Hello, Bob!");
assert_eq!(engine.get(&my_greeting), "Hello, Bob!"); my_name_updater.set("Robo".to_string());
assert_eq!(engine.get(&my_greeting), "Hello, Robo!");
let header = (&my_greeting, &my_unread)
.map(|greeting, unread| format!("{} You have {} new messages.", greeting, unread));
assert_eq!(
engine.get(&header),
"Hello, Robo! You have 999 new messages."
);
let (insulting_name, _) = Var::new("Lazybum".to_string());
let dynamic_name = my_unread.then(move |unread| {
if *unread < 100 {
my_name.clone()
} else {
insulting_name.clone()
}
});
assert_eq!(engine.get(&dynamic_name), "Lazybum");
my_unread_updater.set(50);
assert_eq!(engine.get(&dynamic_name), "Robo");
}