From c7b2d73810697e2b1f51c03195482a767778758a Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Mon, 29 May 2023 00:49:49 -0400 Subject: [PATCH] backfill auto pair delete tests --- helix-term/tests/test/auto_pairs.rs | 549 ++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) diff --git a/helix-term/tests/test/auto_pairs.rs b/helix-term/tests/test/auto_pairs.rs index c921e2ae7..1768ec84f 100644 --- a/helix-term/tests/test/auto_pairs.rs +++ b/helix-term/tests/test/auto_pairs.rs @@ -567,3 +567,552 @@ async fn append_inside_nested_pair_multi() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn delete_basic() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i", + format!("#[{}|]#", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i", + format!("#[{}|]#", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_configured_multi_byte_chars() -> anyhow::Result<()> { + // NOTE: these are multi-byte Unicode characters + let pairs = hashmap!('„' => '“', '‚' => '‘', '「' => '」'); + + let config = Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Pairs(pairs.clone()), + ..Default::default() + }, + ..Default::default() + }; + + for (open, close) in pairs.iter() { + test_with_config( + AppBuilder::new().with_config(config.clone()), + ( + format!("{}#[|{}]#{}", open, close, LINE_END), + "i", + format!("#[{}|]#", LINE_END), + ), + ) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_after_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("foo{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i", + format!("foo#[{}|]#", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + // sanity check unclosed pair delete + test(( + format!("{}#[|f]#oo{}", pair.0, LINE_END), + "i", + format!("#[|f]#oo{}", LINE_END), + )) + .await?; + + // deleting the closing pair should NOT delete the whole pair + test(( + format!("{}{}#[|f]#oo{}", pair.0, pair.1, LINE_END), + "i", + format!("{}#[|f]#oo{}", pair.0, LINE_END), + )) + .await?; + + // deleting whole pair before word + test(( + format!("{}#[|{}]#foo{}", pair.0, pair.1, LINE_END), + "i", + format!("#[f|]#oo{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word_selection() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + // sanity check unclosed pair delete + test(( + format!("{}#[|foo]#{}", pair.0, LINE_END), + "i", + format!("#[foo|]#{}", LINE_END), + )) + .await?; + + // deleting the closing pair should NOT delete the whole pair + test(( + format!("{}{}#[|foo]#{}", pair.0, pair.1, LINE_END), + "i", + format!("{}#[foo|]#{}", pair.0, LINE_END), + )) + .await?; + + // deleting whole pair before word + test(( + format!("{}#[|{}foo]#{}", pair.0, pair.1, LINE_END), + "i", + format!("#[foo|]#{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word_selection_trailing_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("foo{}#[|{} wor]#{}", pair.0, pair.1, LINE_END), + "i", + format!("foo#[ wor|]#{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_eol() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "{eol}{open}#[|{close}]#{eol}", + eol = LINE_END, + open = pair.0, + close = pair.1 + ), + "i", + format!("{0}#[{0}|]#", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_auto_pairs_disabled() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test_with_config( + AppBuilder::new().with_config(Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Enable(false), + ..Default::default() + }, + ..Default::default() + }), + ( + format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i", + format!("#[|{}]#{}", pair.1, LINE_END), + ), + ) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_multi_range() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "{open}#[|{close}]#{eol}{open}#(|{close})#{eol}{open}#(|{close})#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "i", + format!("#[{eol}|]##({eol}|)##({eol}|)#", eol = LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_multi_code_point_graphemes() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("hello {}#[|👨‍👩‍👧‍👦]# goodbye{}", pair.1, LINE_END), + "i", + format!("hello #[|👨‍👩‍👧‍👦]# goodbye{}", LINE_END), + )) + .await?; + + test(( + format!( + "hello {}{}#[|👨‍👩‍👧‍👦]# goodbye{}", + pair.0, pair.1, LINE_END + ), + "i", + format!("hello {}#[|👨‍👩‍👧‍👦]# goodbye{}", pair.0, LINE_END), + )) + .await?; + + test(( + format!( + "hello {}#[|{}]#👨‍👩‍👧‍👦 goodbye{}", + pair.0, pair.1, LINE_END + ), + "i", + format!("hello #[👨‍👩‍👧‍👦|]# goodbye{}", LINE_END), + )) + .await?; + + test(( + format!( + "hello {}#[|{}👨‍👩‍👧‍👦]# goodbye{}", + pair.0, pair.1, LINE_END + ), + "i", + format!("hello #[👨‍👩‍👧‍👦|]# goodbye{}", LINE_END), + )) + .await?; + } + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_at_end_of_document() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(TestCase { + in_text: format!("{}{}{}", LINE_END, pair.0, pair.1), + in_selection: Selection::single(LINE_END.len() + 1, LINE_END.len() + 2), + in_keys: String::from("i"), + out_text: String::from(LINE_END), + out_selection: Selection::single(LINE_END.len(), LINE_END.len()), + }) + .await?; + + test(TestCase { + in_text: format!("foo{}{}{}", LINE_END, pair.0, pair.1), + in_selection: Selection::single(LINE_END.len() + 4, LINE_END.len() + 5), + in_keys: String::from("i"), + out_text: format!("foo{}", LINE_END), + out_selection: Selection::single(3 + LINE_END.len(), 3 + LINE_END.len()), + }) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_nested_open_inside_pair() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + format!( + "{open}{open}#[|{close}]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "i", + format!( + "{open}#[{close}|]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_nested_open_inside_pair_multi() -> anyhow::Result<()> { + for outer_pair in DEFAULT_PAIRS { + for inner_pair in DEFAULT_PAIRS { + if inner_pair.0 == outer_pair.0 { + continue; + } + + test(( + format!( + "{outer_open}{inner_open}#[|{inner_close}]#{outer_close}{eol}{outer_open}{inner_open}#(|{inner_close})#{outer_close}{eol}{outer_open}{inner_open}#(|{inner_close})#{outer_close}{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + inner_open = inner_pair.0, + inner_close = inner_pair.1, + eol = LINE_END + ), + "i", + format!( + "{outer_open}#[{outer_close}|]#{eol}{outer_open}#({outer_close}|)#{eol}{outer_open}#({outer_close}|)#{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + eol = LINE_END + ), + )) + .await?; + } + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_basic() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "#[{eol}{open}|]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!("#[{eol}{eol}|]#", eol = LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_multi_range() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "#[ {open}|]#{close}{eol}#( {open}|)#{close}{eol}#( {open}|)#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!("#[ {eol}|]##( {eol}|)##( {eol}|)#", eol = LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_end_of_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "fo#[o{open}|]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!("fo#[o{}|]#", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_mixed_dedent() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + helpers::platform_line(&format!( + indoc! {"\ + bar = {}#[|{}]# + #(|\n)# + foo#(|\n)# + "}, + pair.0, pair.1, + )), + "i", + helpers::platform_line(indoc! {"\ + bar = #[\n|]# + #(|\n)# + fo#(|\n)# + "}), + )) + .await?; + + test(( + helpers::platform_line(&format!( + indoc! {"\ + bar = {}#[|{}woop]# + #(|word)# + fo#(|o)# + "}, + pair.0, pair.1, + )), + "i", + helpers::platform_line(indoc! {"\ + bar = #[woop|]# + #(|word)# + f#(|o)# + "}), + )) + .await?; + + // delete from the right with append + test(( + helpers::platform_line(&format!( + indoc! {"\ + bar = #[|woop{}]#{} + #(| )# word + #(|fo)#o + "}, + pair.0, pair.1, + )), + "a", + helpers::platform_line(indoc! {"\ + bar = #[woop|]# + #(|w)#ord + #(|fo)# + "}), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_end_of_word_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "fo#[o{open}|]#{close}{eol}fo#(o{open}|)#{close}{eol}fo#(o{open}|)#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!("fo#[o{eol}|]#fo#(o{eol}|)#fo#(o{eol}|)#", eol = LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_inside_nested_pair() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "f#[oo{open}{open}|]#{close}{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!( + "f#[oo{open}{close}|]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_middle_of_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "f#[oo{open}{open}|]#{close}{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a", + format!( + "f#[oo{open}{close}|]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_inside_nested_pair_multi() -> anyhow::Result<()> { + for outer_pair in DEFAULT_PAIRS { + for inner_pair in DEFAULT_PAIRS { + if inner_pair.0 == outer_pair.0 { + continue; + } + + test(( + format!( + "f#[oo{outer_open}{inner_open}|]#{inner_close}{outer_close}{eol}f#(oo{outer_open}{inner_open}|)#{inner_close}{outer_close}{eol}f#(oo{outer_open}{inner_open}|)#{inner_close}{outer_close}{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + inner_open = inner_pair.0, + inner_close = inner_pair.1, + eol = LINE_END + ), + "a", + format!( + "f#[oo{outer_open}{outer_close}|]#{eol}f#(oo{outer_open}{outer_close}|)#{eol}f#(oo{outer_open}{outer_close}|)#{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + eol = LINE_END + ), + )) + .await?; + } + } + + Ok(()) +}