xl-cli-tools

CLI tools for viewing and editing Excel files
Log | Files | Refs | README | LICENSE

commit 110b1b5dab274c003e1636da34959c81c76041cc
parent 6eef68fc23f8d6ad8cdf5e40e5542b8543562d7d
Author: Erik Loualiche <[email protected]>
Date:   Fri, 13 Mar 2026 16:08:19 -0500

test: add edge case tests — large file gate, empty sheets, errors

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

Diffstat:
Mxlcat/tests/test_integration.rs | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 237 insertions(+), 0 deletions(-)

diff --git a/xlcat/tests/test_integration.rs b/xlcat/tests/test_integration.rs @@ -198,3 +198,240 @@ fn test_all_without_sheet_on_multi() { .failure() .stderr(predicate::str::contains("Multiple sheets")); } + +#[test] +fn test_large_file_gate_triggers() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + // Set max-size very low so gate triggers + xlcat() + .arg(path.to_str().unwrap()) + .arg("--max-size") + .arg("1K") + .assert() + .success() + .stdout(predicate::str::contains("Large file")); +} + +#[test] +fn test_large_file_gate_overridden_by_head() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + let output = xlcat() + .arg(path.to_str().unwrap()) + .arg("--max-size") + .arg("1K") + .arg("--head") + .arg("5") + .assert() + .success(); + + let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); + assert!(!stdout.contains("Large file")); +} + +#[test] +fn test_large_file_gate_overridden_by_all() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + let output = xlcat() + .arg(path.to_str().unwrap()) + .arg("--max-size") + .arg("1K") + .arg("--all") + .assert() + .success(); + + let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); + assert!(!stdout.contains("Large file")); +} + +#[test] +fn test_empty_data_headers_only() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("empty_data.xlsx"); + common::create_empty_data(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .assert() + .success() + .stdout(predicate::str::contains("no data rows")); +} + +#[test] +fn test_head_and_tail_together() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .arg("--head") + .arg("3") + .arg("--tail") + .arg("2") + .assert() + .success() + .stdout(predicate::str::contains("omitted")); +} + +#[test] +fn test_tail_flag_alone() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + let output = xlcat() + .arg(path.to_str().unwrap()) + .arg("--tail") + .arg("3") + .assert() + .success(); + + let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); + assert!(!stdout.contains("omitted")); + // Should contain the last rows (ids near 80) + assert!(stdout.contains("80")); +} + +#[test] +fn test_csv_respects_head() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("many.xlsx"); + common::create_many_rows(&path); + + let output = xlcat() + .arg(path.to_str().unwrap()) + .arg("--csv") + .arg("--head") + .arg("3") + .assert() + .success(); + + let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); + // Header + 3 data rows = 4 non-empty lines + let lines: Vec<&str> = stdout.trim().lines().collect(); + assert_eq!(lines.len(), 4, "Expected header + 3 data rows, got: {}", stdout); +} + +#[test] +fn test_head_tail_overlap_shows_all() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("simple.xlsx"); + common::create_simple(&path); + + // 5 rows, head 3 + tail 3 = 6 > 5, so show all without duplication + let output = xlcat() + .arg(path.to_str().unwrap()) + .arg("--head") + .arg("3") + .arg("--tail") + .arg("3") + .assert() + .success(); + + let stdout = String::from_utf8(output.get_output().stdout.clone()).unwrap(); + assert!(!stdout.contains("omitted")); + assert!(stdout.contains("Alice")); + assert!(stdout.contains("Eve")); +} + +#[test] +fn test_wrong_extension() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("data.csv"); + std::fs::write(&path, "a,b\n1,2\n").unwrap(); + + xlcat() + .arg(path.to_str().unwrap()) + .assert() + .failure() + .stderr(predicate::str::contains("Expected .xls or .xlsx")); +} + +#[test] +fn test_sheet_not_found() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("simple.xlsx"); + common::create_simple(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .arg("--sheet") + .arg("Nonexistent") + .assert() + .failure() + .stderr(predicate::str::contains("not found")); +} + +#[test] +fn test_exit_code_success() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("simple.xlsx"); + common::create_simple(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .assert() + .code(0); +} + +#[test] +fn test_exit_code_runtime_error() { + xlcat() + .arg("/nonexistent.xlsx") + .assert() + .code(1); +} + +#[test] +fn test_exit_code_invalid_args() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("simple.xlsx"); + common::create_simple(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .arg("--schema") + .arg("--describe") + .assert() + .code(2); +} + +#[test] +fn test_describe_multi_sheet_no_sheet_flag() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("multi.xlsx"); + common::create_multi_sheet(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .arg("--describe") + .assert() + .success() + .stdout(predicate::str::contains("## Sheet: Revenue")) + .stdout(predicate::str::contains("## Sheet: Expenses")) + .stdout(predicate::str::contains("count")) + .stdout(predicate::str::contains("mean")); +} + +#[test] +fn test_csv_multi_sheet_without_sheet_is_error() { + let dir = TempDir::new().unwrap(); + let path = dir.path().join("multi.xlsx"); + common::create_multi_sheet(&path); + + xlcat() + .arg(path.to_str().unwrap()) + .arg("--csv") + .assert() + .failure() + .stderr(predicate::str::contains("Multiple sheets")); +}