use std::time::Duration;
use jmbl::{OpOutput, Value, JMBL};
use litl::Val;
#[test]
fn root_can_be_list_and_insert_works() {
let mut jmbl = JMBL::new_from_root(
|view| view.create_list(["hello", "world"]),
OpOutput::new_dummy(),
);
std::thread::sleep(Duration::from_millis(10));
let jmbl1 = jmbl.readable.clone();
assert_eq!(
jmbl1.get_root().if_list().unwrap().at(0),
Value::str("hello")
);
assert_eq!(
jmbl1.get_root().if_list().unwrap().at(1),
Value::str("world")
);
assert_eq!(
jmbl1.get_root().if_list().unwrap().at(2),
Value::plain(Val::null())
);
assert_eq!(
jmbl1.get_root().if_list().unwrap().val(),
vec![Value::str("hello"), Value::str("world")]
);
assert_eq!(
jmbl1.get_root().if_list().unwrap().val_to_litl(),
Val::array([Val::str("hello"), Val::str("world")])
);
jmbl.change(|root, _| root.if_list_mut().unwrap().insert_at(1, "cruel"));
let jmbl2 = jmbl.readable.clone();
assert_eq!(
jmbl2.get_root().if_list().unwrap().val(),
vec![
Value::str("hello"),
Value::str("cruel"),
Value::str("world")
]
);
}
#[test]
fn delete_works() {
let mut jmbl = JMBL::new_from_root(
|view| view.create_list(["hello", "cruel", "world"]),
OpOutput::new_dummy(),
);
jmbl.change(|root, _| root.if_list_mut().unwrap().delete_at(1));
let jmbl2 = jmbl.readable.clone();
assert_eq!(
jmbl2.get_root().if_list().unwrap().val(),
vec![Value::str("hello"), Value::str("world")]
);
}
#[test]
fn push_works() {
let mut jmbl = JMBL::new_from_root(
|view| view.create_list(["hello", "world"]),
OpOutput::new_dummy(),
);
jmbl.change(|root, _| root.if_list_mut().unwrap().push("beings"));
let jmbl2 = jmbl.readable.clone();
assert_eq!(
jmbl2.get_root().if_list().unwrap().val(),
vec![
Value::str("hello"),
Value::str("world"),
Value::str("beings")
]
);
}
#[test]
fn pop_works() {
let mut jmbl = JMBL::new_from_root(
|view| view.create_list(["hello", "cruel", "world"]),
OpOutput::new_dummy(),
);
jmbl.change(|root, _| assert_eq!(root.if_list_mut().unwrap().pop(), Some(Value::str("world"))));
let jmbl2 = jmbl.readable.clone();
assert_eq!(
jmbl2.get_root().if_list().unwrap().val(),
vec![Value::str("hello"), Value::str("cruel")]
);
}
#[test]
fn concurrent_inserts_are_ordered_correctly() {
let mut jmbl = JMBL::new_from_root(
|view| view.create_list(["hello", "world"]),
OpOutput::new_dummy(),
);
let jmbl1 = jmbl.readable.clone();
let mut jmbl2a = jmbl.switch_to_new_op_output(OpOutput::new_dummy());
let mut jmbl2b = jmbl.switch_to_new_op_output(OpOutput::new_dummy());
let mut jmbl2c = jmbl.switch_to_new_op_output(OpOutput::new_dummy());
jmbl2a.change(|root, _| root.if_list_mut().unwrap().insert_at(1, "bright"));
std::thread::sleep(Duration::from_millis(10));
jmbl2b.change(|root, _| root.if_list_mut().unwrap().insert_at(1, "dark"));
std::thread::sleep(Duration::from_millis(10));
jmbl2c.change(|root, _| root.if_list_mut().unwrap().insert_at(1, "cheesy"));
let ops_2b_since_1 = jmbl2b.ops_since(&jmbl1).collect::<Vec<_>>();
assert_eq!(ops_2b_since_1, jmbl2b.test_get_past_sent_ops().unwrap());
let ops_2c_since_1 = jmbl2c.ops_since(&jmbl1).collect::<Vec<_>>();
assert_eq!(ops_2c_since_1, jmbl2c.test_get_past_sent_ops().unwrap());
let jmbl3 = jmbl2a
.with_ops_applied(&ops_2b_since_1)
.with_ops_applied(&ops_2c_since_1);
assert_eq!(
jmbl3.get_root().if_list().unwrap().val_to_litl(),
Val::array([
Val::str("hello"),
Val::str("cheesy"),
Val::str("dark"),
Val::str("bright"),
Val::str("world")
])
);
}