helix-mirror/helix-term/tests/test/commands/movement.rs
Skyler Hawthorne f5991657f4
Factor out line ending handling in integration tests (#9921)
Prior to this change, every integration test which wanted its line
endings to be handled transparently across platforms, i.e. test with
the same input that has its platform's line feed characters, converting
the line endings was up to each individual test by calling the
`platform_line` helper function. This significantly increases the amount
of boilerplate one has to copy between all the tests.

However, there are some test cases that need to exert strict control
over the exact input text without being manipulated behind the scenes by
the test framework.

So, with this change, the line feed conversions are factored into
the `TestCase` struct. By default, line endings of the input text
are converted to the platform's native line feed ending, but one can
explicitly specify in their test case when the input text should be left
alone and tested as is.
2024-03-31 07:12:17 -05:00

453 lines
12 KiB
Rust

use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn test_move_parent_node_end() -> anyhow::Result<()> {
let tests = vec![
// single cursor stays single cursor, first goes to end of current
// node, then parent
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
"no#["|]#
}
}
"##},
"<A-e>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"#[\n|]#
}
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"#[\n|]#
}
}
"},
"<A-e>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"
}#[\n|]#
}
"},
),
// select mode extends
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
#["no"|]#
}
}
"##},
"v<A-e><A-e>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
#[\"no\"
}\n|]#
}
"},
),
];
for test in tests {
test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?;
}
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_move_parent_node_start() -> anyhow::Result<()> {
let tests = vec![
// single cursor stays single cursor, first goes to end of current
// node, then parent
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
"no#["|]#
}
}
"##},
"<A-b>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
#[\"|]#no\"
}
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"#[\n|]#
}
}
"},
"<A-b>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else #[{|]#
\"no\"
}
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else #[{|]#
\"no\"
}
}
"},
"<A-b>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} #[e|]#lse {
\"no\"
}
}
"},
),
// select mode extends
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
#["no"|]#
}
}
"##},
"v<A-b><A-b>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else #[|{
]#\"no\"
}
}
"},
),
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
#["no"|]#
}
}
"##},
"v<A-b><A-b><A-b>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} #[|else {
]#\"no\"
}
}
"},
),
];
for test in tests {
test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?;
}
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_smart_tab_move_parent_node_end() -> anyhow::Result<()> {
let tests = vec![
// single cursor stays single cursor, first goes to end of current
// node, then parent
(
indoc! {r##"
fn foo() {
let result = if true {
"yes"
} else {
"no#["|]#
}
}
"##},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"#[|\n]#
}
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"#[\n|]#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"
}#[|\n]#
}
"},
),
// appending to the end of a line should still look at the current
// line, not the next one
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no#[\"|]#
}
}
"},
"a<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"
}#[\n|]#
}
"},
),
// before cursor is all whitespace, so insert tab
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
#[\"no\"|]#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
#[|\"no\"]#
}
}
"},
),
// if selection spans multiple lines, it should still only look at the
// line on which the head is
(
indoc! {"\
fn foo() {
let result = if true {
#[\"yes\"
} else {
\"no\"|]#
}
}
"},
"a<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
} else {
\"no\"
}#[\n|]#
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
#[\"yes\"
} else {
\"no\"|]#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
#[|\"yes\"
} else {
\"no\"]#
}
}
"},
),
(
indoc! {"\
fn foo() {
#[l|]#et result = if true {
#(\"yes\"
} else {
\"no\"|)#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
#[|l]#et result = if true {
#(|\"yes\"
} else {
\"no\")#
}
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
\"yes\"#[\n|]#
} else {
\"no\"#(\n|)#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
}#[| ]#else {
\"no\"
}#(|\n)#
}
"},
),
(
indoc! {"\
fn foo() {
let result = if true {
#[\"yes\"|]#
} else {
#(\"no\"|)#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
#[|\"yes\"]#
} else {
#(|\"no\")#
}
}
"},
),
// if any cursors are not preceded by all whitespace, then do the
// smart_tab action
(
indoc! {"\
fn foo() {
let result = if true {
#[\"yes\"\n|]#
} else {
\"no#(\"\n|)#
}
}
"},
"i<tab>",
indoc! {"\
fn foo() {
let result = if true {
\"yes\"
}#[| ]#else {
\"no\"
}#(|\n)#
}
"},
),
// Ctrl-tab always inserts a tab
(
indoc! {"\
fn foo() {
let result = if true {
#[\"yes\"\n|]#
} else {
\"no#(\"\n|)#
}
}
"},
"i<S-tab>",
indoc! {"\
fn foo() {
let result = if true {
#[|\"yes\"\n]#
} else {
\"no #(|\"\n)#
}
}
"},
),
];
for test in tests {
test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?;
}
Ok(())
}