| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 | use crate::node::script::NodeScript::*;use crate::node::script::NodeTest;use lib_ot::core::{AttributeBuilder, Node};use lib_ot::{    core::{NodeBodyChangeset, NodeData, NodeDataBuilder, NodeOperation, Path},    text_delta::TextOperationBuilder,};#[test]fn operation_insert_node_serde_test() {    let insert = NodeOperation::Insert {        path: Path(vec![0, 1]),        nodes: vec![NodeData::new("text".to_owned())],    };    let result = serde_json::to_string(&insert).unwrap();    assert_eq!(result, r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text"}]}"#);}#[test]fn operation_insert_node_with_children_serde_test() {    let node = NodeDataBuilder::new("text")        .add_node(NodeData::new("sub_text".to_owned()))        .build();    let insert = NodeOperation::Insert {        path: Path(vec![0, 1]),        nodes: vec![node],    };    assert_eq!(        serde_json::to_string(&insert).unwrap(),        r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text","children":[{"type":"sub_text"}]}]}"#    );}#[test]fn operation_update_node_attributes_serde_test() {    let operation = NodeOperation::UpdateAttributes {        path: Path(vec![0, 1]),        new: AttributeBuilder::new().insert("bold", true).build(),        old: AttributeBuilder::new().insert("bold", false).build(),    };    let result = serde_json::to_string(&operation).unwrap();    assert_eq!(        result,        r#"{"op":"update-attribute","path":[0,1],"new":{"bold":true},"old":{"bold":null}}"#    );}#[test]fn operation_update_node_body_serialize_test() {    let delta = TextOperationBuilder::new().insert("AppFlowy...").build();    let inverted = delta.invert_str("");    let changeset = NodeBodyChangeset::Delta { delta, inverted };    let insert = NodeOperation::UpdateBody {        path: Path(vec![0, 1]),        changeset,    };    let result = serde_json::to_string(&insert).unwrap();    assert_eq!(        result,        r#"{"op":"update-body","path":[0,1],"changeset":{"delta":{"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}}}"#    );    //}#[test]fn operation_update_node_body_deserialize_test() {    let json_1 = r#"{"op":"update-body","path":[0,1],"changeset":{"delta":{"delta":[{"insert":"AppFlowy..."}],"inverted":[{"delete":11}]}}}"#;    let operation: NodeOperation = serde_json::from_str(json_1).unwrap();    let json_2 = serde_json::to_string(&operation).unwrap();    assert_eq!(json_1, json_2);}#[test]fn operation_insert_op_transform_test() {    let node_1 = NodeDataBuilder::new("text_1").build();    let node_2 = NodeDataBuilder::new("text_2").build();    let op_1 = NodeOperation::Insert {        path: Path(vec![0, 1]),        nodes: vec![node_1],    };    let mut insert_2 = NodeOperation::Insert {        path: Path(vec![0, 1]),        nodes: vec![node_2],    };    // let mut node_tree = NodeTree::new("root");    // node_tree.apply_op(insert_1.clone()).unwrap();    op_1.transform(&mut insert_2);    let json = serde_json::to_string(&insert_2).unwrap();    assert_eq!(json, r#"{"op":"insert","path":[0,2],"nodes":[{"type":"text_2"}]}"#);}#[test]fn operation_insert_transform_one_level_path_test() {    let mut test = NodeTest::new();    let node_data_1 = NodeDataBuilder::new("text_1").build();    let node_data_2 = NodeDataBuilder::new("text_2").build();    let node_data_3 = NodeDataBuilder::new("text_3").build();    let node_3: Node = node_data_3.clone().into();    //  0: text_1    //  1: text_2    //    //  Insert a new operation with rev_id 1,but the rev_id:1 is already exist, so    //  it needs to be transformed.    //  1:text_3 => 2:text_3    //    //  0: text_1    //  1: text_2    //  2: text_3    //    //  If the rev_id of the insert operation is 3. then the tree will be:    //  0: text_1    //  1: text_3    //  2: text_2    let scripts = vec![        InsertNode {            path: 0.into(),            node_data: node_data_1,            rev_id: 1,        },        InsertNode {            path: 1.into(),            node_data: node_data_2,            rev_id: 2,        },        InsertNode {            path: 1.into(),            node_data: node_data_3,            rev_id: 1,        },        AssertNode {            path: 2.into(),            expected: Some(node_3),        },    ];    test.run_scripts(scripts);}#[test]fn operation_insert_transform_multiple_level_path_test() {    let mut test = NodeTest::new();    let node_data_1 = NodeDataBuilder::new("text_1")        .add_node(NodeDataBuilder::new("text_1_1").build())        .add_node(NodeDataBuilder::new("text_1_2").build())        .build();    let node_data_2 = NodeDataBuilder::new("text_2")        .add_node(NodeDataBuilder::new("text_2_1").build())        .add_node(NodeDataBuilder::new("text_2_2").build())        .build();    let node_data_3 = NodeDataBuilder::new("text_3").build();    let scripts = vec![        InsertNode {            path: 0.into(),            node_data: node_data_1,            rev_id: 1,        },        InsertNode {            path: 1.into(),            node_data: node_data_2,            rev_id: 2,        },        InsertNode {            path: 1.into(),            node_data: node_data_3.clone(),            rev_id: 1,        },        AssertNode {            path: 2.into(),            expected: Some(node_data_3.into()),        },    ];    test.run_scripts(scripts);}#[test]fn operation_delete_transform_path_test() {    let mut test = NodeTest::new();    let node_data_1 = NodeDataBuilder::new("text_1").build();    let node_data_2 = NodeDataBuilder::new("text_2").build();    let node_data_3 = NodeDataBuilder::new("text_3").build();    let node_3: Node = node_data_3.clone().into();    let scripts = vec![        InsertNode {            path: 0.into(),            node_data: node_data_1,            rev_id: 1,        },        InsertNode {            path: 1.into(),            node_data: node_data_2,            rev_id: 2,        },        // The node's in the tree will be:        // 0: text_1        // 2: text_2        //        // The insert action is happened concurrently with the delete action, because they        // share the same rev_id. aka, 3. The delete action is want to delete the node at index 1,        // but it was moved to index 2.        InsertNode {            path: 1.into(),            node_data: node_data_3,            rev_id: 3,        },        // 0: text_1        // 1: text_3        // 2: text_2        //        // The path of the delete action will be transformed to a new path that point to the text_2.        // 1 -> 2        DeleteNode {            path: 1.into(),            rev_id: 3,        },        // After perform the delete action, the tree will be:        // 0: text_1        // 1: text_3        AssertNumberOfNodesAtPath { path: None, len: 2 },        AssertNode {            path: 1.into(),            expected: Some(node_3),        },        AssertNode {            path: 2.into(),            expected: None,        },    ];    test.run_scripts(scripts);}
 |