use pretty_assertions::assert_eq;
use ratatui::text::{Line, Span};
use super::{needle, scan_line, step_focus, Needle, ScanBuffers, SearchStep, TranscriptMatch};
use crate::tui::Theme;
fn line_matches(line: &Line<'_>, needle: &Needle) -> Vec<(usize, usize)> {
let mut hits = Vec::new();
scan_line(line, needle, &mut ScanBuffers::default(), |columns| {
hits.push((columns.start, columns.end));
});
hits
}
#[test]
fn line_matches_report_display_columns() {
let copy = || {
Span::styled(
" COPY ",
Theme::markdown_code_copy_button( false),
)
};
let cases = [
("empty query", Line::raw("anything"), "", vec![]),
(
"case-insensitive",
Line::raw(" Error: error"),
"ERROR",
vec![(1, 6), (8, 13)],
),
(
"across spans",
Line::from(vec![Span::raw(" pa"), Span::raw("th.rs")]),
"path",
vec![(1, 5)],
),
(
"wide glyphs shift columns",
Line::raw("日本 path"),
"path",
vec![(5, 9)],
),
(
"hit covers a wide glyph",
Line::raw("a日本"),
"日",
vec![(1, 3)],
),
(
"ascii query on a tool tree row",
Line::raw("│ Foo foo"),
"foo",
vec![(2, 5), (6, 9)],
),
(
"graphemes paint as one cell run",
Line::raw("👩\u{200d}💻 path"),
"path",
vec![(3, 7)],
),
(
"combining mark highlights its grapheme",
Line::raw("e\u{301}x"),
"\u{301}",
vec![(0, 1)],
),
(
"non-overlapping",
Line::raw("aaaa"),
"aa",
vec![(0, 2), (2, 4)],
),
(
"copy button is not text",
Line::from(vec![Span::raw("─"), copy(), Span::raw("─")]),
"copy",
vec![],
),
];
for (case, line, query, expected) in cases {
assert_eq!(line_matches(&line, &needle(query)), expected, "{case}");
}
}
#[test]
fn step_focus_searches_upward_and_wraps() {
let hits: Vec<TranscriptMatch> = [3, 10, 20]
.into_iter()
.map(|line| TranscriptMatch {
line,
columns: 0..1,
})
.collect();
let cases = [
("query above anchor", None, SearchStep::Query, 15, Some(1)),
(
"query ignores old focus",
Some(0),
SearchStep::Query,
21,
Some(2),
),
(
"query wraps when nothing above",
None,
SearchStep::Query,
2,
Some(2),
),
("older", Some(1), SearchStep::Older, 0, Some(0)),
("older wraps", Some(0), SearchStep::Older, 0, Some(2)),
("newer", Some(1), SearchStep::Newer, 0, Some(2)),
("newer wraps", Some(2), SearchStep::Newer, 0, Some(0)),
("stale focus clamps", Some(9), SearchStep::Older, 0, Some(1)),
];
for (case, focus, step, anchor, expected) in cases {
assert_eq!(step_focus(&hits, focus, step, anchor), expected, "{case}");
}
assert_eq!(step_focus(&[], None, SearchStep::Query, 5), None);
}