lv-tui 0.4.0

A reactive TUI framework for Rust
Documentation
/// Integration tests for DataTable enhancements (RFC 58).
use lv_tui::prelude::*;
use lv_tui::widgets::*;

fn has_text(buf: &Buffer, text: &str) -> bool {
    let all: String = buf.cells.iter().map(|c| c.symbol.as_str()).collect();
    all.contains(text)
}

fn col(title: &str, w: ColumnWidth) -> TableColumn {
    TableColumn { title: Text::from(title), width: w, align: TextAlign::Left }
}

// ── Basic table rendering (backward compat) ────────────────────

#[test]
fn table_renders_headers_and_data() {
    let t = Table::new()
        .columns(vec![col("Name", ColumnWidth::Fixed(10)), col("Size", ColumnWidth::Fixed(8))])
        .rows_simple(vec![vec!["a.rs", "1KB"], vec!["b.rs", "2KB"]]);
    let pilot = Pilot::new(t, 30, 8);

    assert!(has_text(pilot.frame(), "Name"), "header visible");
    assert!(has_text(pilot.frame(), "a.rs"), "row data visible");
}

// ── Row selection (existing behavior) ──────────────────────────

#[test]
fn table_down_selects_row() {
    let t = Table::new()
        .columns(vec![col("Col", ColumnWidth::Fixed(10))])
        .rows_simple(vec![vec!["A"], vec!["B"], vec!["C"]])
        .select_style(Style::default().fg(Color::White).bg(Color::Black));
    let mut pilot = Pilot::new(t, 20, 8);

    pilot.press(Key::Down).unwrap(); // select row 1
    // Row 1 ("B") should still be rendered
    assert!(has_text(pilot.frame(), "B"), "row B visible after Down");
}

// ── Fixed rows (header stays visible) ───────────────────────────

#[test]
fn table_fixed_rows_keeps_header() {
    let mut rows = Vec::new();
    for i in 0..20 {
        rows.push(vec![format!("row-{}", i)]);
    }
    let t = Table::new()
        .columns(vec![col("Col", ColumnWidth::Fixed(10))])
        .rows_simple(rows)
        .fixed_rows(2) // header + separator stay fixed
        .select_style(Style::default().fg(Color::White).bg(Color::Black));

    let mut pilot = Pilot::new(t, 20, 8);

    // Scroll down several times
    for _ in 0..5 {
        pilot.press(Key::Down).unwrap();
    }

    // Header should still be visible
    assert!(has_text(pilot.frame(), "Col"), "header should stay fixed");
}

// ── Cell cursor mode ───────────────────────────────────────────

#[test]
fn table_cell_mode_left_right() {
    let t = Table::new()
        .columns(vec![
            col("A", ColumnWidth::Fixed(8)),
            col("B", ColumnWidth::Fixed(8)),
            col("C", ColumnWidth::Fixed(8)),
        ])
        .rows_simple(vec![vec!["a1", "b1", "c1"], vec!["a2", "b2", "c2"]])
        .cursor_type(CursorType::Cell)
        .select_style(Style::default().fg(Color::White).bg(Color::Black));

    let mut pilot = Pilot::new(t, 40, 8);

    // Navigate right in Cell mode
    pilot.press(Key::Right).unwrap();
    // After right, selected_column should be 1
    // Table still renders correctly
    assert!(has_text(pilot.frame(), "b1"), "data still rendered after right");
}

// ── Three level highlight ──────────────────────────────────────

#[test]
fn table_column_highlight() {
    let t = Table::new()
        .columns(vec![col("X", ColumnWidth::Fixed(10)), col("Y", ColumnWidth::Fixed(10))])
        .rows_simple(vec![vec!["x1", "y1"]])
        .column_highlight_style(Style::default().bold());

    let pilot = Pilot::new(t, 30, 8);
    // Just verify the table renders with column highlight set
    assert!(has_text(pilot.frame(), "X"), "table renders with column highlight");
}

#[test]
fn table_cell_highlight() {
    let t = Table::new()
        .columns(vec![col("Name", ColumnWidth::Fixed(12))])
        .rows_simple(vec![vec!["value"]])
        .select_style(Style::default().fg(Color::White).bg(Color::Black))
        .cell_highlight_style(Style::default().bold());

    // Row 0 column 0 should be highlighted
    let mut pilot = Pilot::new(t, 20, 8);
    // Select first row
    pilot.press(Key::Down).unwrap();
    assert!(has_text(pilot.frame(), "value"), "selected cell still renders");
}

// ── Backward compat: no new fields set ─────────────────────────

#[test]
fn table_defaults_work() {
    let t = Table::new()
        .columns(vec![col("H", ColumnWidth::Fixed(6))])
        .rows_simple(vec![vec!["d"]]);
    let pilot = Pilot::new(t, 20, 6);

    assert!(has_text(pilot.frame(), "H"), "default table renders");
    assert!(has_text(pilot.frame(), "d"), "default data renders");
}