#[cfg(any(feature = "umya", feature = "calamine"))]
use formualizer_workbook::SpreadsheetReader;
use formualizer_workbook::{
CellData, LoadStrategy, SpreadsheetWriter, Workbook, WorkbookConfig, WorkbookLoadLimits,
};
#[cfg(feature = "json")]
use formualizer_workbook::JsonAdapter;
#[cfg(feature = "umya")]
use formualizer_workbook::UmyaAdapter;
#[cfg(all(feature = "calamine", feature = "umya"))]
use formualizer_workbook::CalamineAdapter;
#[cfg(feature = "umya")]
fn sparse_xlsx_bytes() -> Vec<u8> {
let mut book = umya_spreadsheet::new_file();
let sheet = book
.get_sheet_by_name_mut("Sheet1")
.expect("default sheet exists");
sheet.get_cell_mut((1, 1_000)).set_value_number(1.0);
let mut buf = Vec::new();
umya_spreadsheet::writer::xlsx::write_writer(&book, &mut buf).expect("write xlsx bytes");
buf
}
fn sparse_limits() -> WorkbookLoadLimits {
WorkbookLoadLimits {
max_sheet_rows: 10_000,
max_sheet_cols: 100,
max_sheet_logical_cells: u64::MAX,
sparse_sheet_cell_threshold: 100,
max_sparse_cell_ratio: 10,
}
}
#[cfg(feature = "json")]
#[test]
fn json_loader_rejects_dense_sheet_over_logical_budget() {
let mut adapter = JsonAdapter::new();
for row in 1..=11 {
for col in 1..=10 {
adapter
.write_cell("S", row, col, CellData::from_value(1.0))
.expect("write dense cell");
}
}
let mut cfg = WorkbookConfig::ephemeral();
cfg.ingest_limits = WorkbookLoadLimits {
max_sheet_rows: 10_000,
max_sheet_cols: 10_000,
max_sheet_logical_cells: 100,
sparse_sheet_cell_threshold: u64::MAX,
max_sparse_cell_ratio: u64::MAX,
};
let err = match Workbook::from_reader(adapter, LoadStrategy::EagerAll, cfg) {
Ok(_) => panic!("dense sheet should hit logical budget"),
Err(err) => err,
};
let msg = err.to_string();
assert!(
msg.contains("logical-cell budget"),
"unexpected error: {msg}"
);
}
#[cfg(feature = "json")]
#[test]
fn json_loader_rejects_sparse_sheet_over_guardrail() {
let mut adapter = JsonAdapter::new();
adapter
.write_cell("S", 1_000, 1, CellData::from_value(1.0))
.expect("write sparse cell");
let cfg = WorkbookConfig::ephemeral().with_ingest_limits(sparse_limits());
let err = match Workbook::from_reader(adapter, LoadStrategy::EagerAll, cfg) {
Ok(_) => panic!("sparse sheet should hit guardrail"),
Err(err) => err,
};
let msg = err.to_string();
assert!(
msg.contains("sparse-sheet guardrail"),
"unexpected error: {msg}"
);
}
#[cfg(feature = "umya")]
#[test]
fn umya_loader_rejects_sparse_sheet_over_guardrail() {
let adapter = UmyaAdapter::open_bytes(sparse_xlsx_bytes()).expect("open sparse xlsx bytes");
let cfg = WorkbookConfig::ephemeral().with_ingest_limits(sparse_limits());
let err = match Workbook::from_reader(adapter, LoadStrategy::EagerAll, cfg) {
Ok(_) => panic!("sparse xlsx should hit guardrail"),
Err(err) => err,
};
let msg = err.to_string();
assert!(
msg.contains("sparse-sheet guardrail"),
"unexpected error: {msg}"
);
}
#[cfg(all(feature = "calamine", feature = "umya"))]
#[test]
fn calamine_loader_rejects_sparse_sheet_over_guardrail() {
use std::io::Write;
let bytes = sparse_xlsx_bytes();
let mut tmp = tempfile::NamedTempFile::new().expect("create temp xlsx");
tmp.write_all(&bytes).expect("persist xlsx");
let adapter = CalamineAdapter::open_path(tmp.path()).expect("open sparse xlsx path");
let cfg = WorkbookConfig::ephemeral().with_ingest_limits(sparse_limits());
let err = match Workbook::from_reader(adapter, LoadStrategy::EagerAll, cfg) {
Ok(_) => panic!("sparse xlsx should hit guardrail"),
Err(err) => err,
};
let msg = err.to_string();
assert!(
msg.contains("sparse-sheet guardrail"),
"unexpected error: {msg}"
);
}