use super::common::get_vertex_ids_in_order;
use crate::engine::{Engine, EvalConfig};
use crate::test_workbook::TestWorkbook;
use formualizer_common::{ExcelError, LiteralValue};
use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType};
fn create_simple_engine() -> Engine<TestWorkbook> {
let wb = TestWorkbook::new();
let config = EvalConfig::default();
Engine::new(wb, config)
}
fn ref_ast(row: u32, col: u32) -> ASTNode {
ASTNode {
node_type: ASTNodeType::Reference {
original: format!("R{row}C{col}"),
reference: ReferenceType::cell(None, row, col),
},
source_token: None,
contains_volatile: false,
}
}
fn op_ast(left: ASTNode, right: ASTNode, op: &str) -> ASTNode {
ASTNode {
node_type: ASTNodeType::BinaryOp {
op: op.to_string(),
left: Box::new(left),
right: Box::new(right),
},
source_token: None,
contains_volatile: false,
}
}
#[test]
fn test_vertex_evaluation_scalar() {
let mut engine = create_simple_engine();
let ast = op_ast(
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(1)), None),
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(2)), None),
"+",
);
engine
.set_cell_formula("Sheet1", 1, 1, ast.clone())
.unwrap();
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a1_id = vertex_ids[0];
let result = engine.evaluate_vertex(a1_id).unwrap();
assert_eq!(result, LiteralValue::Number(3.0));
assert_eq!(
engine.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(3.0))
);
}
#[test]
fn test_evaluation_of_empty_placeholders() {
let mut engine = create_simple_engine();
let ast = ref_ast(1, 2);
engine.set_cell_formula("Sheet1", 1, 1, ast).unwrap();
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a1_id = vertex_ids[0];
let result = engine.evaluate_vertex(a1_id).unwrap();
assert_eq!(result, LiteralValue::Number(0.0));
}
#[test]
fn test_evaluation_error_handling() {
let mut engine = create_simple_engine();
let ast = op_ast(
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(1)), None),
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(0)), None),
"/",
);
engine.set_cell_formula("Sheet1", 1, 1, ast).unwrap();
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a1_id = vertex_ids[0];
let result = engine.evaluate_vertex(a1_id).unwrap();
assert_eq!(result, LiteralValue::Error(ExcelError::new_div()));
}
#[test]
fn test_error_propagation_through_dependencies() {
let mut engine = create_simple_engine();
let div_zero_ast = op_ast(
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(1)), None),
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(0)), None),
"/",
);
engine
.set_cell_formula("Sheet1", 1, 1, div_zero_ast)
.unwrap();
let ref_a1_ast = ref_ast(1, 1);
engine.set_cell_formula("Sheet1", 2, 1, ref_a1_ast).unwrap();
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a1_id = vertex_ids[0];
let a1_result = engine.evaluate_vertex(a1_id).unwrap();
assert!(matches!(a1_result, LiteralValue::Error(_)));
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a2_id = vertex_ids[1];
let a2_result = engine.evaluate_vertex(a2_id).unwrap();
assert_eq!(a2_result, a1_result);
assert_eq!(a2_result, LiteralValue::Error(ExcelError::new_div()));
}
#[test]
fn test_sequential_evaluation_of_dependency_chain() {
let mut engine = create_simple_engine();
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
let a2_ast = op_ast(
ref_ast(1, 1),
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(5)), None),
"+",
);
engine.set_cell_formula("Sheet1", 2, 1, a2_ast).unwrap();
let a3_ast = op_ast(
ref_ast(2, 1),
ASTNode::new(ASTNodeType::Literal(LiteralValue::Int(2)), None),
"*",
);
engine.set_cell_formula("Sheet1", 3, 1, a3_ast).unwrap();
let vertex_ids = get_vertex_ids_in_order(&engine.graph);
let a2_id = vertex_ids[1];
let a3_id = vertex_ids[2];
let a2_result = engine.evaluate_vertex(a2_id).unwrap();
assert_eq!(a2_result, LiteralValue::Number(15.0));
let a3_result = engine.evaluate_vertex(a3_id).unwrap();
assert_eq!(a3_result, LiteralValue::Number(30.0));
assert_eq!(
engine.get_cell_value("Sheet1", 3, 1),
Some(LiteralValue::Number(30.0))
);
}
#[test]
#[ignore] fn test_vertex_evaluation_array_stub() {
}