use super::*; fn layout(text: &str, width: usize) -> Vec { let mut cache = WrapCache::default(); cache.prepare((1, 0), width); cache.segments(0, text).to_vec() } #[test] fn words_and_long_words_preserve_every_source_cell() { assert_eq!( layout("one two three", 8), vec![Segment { start: 0, end: 8 }, Segment { start: 8, end: 13 },] ); let segments = layout("abcdefgh", 3); assert_eq!( segments, vec![ Segment { start: 0, end: 3 }, Segment { start: 3, end: 6 }, Segment { start: 6, end: 8 }, ] ); assert_eq!(caret_segment(&segments, 3), 1); assert_eq!(caret_segment(&segments, 8), 2); } #[test] fn long_words_do_not_wrap_indentation_onto_an_empty_visual_row() { for source in [ " abcdefghijk", "\tabcdefghijk", "head abcdefghijk", ] { let expanded = source.replace('\t', " "); let segments = layout(source, 8); assert_eq!(segments.first().unwrap().start, 0); assert_eq!(segments.last().unwrap().end, expanded.len()); assert!(segments.windows(2).all(|pair| pair[0].end == pair[1].start)); for segment in segments .iter() .filter(|segment| segment.start < segment.end) { assert!( !expanded[segment.start..segment.end].trim().is_empty(), "whitespace-only visual row {segment:?} in {source:?}" ); } } } #[test] fn tabs_use_source_stops_and_unicode_graphemes_remain_intact() { assert_eq!( layout("ab\t界e\u{301} z", 4), vec![ Segment { start: 0, end: 4 }, Segment { start: 4, end: 8 }, Segment { start: 8, end: 9 }, ] ); assert_eq!( layout("界界界", 3), vec![ Segment { start: 0, end: 2 }, Segment { start: 2, end: 4 }, Segment { start: 4, end: 6 }, ] ); assert_eq!( layout(" \t ", 3), vec![Segment { start: 0, end: 3 }, Segment { start: 3, end: 5 },] ); } #[test] fn narrow_tabs_preserve_all_expanded_cells_at_original_stops() { assert_eq!( layout("\tX", 2), [ Segment { start: 0, end: 2 }, Segment { start: 2, end: 4 }, Segment { start: 4, end: 5 }, ] ); assert_eq!( layout("a\tX", 2), [ Segment { start: 0, end: 1 }, Segment { start: 1, end: 3 }, Segment { start: 3, end: 5 }, Segment { start: 5, end: 5 }, ] ); for source in ["\t", "a\t", "ab\tX", "\t\tX"] { let segments = layout(source, 1); assert!( segments .iter() .all(|segment| segment.end - segment.start <= 1) ); assert!(segments.windows(2).all(|pair| pair[0].end == pair[1].start)); let end = source.graphemes(true).fold(0, |column, grapheme| { column + if grapheme == "\t" { TAB_WIDTH - column % TAB_WIDTH } else { 1 } }); assert_eq!(segments.last().unwrap(), &Segment { start: end, end }); } } #[test] fn full_lines_have_an_insertion_cell_and_cache_invalidation_is_lazy() { let mut cache = WrapCache::default(); cache.prepare((7, 2), 4); assert_eq!( cache.segments(90, "abcd"), [Segment { start: 0, end: 4 }, Segment { start: 4, end: 4 },] ); assert_eq!(caret_segment(cache.segments(90, "abcd"), 4), 1); assert_eq!(cache.rows.len(), 1); cache.prepare((7, 2), 4); assert_eq!(cache.rows.len(), 1); cache.prepare((7, 2), 8); assert!(cache.rows.is_empty()); cache.segments(90, "abcd"); cache.prepare((7, 3), 8); assert!(cache.rows.is_empty()); assert_eq!(layout("", 0), [Segment { start: 0, end: 0 }]); }