Lines
98.22 %
Functions
100 %
Branches
//! Tests for SplitsWidget: row/cell nav, option caching, render lines.
use super::*;
use crate::widgets::EditMode;
fn make_opts(n: usize) -> Vec<SelectOption> {
(0..n)
.map(|i| SelectOption {
id: format!("id-{i}"),
label: format!("Label {i}"),
})
.collect()
}
#[test]
fn new_has_one_row() {
let sw = SplitsWidget::new(EditMode::Emacs);
assert_eq!(sw.rows().len(), 1);
assert_eq!(sw.row_focus, 0);
assert_eq!(sw.col_focus, 0);
fn add_row_inserts_after_focus() {
let mut sw = SplitsWidget::new(EditMode::Emacs);
sw.add_row();
assert_eq!(sw.rows().len(), 2);
assert_eq!(sw.row_focus, 1);
fn add_row_three_times() {
assert_eq!(sw.rows().len(), 4);
fn remove_row_keeps_at_least_one() {
sw.remove_row();
fn remove_row_with_two_rows_leaves_one() {
fn remove_row_adjusts_focus_when_at_last() {
assert_eq!(sw.row_focus, 2);
fn advance_cell_walks_columns_then_stops_at_last_cell() {
for _ in 0..5 {
sw.advance_cell();
assert_eq!(
sw.col_focus, 5,
"single row: advance reaches the last column"
);
assert!(sw.at_last_cell());
sw.advance_cell(); // no-op at the boundary (caller yields)
assert_eq!(sw.col_focus, 5);
fn advance_cell_crosses_into_next_row() {
sw.row_focus = 0;
sw.col_focus = 5;
assert_eq!(sw.row_focus, 1, "advance from last col steps to next row");
fn retreat_cell_stops_at_first_cell() {
assert!(sw.at_first_cell());
sw.retreat_cell(); // no-op at the boundary (caller yields)
fn retreat_cell_crosses_into_previous_row() {
// focus is now (row 1, col 0); retreat → (row 0, last col)
sw.retreat_cell();
fn add_row_inherits_cached_options() {
sw.set_account_options(make_opts(3));
sw.set_commodity_options(make_opts(2));
let row = &sw.rows()[1];
assert_eq!(row.from.option_count(), 3, "new row from-account seeded");
assert_eq!(row.to.option_count(), 3, "new row to-account seeded");
row.from_commodity.option_count(),
2,
"new row from-commodity seeded"
row.to_commodity.option_count(),
"new row to-commodity seeded"
fn render_lines_shows_selected_labels_and_focus_marker() {
sw.set_account_options(make_opts(2));
let lines = sw.render_lines();
assert_eq!(lines.len(), 1);
assert!(
lines[0].starts_with('▸'),
"focused row marked: {}",
lines[0]
lines[0].contains("Label 0"),
"selected label shown: {}",
lines[0].contains("[Label 0]"),
"focused cell bracketed: {}",
fn next_row_wraps_single() {
sw.next_row();
fn next_row_wraps_two() {
fn prev_row_wraps() {
sw.prev_row();
fn col_kind_select_for_first_four() {
assert_eq!(SplitRow::col_kind(COL_FROM), WidgetKind::Select);
assert_eq!(SplitRow::col_kind(COL_TO), WidgetKind::Select);
assert_eq!(SplitRow::col_kind(COL_FROM_COMM), WidgetKind::Select);
assert_eq!(SplitRow::col_kind(COL_TO_COMM), WidgetKind::Select);
fn col_kind_amount_for_last_two() {
assert_eq!(SplitRow::col_kind(COL_VALUE), WidgetKind::Amount);
assert_eq!(SplitRow::col_kind(COL_TO_AMOUNT), WidgetKind::Amount);
fn set_account_options_populates_all_rows() {
for row in sw.rows() {
assert_eq!(row.from.option_count(), 3);
assert_eq!(row.to.option_count(), 3);
fn set_commodity_options_populates_all_rows() {
assert_eq!(row.from_commodity.option_count(), 2);
assert_eq!(row.to_commodity.option_count(), 2);
fn focused_subwidget_kind_follows_col_focus() {
sw.col_focus = COL_FROM;
assert_eq!(sw.focused_subwidget_kind(), WidgetKind::Select);
sw.col_focus = COL_VALUE;
assert_eq!(sw.focused_subwidget_kind(), WidgetKind::Amount);
fn display_shows_row_and_col() {
let d = sw.display();
assert!(d.contains("1 split(s)"), "row count: {d}");
assert!(d.contains("row 0"), "row focus: {d}");