use jmbl::{ops::OpWithTarget, Input, ReadableJMBL, OpOutput, JMBL}; use litl::Val; use pretty_assertions::assert_eq; use proptest::prelude::*; fn arb_input() -> impl Strategy { let leaf = prop_oneof![ Just(Input::Plain(Val::null())), any::().prop_map(|bool| Input::Plain(Val::bool(bool))), (-100.0f64..100.0).prop_map(|num| Input::Plain(Val::number(num))), "[a-zA-Z0-9]{0,20}".prop_map(|string| Input::Plain(Val::str(&string))), "[a-zA-Z0-9]{0,20}".prop_map(Input::CollabText), ]; leaf.prop_recursive( 8, // 8 levels deep 10, // Shoot for maximum size of 256 nodes 5, // We put up to 5 items per collection |inner| { prop_oneof![ // Take the inner strategy and make the two recursive cases. prop::collection::vec(inner.clone(), 0..5).prop_map(Input::CollabList), prop::collection::hash_map("[a-zA-Z0-9]{0,20}", inner, 0..5) .prop_map(|map| { Input::collab_map(map) }), ] }, ) } fn arb_map_or_list() -> impl Strategy { prop_oneof![ prop::collection::vec(arb_input(), 0..5).prop_map(Input::CollabList), prop::collection::hash_map("[a-zA-Z0-9]{0,20}", arb_input(), 0..5) .prop_map(|map| { Input::collab_map(map) }), ] } fn jmbl_and_its_suffled_ops() -> impl Strategy)> { arb_map_or_list().prop_flat_map(|input| { let mut jmbl = JMBL::new_from_root(|view| view.create_input_recursively(input), OpOutput::new_dummy()); let ops = jmbl.test_get_past_sent_ops().unwrap(); (Just(jmbl.readable), Just(ops).prop_shuffle()) }) } proptest! { #[test] fn jmbls_created_from_input_equal_input(input in arb_map_or_list()) { let jmbl = JMBL::new_from_root(|view| view.create_input_recursively(input.clone()), OpOutput::new_dummy()); assert_eq!(jmbl.get_root().val_to_litl(), input.val_to_litl()); } #[test] fn can_reshuffle_ops_and_get_same_arbitrary_jmbl((jmbl1, ops) in jmbl_and_its_suffled_ops()) { let jmbl2 = ReadableJMBL::new().with_ops_applied(&ops); assert_eq!(jmbl2.get_root().val_to_litl(), jmbl1.get_root().val_to_litl()); } }