use crate::engine::tests::common::{create_binary_op_ast, create_cell_ref_ast};
use crate::engine::{Engine, EvalConfig};
use crate::test_workbook::TestWorkbook;
use formualizer_common::LiteralValue;
use formualizer_parse::parser::{ASTNode, ASTNodeType};
#[test]
fn test_evaluate_until_single_clean_target() {
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
let ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(1)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 2, ast).unwrap();
engine.evaluate_all().unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 2)]).unwrap();
assert_eq!(result.computed_vertices, 0);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(11.0))
);
}
#[test]
fn test_evaluate_until_single_dirty_target() {
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
let ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(1)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 2, ast).unwrap();
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(20))
.unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 2)]).unwrap();
assert_eq!(result.computed_vertices, 1);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(21.0))
);
}
#[test]
fn test_evaluate_until_dependency_chain() {
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
let b1_ast = create_cell_ref_ast(None, 1, 1);
engine.set_cell_formula("Sheet1", 1, 2, b1_ast).unwrap();
let c1_ast = create_cell_ref_ast(None, 1, 2);
engine.set_cell_formula("Sheet1", 1, 3, c1_ast).unwrap();
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(30))
.unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 3)]).unwrap();
assert_eq!(result.computed_vertices, 2);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 1),
Some(LiteralValue::Number(30.0))
);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 2),
Some(LiteralValue::Number(30.0))
);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 3),
Some(LiteralValue::Number(30.0))
);
}
#[test]
fn test_evaluate_until_multiple_targets() {
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(10))
.unwrap();
let b1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(1)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 2, b1_ast).unwrap();
let c1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(2)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 3, c1_ast).unwrap();
let d1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 2),
create_cell_ref_ast(None, 1, 3),
"+",
);
engine.set_cell_formula("Sheet1", 1, 4, d1_ast).unwrap();
let e1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(5)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 5, e1_ast).unwrap();
engine
.set_cell_value("Sheet1", 1, 1, LiteralValue::Int(100))
.unwrap();
let result = engine
.evaluate_until(&[("Sheet1", 1, 3), ("Sheet1", 1, 5)])
.unwrap();
assert_eq!(result.computed_vertices, 2);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 3),
Some(LiteralValue::Number(102.0))
); assert_eq!(
engine.get_cell_value("Sheet1", 1, 5),
Some(LiteralValue::Number(105.0))
);
let result2 = engine.evaluate_until(&[("Sheet1", 1, 4)]).unwrap();
assert_eq!(result2.computed_vertices, 2);
assert_eq!(
engine.get_cell_value("Sheet1", 1, 4),
Some(LiteralValue::Number(203.0))
); }
#[test]
fn test_evaluate_until_volatile_precedent() {
crate::builtins::random::register_builtins();
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
let rand_ast = ASTNode {
node_type: ASTNodeType::Function {
name: "RAND".to_string(),
args: vec![],
},
source_token: None,
contains_volatile: true,
};
engine.set_cell_formula("Sheet1", 1, 1, rand_ast).unwrap();
let b1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(1)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 2, b1_ast).unwrap();
engine.evaluate_all().unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 2)]).unwrap();
assert_eq!(result.computed_vertices, 2); }
#[test]
fn test_evaluate_until_target_is_volatile() {
crate::builtins::random::register_builtins();
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
let rand_ast = ASTNode {
node_type: ASTNodeType::Function {
name: "RAND".to_string(),
args: vec![],
},
source_token: None,
contains_volatile: true,
};
engine.set_cell_formula("Sheet1", 1, 1, rand_ast).unwrap();
engine.evaluate_all().unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 1)]).unwrap();
assert_eq!(result.computed_vertices, 1); }
#[test]
fn test_evaluate_until_precedents_include_a_cycle() {
let wb =
TestWorkbook::new().with_function(std::sync::Arc::new(crate::builtins::random::RandFn));
let mut engine = Engine::new(wb, EvalConfig::default());
let a1_ast = create_cell_ref_ast(None, 1, 2); engine.set_cell_formula("Sheet1", 1, 1, a1_ast).unwrap();
let b1_ast = create_cell_ref_ast(None, 1, 1); engine.set_cell_formula("Sheet1", 1, 2, b1_ast).unwrap();
let c1_ast = create_binary_op_ast(
create_cell_ref_ast(None, 1, 1),
ASTNode {
node_type: ASTNodeType::Literal(LiteralValue::Int(1)),
source_token: None,
contains_volatile: false,
},
"+",
);
engine.set_cell_formula("Sheet1", 1, 3, c1_ast).unwrap();
let result = engine.evaluate_until(&[("Sheet1", 1, 3)]).unwrap();
assert_eq!(result.cycle_errors, 1); assert_eq!(result.computed_vertices, 1);
let a1_value = engine.get_cell_value("Sheet1", 1, 1);
assert!(matches!(a1_value, Some(LiteralValue::Error(_))));
let b1_value = engine.get_cell_value("Sheet1", 1, 2);
assert!(matches!(b1_value, Some(LiteralValue::Error(_))));
let c1_value = engine.get_cell_value("Sheet1", 1, 3);
assert!(c1_value.is_some());
}