tabprinter 0.2.2

tabprinter is a Rust library for creating and printing formatted tables in the terminal. It supports various table styles and offers both color and non-color output options.
Documentation
// SPDX-License-Identifier: MIT
// Project: tabprinter
// File: src/tests.rs
// Author: Volker Schwaberow <volker@schwaberow.de>
// Copyright (c) 2024 Volker Schwaberow

use super::*;

fn create_test_table(style: TableStyle) -> Table {
    let mut table = Table::new(style);
    table.add_column("Name", Alignment::Left);
    table.add_column("Age", Alignment::Right);
    table.add_column("City", Alignment::Center);
    table.add_row(vec![
        Cell::new("Alice"),
        Cell::new("30"),
        Cell::new("New York"),
    ]);
    table.add_row(vec![
        Cell::new("Bob"),
        Cell::new("25"),
        Cell::new("Los Angeles"),
    ]);
    table
}

#[test]
fn test_amiga_table_no_crash() {
    let mut table = create_test_table(TableStyle::Amiga);
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    assert!(!buffer.is_empty());
}

#[test]
fn test_add_column() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Test", Alignment::Left);
    assert_eq!(table.get_column_count(), 1);
    
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    let result = String::from_utf8(buffer.into_inner()).unwrap();
    assert!(result.contains("Test"));
}

#[cfg(feature = "csv")]
#[test]
fn test_csv_usage() {
    let mut table = Table::from_csv("examples/data.csv").unwrap();
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    assert!(!buffer.is_empty());
}

#[test]
fn test_add_row() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Test", Alignment::Left);
    table.add_row(vec![Cell::new("Value")]);
    assert_eq!(table.rows.len(), 1);
    assert_eq!(table.rows[0][0].content, "Value");
}

#[test]
#[should_panic(expected = "assertion `left == right` failed: Row length")]
fn test_add_row_mismatch() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Test", Alignment::Left);
    table.add_row(vec![Cell::new("Value1"), Cell::new("Value2")]);
}

#[test]
fn test_print_color() {
    let mut table = create_test_table(TableStyle::Grid);
    let mut buffer = termcolor::Buffer::ansi();
     table.ensure_dimensions();
    table.print_color(&mut buffer).unwrap();
    let result = String::from_utf8(buffer.into_inner()).unwrap();
    assert!(!result.is_empty());
}

#[test]
fn test_print_to_writer() {
    let mut table = create_test_table(TableStyle::Grid);
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    let result = String::from_utf8(buffer.into_inner()).unwrap();
    assert!(!result.is_empty());
}

#[test]
fn test_sort_by_column() {
    let mut table = create_test_table(TableStyle::Simple);
    table.sort_by_column(1, true);
    assert_eq!(table.rows[0][1].content, "25");
    assert_eq!(table.rows[1][1].content, "30");
}

#[test]
fn test_filter_rows() {
    let table = create_test_table(TableStyle::Simple);
    let filtered = table.filter_rows(|row| row[1].content == "30");  
    assert_eq!(filtered.rows.len(), 1);
    assert_eq!(filtered.rows[0][1].content, "30");
}

#[test]
fn test_cell_style_default() {
    let style = CellStyle::new();
    assert!(!style.bold);
    assert!(!style.italic);
    assert!(!style.underline);
    assert_eq!(style.padding, 1);
}

#[test]
fn test_cell_padding() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Test", Alignment::Left);

    let mut cell = Cell::new("Value");
    cell.style.padding = 2;
    table.add_row(vec![cell]);

    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();

    let result = String::from_utf8(buffer.into_inner()).unwrap();
    assert!(result.contains("Value"));
}

#[test]
fn test_number_formatting() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Number", Alignment::Right);
    
    let mut cell = Cell::new("1234.567");
    cell.style.decimal_places = Some(2);
    cell.style.thousand_separator = true;
    
    table.add_row(vec![cell]);
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    let result = String::from_utf8(buffer.into_inner()).unwrap();
    
    assert!(result.contains("1,234"));
    assert!(result.contains(".57"));
}

#[test]
fn test_group_by_column_with_subtotals() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Category", Alignment::Left);
    table.add_column("Amount", Alignment::Right);
    table.add_row(vec![Cell::new("A"), Cell::new("100")]);
    table.add_row(vec![Cell::new("A"), Cell::new("200")]);
    table.add_row(vec![Cell::new("B"), Cell::new("300")]);
    table.add_row(vec![Cell::new("B"), Cell::new("400")]);
    table.group_by_column_with_subtotals(0);
    let mut buffer = termcolor::Buffer::ansi();
    table.print_to_writer(&mut buffer).unwrap();
    let result = String::from_utf8(buffer.into_inner()).unwrap();
    assert!(result.contains("Subtotal"));
    assert!(result.contains("300"));
    assert!(result.contains("700"));
}

#[test]
fn test_sum_column() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Amount", Alignment::Right);
    table.add_row(vec![Cell::new("100")]);
    table.add_row(vec![Cell::new("200")]);
    table.add_row(vec![Cell::new("300")]);
    assert_eq!(table.sum_column(0), Some(600.0));
     
    let empty_table = Table::new(TableStyle::Simple);
    assert_eq!(empty_table.sum_column(0), None);
    
    let mut invalid_table = Table::new(TableStyle::Simple);
    invalid_table.add_column("Value", Alignment::Right);
    invalid_table.add_row(vec![Cell::new("abc")]);
    assert_eq!(invalid_table.sum_column(0), None);
}

#[test]
fn test_average_column() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Amount", Alignment::Right);
    table.add_row(vec![Cell::new("100")]);
    table.add_row(vec![Cell::new("200")]);
    table.add_row(vec![Cell::new("300")]);
    assert_eq!(table.average_column(0), Some(200.0));
     
    let empty_table = Table::new(TableStyle::Simple);
    assert_eq!(empty_table.average_column(0), None);
     
    let mut invalid_table = Table::new(TableStyle::Simple);
    invalid_table.add_column("Value", Alignment::Right);
    invalid_table.add_row(vec![Cell::new("abc")]);
    assert_eq!(invalid_table.average_column(0), None);
}

#[test]
fn test_min_column() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Amount", Alignment::Right);
    table.add_row(vec![Cell::new("100")]);
    table.add_row(vec![Cell::new("200")]);
    table.add_row(vec![Cell::new("300")]);
    assert_eq!(table.min_column(0), Some(100.0));
    
     
    let empty_table = Table::new(TableStyle::Simple);
    assert_eq!(empty_table.min_column(0), None);
    
     
    let mut invalid_table = Table::new(TableStyle::Simple);
    invalid_table.add_column("Value", Alignment::Right);
    invalid_table.add_row(vec![Cell::new("abc")]);
    assert_eq!(invalid_table.min_column(0), None);
}

#[test]
fn test_max_column() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Amount", Alignment::Right);
    table.add_row(vec![Cell::new("100")]);
    table.add_row(vec![Cell::new("200")]);
    table.add_row(vec![Cell::new("300")]);
    assert_eq!(table.max_column(0), Some(300.0));
    
     
    let empty_table = Table::new(TableStyle::Simple);
    assert_eq!(empty_table.max_column(0), None);
    
     
    let mut invalid_table = Table::new(TableStyle::Simple);
    invalid_table.add_column("Value", Alignment::Right);
    invalid_table.add_row(vec![Cell::new("abc")]);
    assert_eq!(invalid_table.max_column(0), None);
}

#[test]
fn test_cell_background_color() {
    let mut table = Table::new(TableStyle::Simple);
    table.add_column("Name", Alignment::Left);
    let mut cell_with_bg = Cell::new("Alice");
    cell_with_bg.style.background_color = Some(Color::Red);
    table.add_row(vec![cell_with_bg]);

    let cell_no_bg = Cell::new("Bob");
    table.add_row(vec![cell_no_bg]);

    let mut buffer = termcolor::Buffer::ansi();
    table.ensure_dimensions(); 
    table.print_color(&mut buffer).unwrap();

    let output = String::from_utf8(buffer.into_inner()).unwrap();
    
    assert!(output.contains("\u{1b}[41m Alice \u{1b}[0m"));
    assert!(output.contains("Bob"));
    assert!(!output.contains("\u{1b}[41mBob"));
}

#[test]
fn test_print_color_amiga_with_background() {
    let mut table = Table::new(TableStyle::Amiga);
    table.add_column("Name", Alignment::Left);
    let mut cell_with_bg = Cell::new("AmigaUser");
    cell_with_bg.style.background_color = Some(Color::Yellow);
    table.add_row(vec![cell_with_bg]);

    let mut buffer = termcolor::Buffer::ansi();
    table.ensure_dimensions();
    table.print_color(&mut buffer).unwrap();
    let output = String::from_utf8(buffer.into_inner()).unwrap();

    assert!(output.contains("\u{1b}[43mAmigaUser"));
}