use assert_cmd::Command;
use sheeter_engine::{convert_workbook, Format};
use std::fs;
use tempfile::tempdir;
fn write_xlsx(path: &std::path::Path, sheets: &[(&str, Vec<Vec<&str>>)]) {
use rust_xlsxwriter::Workbook;
let mut wb = Workbook::new();
for (name, rows) in sheets {
let ws = wb.add_worksheet();
ws.set_name(*name).unwrap();
for (r, row) in rows.iter().enumerate() {
for (c, cell) in row.iter().enumerate() {
ws.write_string(r as u32, c as u16, *cell).unwrap();
}
}
}
wb.save(path).unwrap();
}
#[test]
fn xlsx_single_sheet_to_csv() {
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(&xlsx, &[("Data", vec![vec!["a", "b"], vec!["1", "2"]])]);
let out = dir.path().join("out.csv");
Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"csv",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
let csv = fs::read_to_string(out).unwrap();
assert_eq!(csv, "a,b\n1,2\n");
}
#[test]
fn xlsx_multi_sheet_to_csv_n_outputs() {
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(
&xlsx,
&[
("Alpha", vec![vec!["x"], vec!["1"]]),
("Beta", vec![vec!["y"], vec!["2"]]),
],
);
let out = dir.path().join("out.csv");
Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"csv",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
assert_eq!(
fs::read_to_string(dir.path().join("out.Alpha.csv")).unwrap(),
"x\n1\n"
);
assert_eq!(
fs::read_to_string(dir.path().join("out.Beta.csv")).unwrap(),
"y\n2\n"
);
}
#[test]
fn xlsx_multi_sheet_to_json_single_file() {
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(
&xlsx,
&[
("A", vec![vec!["v"], vec!["1"]]),
("B", vec![vec!["v"], vec!["2"]]),
],
);
let out = dir.path().join("out.json");
Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"json",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
let json = fs::read_to_string(out).unwrap();
assert!(json.contains("\"A\""));
assert!(json.contains("\"B\""));
}
#[test]
fn xlsx_sheet_flag_restricts_output() {
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(
&xlsx,
&[
("Alpha", vec![vec!["x"], vec!["1"]]),
("Beta", vec![vec!["y"], vec!["2"]]),
],
);
let out = dir.path().join("out.csv");
Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"csv",
"--sheet",
"Beta",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
assert_eq!(fs::read_to_string(out).unwrap(), "y\n2\n");
}
#[test]
fn xlsx_roundtrip_preserves_sheet_names() {
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(
&xlsx,
&[
("First", vec![vec!["a"], vec!["1"]]),
("Second", vec![vec!["b"], vec!["2"]]),
],
);
let out = dir.path().join("out.xlsx");
Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"xlsx",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
let bytes = fs::read(out).unwrap();
let sheets = convert_workbook(Format::Xlsx, Format::Json, &bytes).unwrap();
assert_eq!(sheets.len(), 1);
let json = String::from_utf8(sheets[0].1.clone()).unwrap();
assert!(json.contains("\"First\""));
assert!(json.contains("\"Second\""));
}
#[test]
fn xlsx_sheet_names_with_spaces_preserved() {
use tempfile::tempdir;
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
write_xlsx(
&xlsx,
&[
("Vendas 2024", vec![vec!["v"], vec!["1"]]),
("Vendas 2025", vec![vec!["v"], vec!["2"]]),
],
);
let out = dir.path().join("out.csv");
assert_cmd::Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"csv",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
assert!(dir.path().join("out.Vendas 2024.csv").exists());
assert!(dir.path().join("out.Vendas 2025.csv").exists());
}
#[test]
fn xlsx_integer_floats_become_ints_in_json() {
use rust_xlsxwriter::Workbook;
let dir = tempdir().unwrap();
let xlsx = dir.path().join("in.xlsx");
let mut wb = Workbook::new();
let ws = wb.add_worksheet();
ws.write_string(0, 0, "id").unwrap();
ws.write_string(0, 1, "weight").unwrap();
ws.write_number(1, 0, 1.0).unwrap();
ws.write_number(1, 1, 6.9).unwrap();
ws.write_number(2, 0, 2.0).unwrap();
ws.write_number(2, 1, 13.5).unwrap();
wb.save(&xlsx).unwrap();
let out = dir.path().join("out.json");
assert_cmd::Command::cargo_bin("sheeter")
.unwrap()
.args([
"convert",
"--from",
"xlsx",
"--to",
"json",
xlsx.to_str().unwrap(),
out.to_str().unwrap(),
])
.assert()
.success();
let json = fs::read_to_string(out).unwrap();
assert!(
json.contains(r#"{"id":1,"weight":6.9}"#),
"int coercion: {json}"
);
assert!(
json.contains(r#"{"id":2,"weight":13.5}"#),
"int coercion: {json}"
);
}