From bfb80d11845d8a6255b9f17610de8ab4113b59fb Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 18 Aug 2021 13:12:45 +0800 Subject: [PATCH] add undo test --- .../lib/src/service/controller.dart | 3 +- .../delete/preserve_line_format_merge.rs | 2 +- .../extensions/format/format_at_position.rs | 95 ++++++------ .../extensions/insert/auto_exit_block.rs | 2 +- .../client/extensions/insert/auto_format.rs | 2 +- .../insert/preserve_block_format.rs | 1 - rust-lib/flowy-ot/src/client/view.rs | 2 +- .../src/core/attributes/attributes.rs | 2 +- rust-lib/flowy-ot/src/core/delta/cursor.rs | 7 +- rust-lib/flowy-ot/tests/attribute_test.rs | 134 ++++++++--------- rust-lib/flowy-ot/tests/helper/mod.rs | 2 +- rust-lib/flowy-ot/tests/op_test.rs | 30 ++++ rust-lib/flowy-ot/tests/undo_redo_test.rs | 140 +++++++++++++++--- 13 files changed, 274 insertions(+), 148 deletions(-) diff --git a/app_flowy/packages/flowy_editor/lib/src/service/controller.dart b/app_flowy/packages/flowy_editor/lib/src/service/controller.dart index e9f9339fa6..08688a76ae 100644 --- a/app_flowy/packages/flowy_editor/lib/src/service/controller.dart +++ b/app_flowy/packages/flowy_editor/lib/src/service/controller.dart @@ -93,7 +93,8 @@ class EditorController extends ChangeNotifier { toggledStyle = toggledStyle.put(attribute); } - final change = document.format(index, length, attribute); + final change = + document.format(index, length, LinkAttribute("www.baidu.com")); final adjustedSelection = selection.copyWith( baseOffset: change.transformPosition(selection.baseOffset), extentOffset: change.transformPosition(selection.extentOffset), diff --git a/rust-lib/flowy-ot/src/client/extensions/delete/preserve_line_format_merge.rs b/rust-lib/flowy-ot/src/client/extensions/delete/preserve_line_format_merge.rs index 74c39066a9..9941d2d7eb 100644 --- a/rust-lib/flowy-ot/src/client/extensions/delete/preserve_line_format_merge.rs +++ b/rust-lib/flowy-ot/src/client/extensions/delete/preserve_line_format_merge.rs @@ -1,6 +1,6 @@ use crate::{ client::{extensions::DeleteExt, util::is_newline}, - core::{Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, Operation, NEW_LINE}, + core::{Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, NEW_LINE}, }; pub struct PreserveLineFormatOnMerge {} diff --git a/rust-lib/flowy-ot/src/client/extensions/format/format_at_position.rs b/rust-lib/flowy-ot/src/client/extensions/format/format_at_position.rs index 5e0886070f..48ec7992f6 100644 --- a/rust-lib/flowy-ot/src/client/extensions/format/format_at_position.rs +++ b/rust-lib/flowy-ot/src/client/extensions/format/format_at_position.rs @@ -1,47 +1,48 @@ -use crate::{ - client::extensions::FormatExt, - core::{Attribute, AttributeKey, Delta, DeltaBuilder, DeltaIter, Interval}, -}; - -pub struct FormatLinkAtCaretPositionExt {} - -impl FormatExt for FormatLinkAtCaretPositionExt { - fn ext_name(&self) -> &str { std::any::type_name::() } - - fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option { - if attribute.key != AttributeKey::Link || interval.size() != 0 { - return None; - } - - let mut iter = DeltaIter::from_offset(delta, interval.start); - let (before, after) = (iter.next_op_with_len(interval.size()), iter.next_op()); - let mut start = interval.end; - let mut retain = 0; - - if let Some(before) = before { - if before.contain_attribute(attribute) { - start -= before.len(); - retain += before.len(); - } - } - - if let Some(after) = after { - if after.contain_attribute(attribute) { - if retain != 0 { - retain += after.len(); - } - } - } - - if retain == 0 { - return None; - } - - Some( - DeltaBuilder::new() - .retain(start) - .retain_with_attributes(retain, (attribute.clone()).into()) - .build(), - ) - } -} +// use crate::{ +// client::extensions::FormatExt, +// core::{Attribute, AttributeKey, Delta, DeltaBuilder, DeltaIter, +// Interval}, }; +// +// pub struct FormatLinkAtCaretPositionExt {} +// +// impl FormatExt for FormatLinkAtCaretPositionExt { +// fn ext_name(&self) -> &str { +// std::any::type_name::() } +// +// fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) +// -> Option { if attribute.key != AttributeKey::Link || +// interval.size() != 0 { return None; +// } +// +// let mut iter = DeltaIter::from_offset(delta, interval.start); +// let (before, after) = (iter.next_op_with_len(interval.size()), +// iter.next_op()); let mut start = interval.end; +// let mut retain = 0; +// +// if let Some(before) = before { +// if before.contain_attribute(attribute) { +// start -= before.len(); +// retain += before.len(); +// } +// } +// +// if let Some(after) = after { +// if after.contain_attribute(attribute) { +// if retain != 0 { +// retain += after.len(); +// } +// } +// } +// +// if retain == 0 { +// return None; +// } +// +// Some( +// DeltaBuilder::new() +// .retain(start) +// .retain_with_attributes(retain, (attribute.clone()).into()) +// .build(), +// ) +// } +// } diff --git a/rust-lib/flowy-ot/src/client/extensions/insert/auto_exit_block.rs b/rust-lib/flowy-ot/src/client/extensions/insert/auto_exit_block.rs index 80e5e1b2b3..24d330c0f4 100644 --- a/rust-lib/flowy-ot/src/client/extensions/insert/auto_exit_block.rs +++ b/rust-lib/flowy-ot/src/client/extensions/insert/auto_exit_block.rs @@ -1,6 +1,6 @@ use crate::{ client::{extensions::InsertExt, util::is_newline}, - core::{AttributeKey, Delta, DeltaBuilder, DeltaIter, Operation}, + core::{AttributeKey, Delta, DeltaBuilder, DeltaIter}, }; use crate::core::{attributes_except_header, is_empty_line_at_index}; diff --git a/rust-lib/flowy-ot/src/client/extensions/insert/auto_format.rs b/rust-lib/flowy-ot/src/client/extensions/insert/auto_format.rs index 994bf27dad..e363ce7546 100644 --- a/rust-lib/flowy-ot/src/client/extensions/insert/auto_format.rs +++ b/rust-lib/flowy-ot/src/client/extensions/insert/auto_format.rs @@ -50,7 +50,7 @@ impl InsertExt for AutoFormatExt { } } -use crate::core::{AttributeBuilder, Attributes, DeltaBuilder, Operation}; +use crate::core::{AttributeBuilder, Attributes, DeltaBuilder}; use bytecount::num_chars; use std::cmp::min; use url::Url; diff --git a/rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_format.rs b/rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_format.rs index 9ca070a9bf..31dd5dbaf8 100644 --- a/rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_format.rs +++ b/rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_format.rs @@ -7,7 +7,6 @@ use crate::{ Delta, DeltaBuilder, DeltaIter, - Operation, NEW_LINE, }, }; diff --git a/rust-lib/flowy-ot/src/client/view.rs b/rust-lib/flowy-ot/src/client/view.rs index 48b677276d..51b005137e 100644 --- a/rust-lib/flowy-ot/src/client/view.rs +++ b/rust-lib/flowy-ot/src/client/view.rs @@ -94,7 +94,7 @@ fn construct_insert_exts() -> Vec { fn construct_format_exts() -> Vec { vec![ - Box::new(FormatLinkAtCaretPositionExt {}), + // Box::new(FormatLinkAtCaretPositionExt {}), Box::new(ResolveBlockFormat {}), Box::new(ResolveInlineFormat {}), ] diff --git a/rust-lib/flowy-ot/src/core/attributes/attributes.rs b/rust-lib/flowy-ot/src/core/attributes/attributes.rs index 90a2f86816..d0f6d2130b 100644 --- a/rust-lib/flowy-ot/src/core/attributes/attributes.rs +++ b/rust-lib/flowy-ot/src/core/attributes/attributes.rs @@ -47,7 +47,7 @@ impl Attributes { None => { self.inner .iter_mut() - .for_each(|(k, v)| v.0 = REMOVE_FLAG.into()); + .for_each(|(_k, v)| v.0 = REMOVE_FLAG.into()); }, Some(attribute) => { self.inner.iter_mut().for_each(|(k, v)| { diff --git a/rust-lib/flowy-ot/src/core/delta/cursor.rs b/rust-lib/flowy-ot/src/core/delta/cursor.rs index d4128c6109..e3789731a6 100644 --- a/rust-lib/flowy-ot/src/core/delta/cursor.rs +++ b/rust-lib/flowy-ot/src/core/delta/cursor.rs @@ -175,14 +175,17 @@ pub struct CharMetric {} impl Metric for CharMetric { fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult { - let _ = check_bound(cursor.consume_count, index)?; - let _ = cursor.next_with_len(Some(index)); + if index > 0 { + let _ = check_bound(cursor.consume_count, index)?; + let _ = cursor.next_with_len(Some(index)); + } Ok(()) } } fn check_bound(current: usize, target: usize) -> Result<(), OTError> { + debug_assert!(current <= target); if current > target { let msg = format!("{} should be greater than current: {}", target, current); return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) diff --git a/rust-lib/flowy-ot/tests/attribute_test.rs b/rust-lib/flowy-ot/tests/attribute_test.rs index aaf1f5a280..6824fa4ab4 100644 --- a/rust-lib/flowy-ot/tests/attribute_test.rs +++ b/rust-lib/flowy-ot/tests/attribute_test.rs @@ -1,61 +1,10 @@ pub mod helper; use crate::helper::{TestOp::*, *}; -use flowy_ot::core::Interval; - -use flowy_ot::core::{NEW_LINE, WHITESPACE}; +use flowy_ot::core::{Interval, NEW_LINE, WHITESPACE}; #[test] -fn attributes_insert_text() { - let ops = vec![ - Insert(0, "123", 0), - Insert(0, "456", 3), - AssertOpsJson(0, r#"[{"insert":"123456"}]"#), - ]; - OpTester::new().run_script(ops); -} - -#[test] -fn attributes_insert_text_at_head() { - let ops = vec![ - Insert(0, "123", 0), - Insert(0, "456", 0), - AssertOpsJson(0, r#"[{"insert":"456123"}]"#), - ]; - OpTester::new().run_script(ops); -} - -#[test] -fn attributes_insert_text_at_middle() { - let ops = vec![ - Insert(0, "123", 0), - Insert(0, "456", 1), - AssertOpsJson(0, r#"[{"insert":"145623"}]"#), - ]; - OpTester::new().run_script(ops); -} - -#[test] -fn attributes_insert_text_with_attr() { - let ops = vec![ - Insert(0, "145", 0), - Insert(0, "23", 1), - Bold(0, Interval::new(0, 2), true), - AssertOpsJson( - 0, - r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"345"}]"#, - ), - Insert(0, "abc", 1), - AssertOpsJson( - 0, - r#"[{"insert":"1abc2","attributes":{"bold":"true"}},{"insert":"345"}]"#, - ), - ]; - OpTester::new().run_script(ops); -} - -#[test] -fn attributes_add_bold() { +fn attributes_bold_added() { let ops = vec![ Insert(0, "123456", 0), Bold(0, Interval::new(3, 5), true), @@ -72,7 +21,7 @@ fn attributes_add_bold() { } #[test] -fn attributes_add_bold_and_invert_all() { +fn attributes_bold_added_and_invert_all() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -84,7 +33,7 @@ fn attributes_add_bold_and_invert_all() { } #[test] -fn attributes_add_bold_and_invert_partial_suffix() { +fn attributes_bold_added_and_invert_partial_suffix() { let ops = vec![ Insert(0, "1234", 0), Bold(0, Interval::new(0, 4), true), @@ -99,7 +48,7 @@ fn attributes_add_bold_and_invert_partial_suffix() { } #[test] -fn attributes_add_bold_and_invert_partial_suffix2() { +fn attributes_bold_added_and_invert_partial_suffix2() { let ops = vec![ Insert(0, "1234", 0), Bold(0, Interval::new(0, 4), true), @@ -116,7 +65,7 @@ fn attributes_add_bold_and_invert_partial_suffix2() { } #[test] -fn attributes_add_bold_with_new_line() { +fn attributes_bold_added_with_new_line() { let ops = vec![ Insert(0, "123456", 0), Bold(0, Interval::new(0, 6), true), @@ -144,7 +93,7 @@ fn attributes_add_bold_with_new_line() { } #[test] -fn attributes_add_bold_and_invert_partial_prefix() { +fn attributes_bold_added_and_invert_partial_prefix() { let ops = vec![ Insert(0, "1234", 0), Bold(0, Interval::new(0, 4), true), @@ -159,7 +108,7 @@ fn attributes_add_bold_and_invert_partial_prefix() { } #[test] -fn attributes_add_bold_consecutive() { +fn attributes_bold_added_consecutive() { let ops = vec![ Insert(0, "1234", 0), Bold(0, Interval::new(0, 1), true), @@ -177,7 +126,7 @@ fn attributes_add_bold_consecutive() { } #[test] -fn attributes_add_bold_italic() { +fn attributes_bold_added_italic() { let ops = vec![ Insert(0, "1234", 0), Bold(0, Interval::new(0, 4), true), @@ -196,7 +145,7 @@ fn attributes_add_bold_italic() { } #[test] -fn attributes_add_bold_italic2() { +fn attributes_bold_added_italic2() { let ops = vec![ Insert(0, "123456", 0), Bold(0, Interval::new(0, 6), true), @@ -224,7 +173,7 @@ fn attributes_add_bold_italic2() { } #[test] -fn attributes_add_bold_italic3() { +fn attributes_bold_added_italic3() { let ops = vec![ Insert(0, "123456789", 0), Bold(0, Interval::new(0, 5), true), @@ -261,7 +210,7 @@ fn attributes_add_bold_italic3() { } #[test] -fn attributes_add_bold_italic_delete() { +fn attributes_bold_added_italic_delete() { let ops = vec![ Insert(0, "123456789", 0), Bold(0, Interval::new(0, 5), true), @@ -467,7 +416,7 @@ fn attributes_header_insert_newline_at_middle() { } #[test] -fn attributes_header_insert_newline_at_middle2() { +fn attributes_header_insert_double_newline_at_middle() { let ops = vec![ Insert(0, "123456", 0), Header(0, Interval::new(0, 6), 1, true), @@ -523,7 +472,7 @@ fn attributes_header_insert_double_newline_at_trailing() { } #[test] -fn attributes_add_link() { +fn attributes_link_added() { let ops = vec![ Insert(0, "123456", 0), Link(0, Interval::new(0, 6), "https://appflowy.io", true), @@ -536,6 +485,25 @@ fn attributes_add_link() { OpTester::new().run_script_with_newline(ops); } +#[test] +fn attributes_link_format_with_bold() { + let ops = vec![ + Insert(0, "123456", 0), + Link(0, Interval::new(0, 6), "https://appflowy.io", true), + Bold(0, Interval::new(0, 3), true), + AssertOpsJson( + 0, + r#"[ + {"insert":"123","attributes":{"bold":"true","link":"https://appflowy.io"}}, + {"insert":"456","attributes":{"link":"https://appflowy.io"}}, + {"insert":"\n"}] + "#, + ), + ]; + + OpTester::new().run_script_with_newline(ops); +} + #[test] fn attributes_link_insert_char_at_head() { let ops = vec![ @@ -605,7 +573,7 @@ fn attributes_link_insert_newline_at_middle() { } #[test] -fn attributes_auto_format_link() { +fn attributes_link_auto_format() { let site = "https://appflowy.io"; let ops = vec![ Insert(0, site, 0), @@ -621,7 +589,7 @@ fn attributes_auto_format_link() { } #[test] -fn attributes_auto_format_exist_link() { +fn attributes_link_auto_format_exist() { let site = "https://appflowy.io"; let ops = vec![ Insert(0, site, 0), @@ -637,7 +605,7 @@ fn attributes_auto_format_exist_link() { } #[test] -fn attributes_auto_format_exist_link2() { +fn attributes_link_auto_format_exist2() { let site = "https://appflowy.io"; let ops = vec![ Insert(0, site, 0), @@ -653,7 +621,7 @@ fn attributes_auto_format_exist_link2() { } #[test] -fn attributes_add_bullet() { +fn attributes_bullet_added() { let ops = vec![ Insert(0, "12", 0), Bullet(0, Interval::new(0, 1), true), @@ -667,7 +635,7 @@ fn attributes_add_bullet() { } #[test] -fn attributes_add_bullet2() { +fn attributes_bullet_added_2() { let ops = vec![ Insert(0, "1", 0), Bullet(0, Interval::new(0, 1), true), @@ -691,7 +659,7 @@ fn attributes_add_bullet2() { } #[test] -fn attributes_un_bullet_one() { +fn attributes_bullet_remove_partial() { let ops = vec![ Insert(0, "1", 0), Bullet(0, Interval::new(0, 1), true), @@ -708,7 +676,7 @@ fn attributes_un_bullet_one() { } #[test] -fn attributes_auto_exit_block() { +fn attributes_bullet_auto_exit() { let ops = vec![ Insert(0, "1", 0), Bullet(0, Interval::new(0, 1), true), @@ -764,7 +732,7 @@ fn attributes_preserve_block_when_insert_newline_inside() { } #[test] -fn attributes_preserve_line_format_on_merge() { +fn attributes_preserve_header_format_on_merge() { let ops = vec![ Insert(0, "123456", 0), Header(0, Interval::new(0, 6), 1, true), @@ -782,3 +750,23 @@ fn attributes_preserve_line_format_on_merge() { OpTester::new().run_script_with_newline(ops); } + +#[test] +fn attributes_preserve_list_format_on_merge() { + let ops = vec![ + Insert(0, "123456", 0), + Bullet(0, Interval::new(0, 6), true), + Insert(0, NEW_LINE, 3), + AssertOpsJson( + 0, + r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Delete(0, Interval::new(3, 4)), + AssertOpsJson( + 0, + r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + ]; + + OpTester::new().run_script_with_newline(ops); +} diff --git a/rust-lib/flowy-ot/tests/helper/mod.rs b/rust-lib/flowy-ot/tests/helper/mod.rs index cc125636a9..045cb57c21 100644 --- a/rust-lib/flowy-ot/tests/helper/mod.rs +++ b/rust-lib/flowy-ot/tests/helper/mod.rs @@ -3,7 +3,7 @@ use flowy_ot::{client::Document, core::*}; use rand::{prelude::*, Rng as WrappedRng}; use std::{sync::Once, time::Duration}; -const LEVEL: &'static str = "debug"; +const LEVEL: &'static str = "info"; #[derive(Clone, Debug, Display)] pub enum TestOp { diff --git a/rust-lib/flowy-ot/tests/op_test.rs b/rust-lib/flowy-ot/tests/op_test.rs index 1266a54ed5..818865c4b2 100644 --- a/rust-lib/flowy-ot/tests/op_test.rs +++ b/rust-lib/flowy-ot/tests/op_test.rs @@ -5,6 +5,36 @@ use bytecount::num_chars; use flowy_ot::core::*; use helper::*; +#[test] +fn attributes_insert_text() { + let ops = vec![ + Insert(0, "123", 0), + Insert(0, "456", 3), + AssertOpsJson(0, r#"[{"insert":"123456"}]"#), + ]; + OpTester::new().run_script(ops); +} + +#[test] +fn attributes_insert_text_at_head() { + let ops = vec![ + Insert(0, "123", 0), + Insert(0, "456", 0), + AssertOpsJson(0, r#"[{"insert":"456123"}]"#), + ]; + OpTester::new().run_script(ops); +} + +#[test] +fn attributes_insert_text_at_middle() { + let ops = vec![ + Insert(0, "123", 0), + Insert(0, "456", 1), + AssertOpsJson(0, r#"[{"insert":"145623"}]"#), + ]; + OpTester::new().run_script(ops); +} + #[test] fn delta_get_ops_in_interval_1() { let mut delta = Delta::default(); diff --git a/rust-lib/flowy-ot/tests/undo_redo_test.rs b/rust-lib/flowy-ot/tests/undo_redo_test.rs index 2605356390..1426732ab7 100644 --- a/rust-lib/flowy-ot/tests/undo_redo_test.rs +++ b/rust-lib/flowy-ot/tests/undo_redo_test.rs @@ -1,10 +1,13 @@ pub mod helper; use crate::helper::{TestOp::*, *}; -use flowy_ot::{client::RECORD_THRESHOLD, core::Interval}; +use flowy_ot::{ + client::RECORD_THRESHOLD, + core::{Interval, NEW_LINE, WHITESPACE}, +}; #[test] -fn history_undo_insert() { +fn history_insert_undo() { let ops = vec![ Insert(0, "123", 0), Undo(0), @@ -14,7 +17,7 @@ fn history_undo_insert() { } #[test] -fn history_undo_insert2() { +fn history_insert_undo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -28,7 +31,7 @@ fn history_undo_insert2() { } #[test] -fn history_redo_insert() { +fn history_insert_redo() { let ops = vec![ Insert(0, "123", 0), AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), @@ -41,7 +44,7 @@ fn history_redo_insert() { } #[test] -fn history_redo_insert_with_lagging() { +fn history_insert_redo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -60,7 +63,7 @@ fn history_redo_insert_with_lagging() { } #[test] -fn history_undo_attributes() { +fn history_bold_undo() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -71,7 +74,7 @@ fn history_undo_attributes() { } #[test] -fn history_undo_attributes_with_lagging() { +fn history_bold_undo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -83,7 +86,7 @@ fn history_undo_attributes_with_lagging() { } #[test] -fn history_redo_attributes() { +fn history_bold_redo() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -99,7 +102,7 @@ fn history_redo_attributes() { } #[test] -fn history_redo_attributes_with_lagging() { +fn history_bold_redo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -116,7 +119,7 @@ fn history_redo_attributes_with_lagging() { } #[test] -fn history_undo_delete() { +fn history_delete_undo() { let ops = vec![ Insert(0, "123", 0), AssertOpsJson(0, r#"[{"insert":"123"}]"#), @@ -129,7 +132,7 @@ fn history_undo_delete() { } #[test] -fn history_undo_delete2() { +fn history_delete_undo_2() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -148,7 +151,7 @@ fn history_undo_delete2() { } #[test] -fn history_undo_delete2_with_lagging() { +fn history_delete_undo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -175,7 +178,7 @@ fn history_undo_delete2_with_lagging() { } #[test] -fn history_redo_delete() { +fn history_delete_redo() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -189,7 +192,7 @@ fn history_redo_delete() { } #[test] -fn history_undo_replace() { +fn history_replace_undo() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -208,7 +211,7 @@ fn history_undo_replace() { } #[test] -fn history_undo_replace_with_lagging() { +fn history_replace_undo_with_lagging() { let ops = vec![ Insert(0, "123", 0), Wait(RECORD_THRESHOLD), @@ -232,7 +235,7 @@ fn history_undo_replace_with_lagging() { } #[test] -fn history_redo_replace() { +fn history_replace_redo() { let ops = vec![ Insert(0, "123", 0), Bold(0, Interval::new(0, 3), true), @@ -251,13 +254,14 @@ fn history_redo_replace() { } #[test] -fn history_undo_add_header() { +fn history_header_added_undo() { let ops = vec![ Insert(0, "123456", 0), Header(0, Interval::new(0, 6), 1, true), Insert(0, "\n", 3), Insert(0, "\n", 4), Undo(0), + AssertOpsJson(0, r#"[{"insert":"\n"}]"#), Redo(0), AssertOpsJson( 0, @@ -269,7 +273,7 @@ fn history_undo_add_header() { } #[test] -fn history_undo_add_link() { +fn history_link_added_undo() { let site = "https://appflowy.io"; let ops = vec![ Insert(0, site, 0), @@ -286,3 +290,103 @@ fn history_undo_add_link() { OpTester::new().run_script_with_newline(ops); } + +#[test] +fn history_link_auto_format_undo_with_lagging() { + let site = "https://appflowy.io"; + let ops = vec![ + Insert(0, site, 0), + AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), + Wait(RECORD_THRESHOLD), + Insert(0, WHITESPACE, site.len()), + AssertOpsJson( + 0, + r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#, + ), + Undo(0), + AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), + ]; + + OpTester::new().run_script_with_newline(ops); +} + +#[test] +fn history_bullet_undo() { + let ops = vec![ + Insert(0, "1", 0), + Bullet(0, Interval::new(0, 1), true), + Insert(0, NEW_LINE, 1), + Insert(0, "2", 2), + AssertOpsJson( + 0, + r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Undo(0), + AssertOpsJson(0, r#"[{"insert":"\n"}]"#), + Redo(0), + AssertOpsJson( + 0, + r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + ]; + + OpTester::new().run_script_with_newline(ops); +} + +#[test] +fn history_bullet_undo_with_lagging() { + let ops = vec![ + Insert(0, "1", 0), + Bullet(0, Interval::new(0, 1), true), + Wait(RECORD_THRESHOLD), + Insert(0, NEW_LINE, 1), + Insert(0, "2", 2), + Wait(RECORD_THRESHOLD), + AssertOpsJson( + 0, + r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Undo(0), + AssertOpsJson( + 0, + r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Undo(0), + AssertOpsJson(0, r#"[{"insert":"\n"}]"#), + Redo(0), + Redo(0), + AssertOpsJson( + 0, + r#"[{"insert":"1"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"2"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + ]; + + OpTester::new().run_script_with_newline(ops); +} + +#[test] +fn history_undo_attribute_on_merge_between_line() { + let ops = vec![ + Insert(0, "123456", 0), + Bullet(0, Interval::new(0, 6), true), + Wait(RECORD_THRESHOLD), + Insert(0, NEW_LINE, 3), + Wait(RECORD_THRESHOLD), + AssertOpsJson( + 0, + r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Delete(0, Interval::new(3, 4)), // delete the newline + AssertOpsJson( + 0, + r#"[{"insert":"123456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + Undo(0), + AssertOpsJson( + 0, + r#"[{"insert":"123"},{"insert":"\n","attributes":{"bullet":"true"}},{"insert":"456"},{"insert":"\n","attributes":{"bullet":"true"}}]"#, + ), + ]; + + OpTester::new().run_script_with_newline(ops); +}