use crate::engine::{EvalConfig, eval::Engine};
use crate::test_workbook::TestWorkbook;
use formualizer_parse::LiteralValue;
use formualizer_parse::parser::parse;
#[test]
fn overlay_budget_keeps_computed_overlay_bounded_across_recalcs() {
let wb = TestWorkbook::new();
let cfg = EvalConfig {
max_overlay_memory_bytes: Some(2048),
..EvalConfig::default()
};
let mut engine = Engine::new(wb, cfg);
for r in 1..=2000 {
engine
.set_cell_formula("Sheet1", r, 1, parse("=1").unwrap())
.unwrap();
}
engine
.set_cell_formula("Sheet1", 1, 2, parse("=SUM(A1:A2000)").unwrap())
.unwrap();
for _ in 0..5 {
let _ = engine.evaluate_all().unwrap();
assert!(engine.overlay_memory_usage() <= 2048);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(2000.0))
);
}
}
#[test]
fn bulk_spill_clear_dirties_dependents_without_delta_scan_fallback() {
std::thread::Builder::new()
.name("hardening_503_bulk_spill_clear".to_string())
.stack_size(32 * 1024 * 1024)
.spawn(|| {
let wb = TestWorkbook::new();
let mut engine = Engine::new(wb, EvalConfig::default());
engine
.set_cell_formula("Sheet1", 1, 1, parse("=SEQUENCE(5000,1)").unwrap())
.unwrap();
engine
.set_cell_formula("Sheet1", 1, 2, parse("=SUM(A1:A5000)").unwrap())
.unwrap();
let _ = engine.evaluate_all().unwrap();
{
let asheet = engine.sheet_store().sheet("Sheet1").expect("arrow sheet");
let col0 = &asheet.columns[0];
let at_row = |row0: usize| -> Option<crate::arrow_store::OverlayValue> {
let (ch_idx, in_off) = asheet.chunk_of_row(row0)?;
let ch = col0.chunk(ch_idx)?;
ch.computed_overlay.get(in_off)
};
match at_row(0) {
Some(crate::arrow_store::OverlayValue::Number(n)) => {
assert!((n - 1.0).abs() < 1e-6)
}
other => panic!("expected computed overlay number at row0=0, got {other:?}"),
}
match at_row(9) {
Some(crate::arrow_store::OverlayValue::Number(n)) => {
assert!((n - 10.0).abs() < 1e-6)
}
other => panic!("expected computed overlay number at row0=9, got {other:?}"),
}
match at_row(4999) {
Some(crate::arrow_store::OverlayValue::Number(n)) => {
assert!((n - 5000.0).abs() < 1e-6)
}
other => {
panic!("expected computed overlay number at row0=4999, got {other:?}")
}
}
let av = asheet.range_view(0, 0, 4999, 0);
let mut tot = 0.0;
for res in av.numbers_slices() {
let (_, _, num_cols) = res.unwrap();
for col in num_cols {
tot += arrow::compute::kernels::aggregate::sum(col.as_ref()).unwrap_or(0.0);
}
}
assert!((tot - 12_502_500.0).abs() < 1e-6, "arrow sum saw {tot}");
}
let _ = engine.evaluate_until(&[("Sheet1", 1, 2)]).unwrap();
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(12_502_500.0))
);
engine.graph.reset_instr();
engine
.set_cell_formula("Sheet1", 1, 1, parse("=1").unwrap())
.unwrap();
let _ = engine.evaluate_all().unwrap();
let _ = engine.evaluate_until(&[("Sheet1", 1, 2)]).unwrap();
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(1.0))
);
let instr = engine.graph.instr();
assert_eq!(instr.dependents_scan_fallback_calls, 0);
})
.unwrap()
.join()
.unwrap();
}