src/render/mode/table_test.rs

#[cfg(test)]
mod tests {
    use crate::render::mode::table::TableRenderer;

    fn render_rows(rows: &[&[&str]], width: usize) -> String {
        let mut buf = Vec::new();
        {
            let mut r = TableRenderer::new(&mut buf, &["time", "host", "msg"], width);
            r.write_header().unwrap();
            for row in rows {
                r.write_row(row).unwrap();
            }
        }
        String::from_utf8(buf).unwrap()
    }

    #[test]
    fn header_appears_first() {
        let out = render_rows(&[&["10:00", "web", "ok"]], 80);
        assert!(out.lines().next().unwrap().contains("time"));
    }

    #[test]
    fn rows_align_wider_column_to_max_width() {
        let out = render_rows(
            &[
                &["10:00", "web", "ok"],
                &["10:01", "batch-worker", "ok"],
            ],
            200,
        );
        let mut lines = out.lines();
        let _header = lines.next().unwrap();
        let first = lines.next().unwrap();
        let second = lines.next().unwrap();
        assert_eq!(first.len(), second.len());
    }

    #[test]
    fn truncation_adds_ellipsis() {
        let out = render_rows(
            &[&["10:00", "web", "this is an extremely long message line"]],
            30,
        );
        assert!(out.contains('…'));
    }

    #[test]
    fn exact_fit_is_not_truncated() {
        let out = render_rows(&[&["00", "ab", "hi"]], 80);
        assert!(!out.contains('…'));
    }

    #[test]
    fn empty_rows_produce_header_only() {
        let out = render_rows(&[], 80);
        assert_eq!(out.lines().count(), 1);
    }
}