Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/test.rs')
| -rw-r--r-- | helix-core/src/test.rs | 386 |
1 files changed, 0 insertions, 386 deletions
diff --git a/helix-core/src/test.rs b/helix-core/src/test.rs deleted file mode 100644 index 71c71cce..00000000 --- a/helix-core/src/test.rs +++ /dev/null @@ -1,386 +0,0 @@ -//! Test helpers. -use crate::{Range, Selection}; -use ropey::Rope; -use smallvec::SmallVec; -use std::cmp::Reverse; -use unicode_segmentation::UnicodeSegmentation; - -/// Convert annotated test string to test string and selection. -/// -/// `#[|` for primary selection with head before anchor followed by `]#`. -/// `#(|` for secondary selection with head before anchor followed by `)#`. -/// `#[` for primary selection with head after anchor followed by `|]#`. -/// `#(` for secondary selection with head after anchor followed by `|)#`. -/// -/// If the selection contains any LF or CRLF sequences, which are immediately -/// followed by the same grapheme, then the subsequent one is removed. This is -/// to allow representing having the cursor over the end of the line. -/// -/// # Examples -/// -/// ``` -/// use helix_core::{Range, Selection, test::print}; -/// use smallvec::smallvec; -/// -/// assert_eq!( -/// print("#[a|]#b#(|c)#"), -/// ("abc".to_owned(), Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)) -/// ); -/// ``` -/// -/// # Panics -/// -/// Panics when missing primary or appeared more than once. -/// Panics when missing head or anchor. -/// Panics when head come after head or anchor come after anchor. -pub fn print(s: &str) -> (String, Selection) { - let mut primary_idx = None; - let mut ranges = SmallVec::new(); - let mut iter = UnicodeSegmentation::graphemes(s, true).peekable(); - let mut left = String::with_capacity(s.len()); - - 'outer: while let Some(c) = iter.next() { - let start = left.chars().count(); - - if c != "#" { - left.push_str(c); - continue; - } - - let (is_primary, close_pair) = match iter.next() { - Some("[") => (true, "]"), - Some("(") => (false, ")"), - Some(ch) => { - left.push('#'); - left.push_str(ch); - continue; - } - None => break, - }; - - if is_primary && primary_idx.is_some() { - panic!("primary `#[` already appeared {:?} {:?}", left, s); - } - - let head_at_beg = iter.next_if_eq(&"|").is_some(); - let last_grapheme = |s: &str| { - UnicodeSegmentation::graphemes(s, true) - .next_back() - .map(String::from) - }; - - while let Some(c) = iter.next() { - let next = iter.peek(); - let mut prev = last_grapheme(left.as_str()); - - if !(c == close_pair && next == Some(&"#")) { - left.push_str(c); - continue; - } - - if !head_at_beg { - match &prev { - Some(p) if p != "|" => { - left.push_str(c); - continue; - } - Some(p) if p == "|" => { - left.pop().unwrap(); // pop the | - prev = last_grapheme(left.as_str()); - } - _ => (), - } - } - - iter.next(); // skip "#" - let next = iter.peek(); - - // skip explicit line end inside selection - if (prev == Some(String::from("\r\n")) || prev == Some(String::from("\n"))) - && next.map(|n| String::from(*n)) == prev - { - iter.next(); - } - - if is_primary { - primary_idx = Some(ranges.len()); - } - - let (anchor, head) = match head_at_beg { - true => (left.chars().count(), start), - false => (start, left.chars().count()), - }; - - ranges.push(Range::new(anchor, head)); - continue 'outer; - } - - if head_at_beg { - panic!("missing end `{}#` {:?} {:?}", close_pair, left, s); - } else { - panic!("missing end `|{}#` {:?} {:?}", close_pair, left, s); - } - } - - let primary = match primary_idx { - Some(i) => i, - None => panic!("missing primary `#[|]#` {:?}", s), - }; - - let selection = Selection::new(ranges, primary); - (left, selection) -} - -/// Convert test string and selection to annotated test string. -/// -/// `#[|` for primary selection with head before anchor followed by `]#`. -/// `#(|` for secondary selection with head before anchor followed by `)#`. -/// `#[` for primary selection with head after anchor followed by `|]#`. -/// `#(` for secondary selection with head after anchor followed by `|)#`. -/// -/// # Examples -/// -/// ``` -/// use helix_core::{Range, Selection, test::plain}; -/// use smallvec::smallvec; -/// -/// assert_eq!( -/// plain("abc", &Selection::new(smallvec![Range::new(0, 1), Range::new(3, 2)], 0)), -/// "#[a|]#b#(|c)#".to_owned() -/// ); -/// ``` -pub fn plain<R: Into<Rope>>(s: R, selection: &Selection) -> String { - let s = s.into(); - let primary = selection.primary_index(); - let mut out = String::with_capacity(s.len_bytes() + 5 * selection.len()); - out.push_str(&s.to_string()); - - let mut insertion: Vec<_> = selection - .iter() - .enumerate() - .flat_map(|(i, range)| { - // sort like this before reversed so anchor < head later - match (range.anchor < range.head, i == primary) { - (true, true) => [(range.anchor, "#["), (range.head, "|]#")], - (true, false) => [(range.anchor, "#("), (range.head, "|)#")], - (false, true) => [(range.anchor, "]#"), (range.head, "#[|")], - (false, false) => [(range.anchor, ")#"), (range.head, "#(|")], - } - }) - .map(|(char_idx, marker)| (s.char_to_byte(char_idx), marker)) - .collect(); - - // insert in reverse order - insertion.sort_unstable_by_key(|k| Reverse(k.0)); - for (i, s) in insertion { - out.insert_str(i, s); - } - out -} - -#[cfg(test)] -#[allow(clippy::module_inception)] -mod test { - use super::*; - - #[test] - fn print_single() { - assert_eq!( - (String::from("hello"), Selection::single(1, 0)), - print("#[|h]#ello") - ); - assert_eq!( - (String::from("hello"), Selection::single(0, 1)), - print("#[h|]#ello") - ); - assert_eq!( - (String::from("hello"), Selection::single(4, 0)), - print("#[|hell]#o") - ); - assert_eq!( - (String::from("hello"), Selection::single(0, 4)), - print("#[hell|]#o") - ); - assert_eq!( - (String::from("hello"), Selection::single(5, 0)), - print("#[|hello]#") - ); - assert_eq!( - (String::from("hello"), Selection::single(0, 5)), - print("#[hello|]#") - ); - } - - #[test] - fn print_multi() { - assert_eq!( - ( - String::from("hello"), - Selection::new( - SmallVec::from_slice(&[Range::new(1, 0), Range::new(5, 4)]), - 0 - ) - ), - print("#[|h]#ell#(|o)#") - ); - assert_eq!( - ( - String::from("hello"), - Selection::new( - SmallVec::from_slice(&[Range::new(0, 1), Range::new(4, 5)]), - 0 - ) - ), - print("#[h|]#ell#(o|)#") - ); - assert_eq!( - ( - String::from("hello"), - Selection::new( - SmallVec::from_slice(&[Range::new(2, 0), Range::new(5, 3)]), - 0 - ) - ), - print("#[|he]#l#(|lo)#") - ); - assert_eq!( - ( - String::from("hello\r\nhello\r\nhello\r\n"), - Selection::new( - SmallVec::from_slice(&[ - Range::new(7, 5), - Range::new(21, 19), - Range::new(14, 12) - ]), - 0 - ) - ), - print("hello#[|\r\n]#hello#(|\r\n)#hello#(|\r\n)#") - ); - } - - #[test] - fn print_multi_byte_code_point() { - assert_eq!( - (String::from("„“"), Selection::single(1, 0)), - print("#[|„]#“") - ); - assert_eq!( - (String::from("„“"), Selection::single(2, 1)), - print("„#[|“]#") - ); - assert_eq!( - (String::from("„“"), Selection::single(0, 1)), - print("#[„|]#“") - ); - assert_eq!( - (String::from("„“"), Selection::single(1, 2)), - print("„#[“|]#") - ); - assert_eq!( - (String::from("they said „hello“"), Selection::single(11, 10)), - print("they said #[|„]#hello“") - ); - } - - #[test] - fn print_multi_code_point_grapheme() { - assert_eq!( - ( - String::from("hello 👨👩👧👦 goodbye"), - Selection::single(13, 6) - ), - print("hello #[|👨👩👧👦]# goodbye") - ); - } - - #[test] - fn plain_single() { - assert_eq!("#[|h]#ello", plain("hello", &Selection::single(1, 0))); - assert_eq!("#[h|]#ello", plain("hello", &Selection::single(0, 1))); - assert_eq!("#[|hell]#o", plain("hello", &Selection::single(4, 0))); - assert_eq!("#[hell|]#o", plain("hello", &Selection::single(0, 4))); - assert_eq!("#[|hello]#", plain("hello", &Selection::single(5, 0))); - assert_eq!("#[hello|]#", plain("hello", &Selection::single(0, 5))); - } - - #[test] - fn plain_multi() { - assert_eq!( - plain( - "hello", - &Selection::new( - SmallVec::from_slice(&[Range::new(1, 0), Range::new(5, 4)]), - 0 - ) - ), - String::from("#[|h]#ell#(|o)#") - ); - assert_eq!( - plain( - "hello", - &Selection::new( - SmallVec::from_slice(&[Range::new(0, 1), Range::new(4, 5)]), - 0 - ) - ), - String::from("#[h|]#ell#(o|)#") - ); - assert_eq!( - plain( - "hello", - &Selection::new( - SmallVec::from_slice(&[Range::new(2, 0), Range::new(5, 3)]), - 0 - ) - ), - String::from("#[|he]#l#(|lo)#") - ); - assert_eq!( - plain( - "hello\r\nhello\r\nhello\r\n", - &Selection::new( - SmallVec::from_slice(&[ - Range::new(7, 5), - Range::new(21, 19), - Range::new(14, 12) - ]), - 0 - ) - ), - String::from("hello#[|\r\n]#hello#(|\r\n)#hello#(|\r\n)#") - ); - } - - #[test] - fn plain_multi_byte_code_point() { - assert_eq!( - plain("„“", &Selection::single(1, 0)), - String::from("#[|„]#“") - ); - assert_eq!( - plain("„“", &Selection::single(2, 1)), - String::from("„#[|“]#") - ); - assert_eq!( - plain("„“", &Selection::single(0, 1)), - String::from("#[„|]#“") - ); - assert_eq!( - plain("„“", &Selection::single(1, 2)), - String::from("„#[“|]#") - ); - assert_eq!( - plain("they said „hello“", &Selection::single(11, 10)), - String::from("they said #[|„]#hello“") - ); - } - - #[test] - fn plain_multi_code_point_grapheme() { - assert_eq!( - plain("hello 👨👩👧👦 goodbye", &Selection::single(13, 6)), - String::from("hello #[|👨👩👧👦]# goodbye") - ); - } -} |