use super::*;
#[test]
fn test_basic_motion() {
let mut editor = VimLineEditor::new();
let text = "hello world";
editor.handle_key(Key::char('l'), text);
assert_eq!(editor.cursor(), 1);
editor.handle_key(Key::char('w'), text);
assert_eq!(editor.cursor(), 6);
editor.handle_key(Key::char('$'), text);
assert_eq!(editor.cursor(), 10);
editor.handle_key(Key::char('0'), text);
assert_eq!(editor.cursor(), 0);
}
#[test]
fn test_mode_switching() {
let mut editor = VimLineEditor::new();
let text = "hello";
assert_eq!(editor.mode(), Mode::Normal);
editor.handle_key(Key::char('i'), text);
assert_eq!(editor.mode(), Mode::Insert);
editor.handle_key(Key::code(KeyCode::Escape), text);
assert_eq!(editor.mode(), Mode::Normal);
}
#[test]
fn test_delete_word() {
let mut editor = VimLineEditor::new();
let text = "hello world";
editor.handle_key(Key::char('d'), text);
editor.handle_key(Key::char('w'), text);
assert_eq!(editor.mode(), Mode::Normal);
}
#[test]
fn test_insert_char() {
let mut editor = VimLineEditor::new();
let text = "";
editor.handle_key(Key::char('i'), text);
let result = editor.handle_key(Key::char('x'), text);
assert_eq!(result.edits.len(), 1);
match &result.edits[0] {
TextEdit::Insert { at, text } => {
assert_eq!(*at, 0);
assert_eq!(text, "x");
}
_ => panic!("Expected Insert"),
}
}
#[test]
fn test_visual_mode() {
let mut editor = VimLineEditor::new();
let text = "hello world";
editor.handle_key(Key::char('v'), text);
assert_eq!(editor.mode(), Mode::Visual);
editor.handle_key(Key::char('w'), text);
let sel = editor.selection().unwrap();
assert_eq!(sel.start, 0);
assert!(sel.end > 0);
}
#[test]
fn test_backspace_ascii() {
let mut editor = VimLineEditor::new();
let mut text = String::from("abc");
editor.handle_key(Key::char('i'), &text);
editor.handle_key(Key::code(KeyCode::End), &text);
assert_eq!(editor.cursor(), 3);
let result = editor.handle_key(Key::code(KeyCode::Backspace), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "ab");
assert_eq!(editor.cursor(), 2);
}
#[test]
fn test_backspace_unicode() {
let mut editor = VimLineEditor::new();
let mut text = String::from("a😀b");
editor.handle_key(Key::char('i'), &text);
editor.handle_key(Key::code(KeyCode::End), &text);
editor.handle_key(Key::code(KeyCode::Left), &text); assert_eq!(editor.cursor(), 5);
let result = editor.handle_key(Key::code(KeyCode::Backspace), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "ab");
assert_eq!(editor.cursor(), 1);
}
#[test]
fn test_yank_and_paste() {
let mut editor = VimLineEditor::new();
let mut text = String::from("hello world");
editor.handle_key(Key::char('y'), &text);
let result = editor.handle_key(Key::char('w'), &text);
assert!(result.yanked.is_some());
assert_eq!(result.yanked.unwrap(), "hello ");
editor.handle_key(Key::char('$'), &text);
let result = editor.handle_key(Key::char('p'), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "hello worldhello ");
}
#[test]
fn test_visual_mode_delete() {
let mut editor = VimLineEditor::new();
let mut text = String::from("hello world");
editor.handle_key(Key::char('v'), &text);
assert_eq!(editor.mode(), Mode::Visual);
editor.handle_key(Key::char('e'), &text);
let result = editor.handle_key(Key::char('d'), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, " world");
assert_eq!(editor.mode(), Mode::Normal);
}
#[test]
fn test_operator_pending_escape() {
let mut editor = VimLineEditor::new();
let text = "hello world";
editor.handle_key(Key::char('d'), text);
assert!(matches!(editor.mode(), Mode::OperatorPending(_)));
editor.handle_key(Key::code(KeyCode::Escape), text);
assert_eq!(editor.mode(), Mode::Normal);
}
#[test]
fn test_replace_char() {
let mut editor = VimLineEditor::new();
let mut text = String::from("hello");
editor.handle_key(Key::char('r'), &text);
assert_eq!(editor.mode(), Mode::ReplaceChar);
let result = editor.handle_key(Key::char('x'), &text);
assert_eq!(editor.mode(), Mode::Normal);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "xello");
}
#[test]
fn test_replace_char_escape() {
let mut editor = VimLineEditor::new();
let text = "hello";
editor.handle_key(Key::char('r'), text);
assert_eq!(editor.mode(), Mode::ReplaceChar);
editor.handle_key(Key::code(KeyCode::Escape), text);
assert_eq!(editor.mode(), Mode::Normal);
}
#[test]
fn test_cw_no_trailing_space() {
let mut editor = VimLineEditor::new();
let mut text = String::from("hello world");
editor.handle_key(Key::char('c'), &text);
let result = editor.handle_key(Key::char('w'), &text);
assert_eq!(editor.mode(), Mode::Insert);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, " world");
}
#[test]
fn test_dw_includes_trailing_space() {
let mut editor = VimLineEditor::new();
let mut text = String::from("hello world");
editor.handle_key(Key::char('d'), &text);
let result = editor.handle_key(Key::char('w'), &text);
assert_eq!(editor.mode(), Mode::Normal);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "world");
}
#[test]
fn test_paste_at_empty_buffer() {
let mut editor = VimLineEditor::new();
let yank_text = String::from("test");
editor.handle_key(Key::char('y'), &yank_text);
editor.handle_key(Key::char('w'), &yank_text);
let mut text = String::new();
editor.set_cursor(0, &text);
let result = editor.handle_key(Key::char('p'), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "test");
}
#[test]
fn test_dollar_cursor_on_last_char() {
let mut editor = VimLineEditor::new();
let text = "abc";
editor.handle_key(Key::char('$'), text);
assert_eq!(editor.cursor(), 2);
let text = "x";
editor.set_cursor(0, text);
editor.handle_key(Key::char('$'), text);
assert_eq!(editor.cursor(), 0); }
#[test]
fn test_x_delete_last_char_moves_cursor_left() {
let mut editor = VimLineEditor::new();
let mut text = String::from("abc");
editor.handle_key(Key::char('$'), &text);
assert_eq!(editor.cursor(), 2);
let result = editor.handle_key(Key::char('x'), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "ab");
assert_eq!(editor.cursor(), 1); }
#[test]
fn test_x_delete_middle_char_cursor_stays() {
let mut editor = VimLineEditor::new();
let mut text = String::from("abc");
editor.handle_key(Key::char('l'), &text);
assert_eq!(editor.cursor(), 1);
let result = editor.handle_key(Key::char('x'), &text);
for edit in result.edits.into_iter().rev() {
edit.apply(&mut text);
}
assert_eq!(text, "ac");
assert_eq!(editor.cursor(), 1);
}
#[test]
fn test_percent_bracket_matching() {
let mut editor = VimLineEditor::new();
let text = "(hello world)";
assert_eq!(editor.cursor(), 0);
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 12);
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 0);
}
#[test]
fn test_percent_nested_brackets() {
let mut editor = VimLineEditor::new();
let text = "([{<>}])";
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 7);
editor.set_cursor(1, text);
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 6);
editor.set_cursor(2, text);
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 5);
editor.set_cursor(3, text);
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), 4); }
#[test]
fn test_percent_on_non_bracket() {
let mut editor = VimLineEditor::new();
let text = "hello";
let orig_cursor = editor.cursor();
editor.handle_key(Key::char('%'), text);
assert_eq!(editor.cursor(), orig_cursor);
}