use super::*;
use crate::tui::{PickerBadge, PickerBadgeTone, PickerItem};
use pretty_assertions::assert_eq;
fn item(label: &str, section: Option<&str>) -> PickerItem {
PickerItem {
label: label.into(),
section: section.map(Into::into),
detail: None,
preview: None,
badge: None,
value: label.to_ascii_lowercase(),
selection_verb: None,
}
}
fn line_text(line: &ratatui::text::Line<'_>) -> String {
line.spans
.iter()
.map(|span| span.content.as_ref())
.collect()
}
fn aligned_layout(width: usize, column: usize) -> RowLayout {
RowLayout {
width,
width_mode: RowWidthMode::AlignedColumn(column),
show_badges: true,
show_preview: true,
fill: crate::tui::LineFill::Natural,
}
}
#[test]
fn aligned_rows_insert_section_headers_on_transitions() {
let items = vec![
item("alpha", Some("FIRST")),
item("beta", Some("FIRST")),
item("gamma", Some("SECOND")),
];
let matching = vec![0, 1, 2];
let rows = picker_item_rows(&items, &matching, 2, aligned_layout(40, 12), None);
let texts = rows
.rows
.iter()
.map(|line| line_text(line).trim_end().to_string())
.collect::<Vec<_>>();
assert_eq!(
texts,
vec![" FIRST", " alpha", " beta", " SECOND", "→ gamma"]
);
assert_eq!(rows.selected_row, 4);
}
#[test]
fn selected_row_index_ignores_headers_before_it() {
let items = vec![item("one", None), item("two", Some("GROUP"))];
let rows = picker_item_rows(&items, &[0, 1], 1, aligned_layout(30, 12), None);
assert_eq!(rows.selected_row, 2);
assert_eq!(rows.rows.len(), 3);
}
#[test]
fn scroll_window_start_keeps_selected_visible() {
assert_eq!(scroll_window_start(0, 5), 0);
assert_eq!(scroll_window_start(4, 5), 0);
assert_eq!(scroll_window_start(5, 5), 1);
assert_eq!(scroll_window_start(9, 5), 5);
assert_eq!(scroll_window_start(3, 0), 3);
}
#[test]
fn fill_pane_rows_pad_label_and_keep_badge() {
let mut badged = item("workhorse", None);
badged.badge = Some(PickerBadge {
text: "editable".into(),
tone: PickerBadgeTone::Editable,
});
let rows = picker_item_rows(
&[badged],
&[0],
0,
RowLayout {
width: 24,
width_mode: RowWidthMode::FillPane,
show_badges: true,
show_preview: false,
fill: crate::tui::LineFill::PadToWidth,
},
None,
);
let text = line_text(&rows.rows[0]);
assert_eq!(text, "→ workhorse editable");
assert_eq!(text.chars().count(), 24);
}
#[test]
fn aligned_rows_show_preview_after_badge() {
let mut full = item("model", None);
full.badge = Some(PickerBadge {
text: "pinned".into(),
tone: PickerBadgeTone::Favorite,
});
full.preview = Some("fast default".into());
let rows = picker_item_rows(&[full], &[0], 0, aligned_layout(60, 12), None);
assert_eq!(
line_text(&rows.rows[0]),
"→ model pinned fast default"
);
}
#[test]
fn label_column_width_tracks_widest_label_within_caps() {
let narrow = vec![item("ab", None)];
assert_eq!(label_column_width(&narrow, 80), 12);
let wide = vec![item(&"x".repeat(90), None)];
assert_eq!(label_column_width(&wide, 200), 60);
let medium = vec![item(&"y".repeat(30), None)];
assert_eq!(label_column_width(&medium, 80), 30);
}