#![allow(clippy::unwrap_used, clippy::expect_used)]
use idet_core::{
completion::{char_to_byte, collect_words, current_prefix, current_word, matches},
edits::{changed_range, dedent_line, indent_line, insert, newline_indent},
lineops::{LineMove, Segment, move_line, move_segment},
wordops::{WordSwap, swap},
};
#[test]
fn move_line_swaps_and_keeps_column() {
let text = "alpha\nbeta\ngamma";
let (moved, cursor) = move_line(text, 8, LineMove::Up).unwrap();
assert_eq!(moved, "beta\nalpha\ngamma");
assert_eq!(cursor, 2);
}
#[test]
fn move_line_down_at_last_line_is_none() {
let text = "one\ntwo";
assert!(move_line(text, 5, LineMove::Down).is_none());
}
#[test]
fn move_line_up_at_first_line_is_none() {
let text = "one\ntwo";
assert!(move_line(text, 1, LineMove::Up).is_none());
}
#[test]
fn move_line_cursor_follows_its_line() {
let text = "ab\ncdef";
let (moved, cursor) = move_line(text, 1, LineMove::Down).unwrap();
assert_eq!(moved, "cdef\nab");
assert_eq!(cursor, 6);
}
#[test]
fn move_line_counts_multibyte_columns() {
let text = "äö\nxy";
let (moved, cursor) = move_line(text, 1, LineMove::Down).unwrap();
assert_eq!(moved, "xy\näö");
assert_eq!(cursor, 4);
}
#[test]
fn move_block_swaps_paragraphs_and_keeps_the_gap() {
let text = "one\ntwo\n\n\nthree\nfour";
let (moved, cursor) = move_segment(text, 10, Segment::Block, LineMove::Up).unwrap();
assert_eq!(moved, "three\nfour\n\n\none\ntwo");
assert_eq!(cursor, 0);
}
#[test]
fn move_block_down_carries_the_cursor_along() {
let text = "one\ntwo\n\nthree";
let (moved, cursor) = move_segment(text, 5, Segment::Block, LineMove::Down).unwrap();
assert_eq!(moved, "three\n\none\ntwo");
assert_eq!(cursor, 12);
}
#[test]
fn move_block_on_a_blank_line_is_none() {
assert!(move_segment("one\n\ntwo", 4, Segment::Block, LineMove::Down).is_none());
}
#[test]
fn move_block_without_a_neighbour_is_none() {
assert!(move_segment("one\ntwo", 0, Segment::Block, LineMove::Up).is_none());
assert!(move_segment("one\n\n", 0, Segment::Block, LineMove::Down).is_none());
}
#[test]
fn move_section_takes_subsections_along() {
let text = "# top\n\n## a\nbody a\n\n### deep\n\n## b\nbody b\n";
let (moved, _) = move_segment(text, 8, Segment::Section, LineMove::Down).unwrap();
assert_eq!(moved, "# top\n\n## b\nbody b\n\n## a\nbody a\n\n### deep\n");
}
#[test]
fn move_section_works_from_inside_the_body() {
let text = "## a\nbody a\n## b\nbody b";
let (moved, cursor) = move_segment(text, 7, Segment::Section, LineMove::Down).unwrap();
assert_eq!(moved, "## b\nbody b\n## a\nbody a");
assert_eq!(cursor, 19);
}
#[test]
fn move_section_stops_at_a_different_level() {
let text = "# top\n## child\nbody\n# other";
assert!(move_segment(text, 6, Segment::Section, LineMove::Down).is_none());
assert!(move_segment(text, 6, Segment::Section, LineMove::Up).is_none());
}
#[test]
fn move_section_outside_any_heading_is_none() {
assert!(move_segment("plain\ntext", 0, Segment::Section, LineMove::Down).is_none());
}
#[test]
fn heading_needs_a_space_after_the_hashes() {
let text = "#nope\n# yes\nbody\n# also";
let (moved, _) = move_segment(text, 8, Segment::Section, LineMove::Down).unwrap();
assert_eq!(moved, "#nope\n# also\n# yes\nbody");
}
#[test]
fn collect_words_dedups_and_filters_short() {
let words = collect_words("foo bar foo a bb baz_1");
assert_eq!(
words,
vec![
("foo".to_owned(), 2),
("bar".to_owned(), 1),
("baz_1".to_owned(), 1),
]
);
}
#[test]
fn current_prefix_reads_word_before_cursor() {
assert_eq!(current_prefix("let val", 7), "val");
assert_eq!(current_prefix("let val ", 8), "");
assert_eq!(current_prefix("hä_ll", 5), "hä_ll");
}
#[test]
fn current_word_spans_both_directions() {
assert_eq!(current_word("hello world", 3), (0, 5));
assert_eq!(current_word("hello world", 6), (6, 11));
assert_eq!(current_word("hello world", 5), (0, 5));
assert_eq!(current_word("a b", 2), (2, 2));
assert_eq!(current_word("hä_ll", 5), (0, 5));
}
#[test]
fn matches_keeps_exact_word_beside_longer_ones() {
let words = vec![
("value".to_owned(), 3),
("val".to_owned(), 1),
("other".to_owned(), 2),
];
let found = matches(&words, "val");
assert_eq!(
found,
vec![(&"value".to_owned(), 3), (&"val".to_owned(), 1)]
);
}
#[test]
fn matches_is_empty_when_only_the_exact_word_fits() {
let words = vec![("val".to_owned(), 1), ("other".to_owned(), 2)];
assert!(matches(&words, "val").is_empty());
}
#[test]
fn char_to_byte_handles_multibyte() {
assert_eq!(char_to_byte("äbc", 0), 0);
assert_eq!(char_to_byte("äbc", 1), 2);
assert_eq!(char_to_byte("äbc", 3), 4);
}
#[test]
fn swap_caret_word_with_next() {
assert_eq!(
swap("foo bar", (1, 1), WordSwap::Next).unwrap(),
("bar foo".to_owned(), (5, 5))
);
}
#[test]
fn swap_caret_word_with_prev() {
assert_eq!(
swap("foo bar", (5, 5), WordSwap::Prev).unwrap(),
("bar foo".to_owned(), (1, 1))
);
}
#[test]
fn swap_none_without_neighbour() {
assert!(swap("foo", (1, 1), WordSwap::Next).is_none());
assert!(swap(" ", (1, 1), WordSwap::Next).is_none());
}
#[test]
fn swap_caret_word_keeps_multibyte() {
assert_eq!(
swap("ä ö", (0, 0), WordSwap::Next).unwrap(),
("ö ä".to_owned(), (2, 2))
);
}
#[test]
fn swap_selection_moves_whole_span() {
assert_eq!(
swap("don't next", (0, 5), WordSwap::Next).unwrap(),
("next don't".to_owned(), (5, 10))
);
}
#[test]
fn swap_selection_prev_keeps_range() {
assert_eq!(
swap("one don't", (4, 9), WordSwap::Prev).unwrap(),
("don't one".to_owned(), (0, 5))
);
}
#[test]
fn insert_places_after_insertion() {
assert_eq!(insert("ab", 1, "XY"), ("aXYb".to_owned(), 3));
}
#[test]
fn newline_indent_copies_leading_whitespace() {
assert_eq!(newline_indent(" x", 5), (" x\n ".to_owned(), 10));
}
#[test]
fn indent_line_prepends_a_tab_width_of_spaces() {
assert_eq!(indent_line("ab\ncd", 4, 4), ("ab\n cd".to_owned(), 8));
assert_eq!(indent_line("ab\ncd", 4, 2), ("ab\n cd".to_owned(), 6));
}
#[test]
fn changed_range_spans_restored_text() {
assert_eq!(changed_range("ac", "abbc"), (1, 3));
}
#[test]
fn changed_range_is_empty_where_text_vanished() {
assert_eq!(changed_range("abbc", "ac"), (1, 1));
}
#[test]
fn changed_range_counts_characters_not_bytes() {
assert_eq!(changed_range("äc", "äöüc"), (1, 3));
}
#[test]
fn changed_range_handles_a_repeated_neighbour() {
assert_eq!(changed_range("aa", "aaa"), (2, 3));
assert_eq!(changed_range("", "abc"), (0, 3));
}
#[test]
fn dedent_line_removes_leading_spaces() {
assert_eq!(dedent_line(" cd", 7, 4), (" cd".to_owned(), 3));
assert_eq!(dedent_line("cd", 1, 4), ("cd".to_owned(), 1));
assert_eq!(dedent_line(" cd", 7, 2), (" cd".to_owned(), 5));
}