transaction_compose_test.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. use crate::node::script::{edit_node_delta, make_node_delta_changeset};
  2. use lib_ot::core::{
  3. AttributeEntry, Changeset, NodeDataBuilder, NodeOperation, Transaction, TransactionBuilder,
  4. };
  5. use lib_ot::text_delta::DeltaTextOperationBuilder;
  6. #[test]
  7. fn transaction_compose_update_after_insert_test() {
  8. let (initial_delta, changeset, _) = make_node_delta_changeset("Hello", " world");
  9. let node_data = NodeDataBuilder::new("text")
  10. .insert_delta(initial_delta)
  11. .build();
  12. // Modify the same path, the operations will be merged after composing if possible.
  13. let mut transaction_a = TransactionBuilder::new()
  14. .insert_node_at_path(0, node_data)
  15. .build();
  16. let transaction_b = TransactionBuilder::new()
  17. .update_node_at_path(0, changeset)
  18. .build();
  19. transaction_a.compose(transaction_b).unwrap();
  20. // The operations are merged into one operation
  21. assert_eq!(transaction_a.operations.len(), 1);
  22. assert_eq!(
  23. transaction_a.to_json().unwrap(),
  24. r#"{"operations":[{"op":"insert","path":[0],"nodes":[{"type":"text","body":{"delta":[{"insert":"Hello world"}]}}]}]}"#
  25. );
  26. }
  27. #[test]
  28. fn transaction_compose_multiple_update_test() {
  29. let (initial_delta, changeset_1, final_delta) = make_node_delta_changeset("Hello", " world");
  30. let mut transaction = TransactionBuilder::new()
  31. .insert_node_at_path(
  32. 0,
  33. NodeDataBuilder::new("text")
  34. .insert_delta(initial_delta)
  35. .build(),
  36. )
  37. .build();
  38. let (changeset_2, _) = edit_node_delta(
  39. &final_delta,
  40. DeltaTextOperationBuilder::new()
  41. .retain(final_delta.utf16_target_len)
  42. .insert("😁")
  43. .build(),
  44. );
  45. let mut other_transaction = Transaction::new();
  46. // the following two update operations will be merged into one
  47. let update_1 = TransactionBuilder::new()
  48. .update_node_at_path(0, changeset_1)
  49. .build();
  50. other_transaction.compose(update_1).unwrap();
  51. let update_2 = TransactionBuilder::new()
  52. .update_node_at_path(0, changeset_2)
  53. .build();
  54. other_transaction.compose(update_2).unwrap();
  55. let inverted = Transaction::from_operations(other_transaction.operations.inverted());
  56. // the update operation will be merged into insert operation
  57. transaction.compose(other_transaction).unwrap();
  58. assert_eq!(transaction.operations.len(), 1);
  59. assert_eq!(
  60. transaction.to_json().unwrap(),
  61. r#"{"operations":[{"op":"insert","path":[0],"nodes":[{"type":"text","body":{"delta":[{"insert":"Hello world😁"}]}}]}]}"#
  62. );
  63. transaction.compose(inverted).unwrap();
  64. assert_eq!(
  65. transaction.to_json().unwrap(),
  66. r#"{"operations":[{"op":"insert","path":[0],"nodes":[{"type":"text","body":{"delta":[{"insert":"Hello"}]}}]}]}"#
  67. );
  68. }
  69. #[test]
  70. fn transaction_compose_multiple_attribute_test() {
  71. let delta = DeltaTextOperationBuilder::new().insert("Hello").build();
  72. let node = NodeDataBuilder::new("text").insert_delta(delta).build();
  73. let insert_operation = NodeOperation::Insert {
  74. path: 0.into(),
  75. nodes: vec![node],
  76. };
  77. let mut transaction = Transaction::new();
  78. transaction.push_operation(insert_operation);
  79. let new_attribute = AttributeEntry::new("subtype", "bulleted-list");
  80. let update_operation = NodeOperation::Update {
  81. path: 0.into(),
  82. changeset: Changeset::Attributes {
  83. new: new_attribute.clone().into(),
  84. old: Default::default(),
  85. },
  86. };
  87. transaction.push_operation(update_operation);
  88. assert_eq!(
  89. transaction.to_json().unwrap(),
  90. r#"{"operations":[{"op":"insert","path":[0],"nodes":[{"type":"text","body":{"delta":[{"insert":"Hello"}]}}]},{"op":"update","path":[0],"changeset":{"attributes":{"new":{"subtype":"bulleted-list"},"old":{}}}}]}"#
  91. );
  92. let old_attribute = new_attribute;
  93. let new_attribute = AttributeEntry::new("subtype", "number-list");
  94. transaction.push_operation(NodeOperation::Update {
  95. path: 0.into(),
  96. changeset: Changeset::Attributes {
  97. new: new_attribute.into(),
  98. old: old_attribute.into(),
  99. },
  100. });
  101. assert_eq!(
  102. transaction.to_json().unwrap(),
  103. r#"{"operations":[{"op":"insert","path":[0],"nodes":[{"type":"text","body":{"delta":[{"insert":"Hello"}]}}]},{"op":"update","path":[0],"changeset":{"attributes":{"new":{"subtype":"number-list"},"old":{"subtype":"bulleted-list"}}}}]}"#
  104. );
  105. }