use crate::engine::{Engine, EvalConfig};
use crate::reference::{CellRef, Coord};
use crate::test_workbook::TestWorkbook;
use formualizer_common::LiteralValue;
use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType, parse};
fn make_engine() -> Engine<TestWorkbook> {
let wb = TestWorkbook::new();
let cfg = EvalConfig::default();
Engine::new(wb, cfg)
}
fn lit(n: i64) -> ASTNode {
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(n)), None)
}
fn ref_cell(row: u32, col: u32) -> ASTNode {
ASTNode::new(
ASTNodeType::Reference {
original: format!("R{row}C{col}"),
reference: ReferenceType::cell(None, row, col),
},
None,
)
}
#[test]
fn dependents_redirty_on_formula_edit_direct_chain() {
let mut engine = make_engine();
engine.set_cell_formula("Sheet1", 1, 1, lit(10)).unwrap();
engine
.set_cell_formula("Sheet1", 1, 2, ref_cell(1, 1))
.unwrap();
engine
.set_cell_formula("Sheet1", 1, 3, ref_cell(1, 2))
.unwrap();
engine.evaluate_all().unwrap();
engine.set_cell_formula("Sheet1", 1, 1, lit(20)).unwrap();
let sheet_id = engine.graph.sheet_id("Sheet1").unwrap();
let b1 = engine
.graph
.get_vertex_for_cell(&CellRef::new(sheet_id, Coord::from_excel(1, 2, true, true)))
.unwrap();
let c1 = engine
.graph
.get_vertex_for_cell(&CellRef::new(sheet_id, Coord::from_excel(1, 3, true, true)))
.unwrap();
let scheduled = engine.graph.get_evaluation_vertices();
assert!(
scheduled.contains(&b1),
"B1 should be scheduled after A1 edit"
);
assert!(
scheduled.contains(&c1),
"C1 should be scheduled after A1 edit"
);
let eval = engine.evaluate_all().unwrap();
assert!(
eval.computed_vertices >= 2,
"expected >=2 recomputations, got {}",
eval.computed_vertices
);
}
#[test]
fn dependents_redirty_when_value_becomes_formula() {
let mut engine = make_engine();
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
engine
.set_cell_formula("Sheet1", 1, 2, ref_cell(1, 1))
.unwrap();
engine
.set_cell_formula("Sheet1", 1, 3, ref_cell(1, 2))
.unwrap();
engine.evaluate_all().unwrap();
engine.set_cell_formula("Sheet1", 1, 1, lit(20)).unwrap();
let sid = engine.graph.sheet_id("Sheet1").unwrap();
let b1 = engine
.graph
.get_vertex_for_cell(&CellRef::new(sid, Coord::from_excel(1, 2, true, true)))
.unwrap();
let c1 = engine
.graph
.get_vertex_for_cell(&CellRef::new(sid, Coord::from_excel(1, 3, true, true)))
.unwrap();
let scheduled = engine.graph.get_evaluation_vertices();
assert!(scheduled.contains(&b1));
assert!(scheduled.contains(&c1));
let eval = engine.evaluate_all().unwrap();
assert!(eval.computed_vertices >= 2);
}
#[test]
fn whole_column_dependent_redirty_on_formula_edit() {
let mut engine = make_engine();
engine.set_cell_formula("Sheet1", 2, 4, lit(1)).unwrap();
engine.set_cell_formula("Sheet1", 3, 4, lit(2)).unwrap();
engine.set_cell_formula("Sheet1", 4, 4, lit(3)).unwrap();
engine.set_cell_formula("Sheet1", 5, 4, lit(4)).unwrap();
engine
.set_cell_formula("Sheet1", 1, 19, parse("=SUM(D:D)").unwrap())
.unwrap();
engine.evaluate_all().unwrap();
engine.set_cell_formula("Sheet1", 5, 4, lit(40)).unwrap();
let sheet_id = engine.graph.sheet_id("Sheet1").unwrap();
let s1 = engine
.graph
.get_vertex_for_cell(&CellRef::new(
sheet_id,
Coord::from_excel(1, 19, true, true),
))
.unwrap();
let scheduled = engine.graph.get_evaluation_vertices();
assert!(
scheduled.contains(&s1),
"S1 should be scheduled after D5 edit"
);
}
#[test]
fn cross_sheet_whole_column_dependent_redirty_on_formula_edit() {
let mut engine = make_engine();
engine.graph.add_sheet("Sheet2").unwrap();
engine.set_cell_formula("Sheet1", 2, 4, lit(5)).unwrap();
engine.set_cell_formula("Sheet1", 5, 4, lit(7)).unwrap();
engine
.set_cell_formula("Sheet2", 1, 1, parse("=SUM(Sheet1!D:D)").unwrap())
.unwrap();
engine.evaluate_all().unwrap();
engine.set_cell_formula("Sheet1", 5, 4, lit(70)).unwrap();
let s2_id = engine.graph.sheet_id("Sheet2").unwrap();
let a1_sheet2 = engine
.graph
.get_vertex_for_cell(&CellRef::new(s2_id, Coord::from_excel(1, 1, true, true)))
.unwrap();
let scheduled = engine.graph.get_evaluation_vertices();
assert!(
scheduled.contains(&a1_sheet2),
"Sheet2!A1 should be scheduled after Sheet1!D5 edit"
);
}