formualizer-eval 0.6.0

High-performance Arrow-backed Excel formula engine with dependency graph and incremental recalculation
Documentation
use chrono::Duration;

use crate::engine::{Engine, EvalConfig};
use crate::test_workbook::TestWorkbook;
use formualizer_common::LiteralValue;
use formualizer_parse::parser::parse;

fn run(formula: &str, a1: LiteralValue) -> Option<LiteralValue> {
    let mut engine = Engine::new(TestWorkbook::new(), EvalConfig::default());
    engine.set_cell_value("Sheet1", 1, 1, a1).unwrap();
    engine
        .set_cell_formula("Sheet1", 1, 2, parse(formula).unwrap())
        .unwrap();
    engine.evaluate_all().unwrap();
    engine.get_cell_value("Sheet1", 1, 2)
}

fn dur_2d_14h_30m_45s() -> LiteralValue {
    LiteralValue::Duration(Duration::seconds(2 * 86_400 + 14 * 3600 + 30 * 60 + 45))
}

fn assert_int_like(v: Option<LiteralValue>, expected: i64) {
    match v {
        Some(LiteralValue::Int(n)) => assert_eq!(n, expected),
        Some(LiteralValue::Number(n)) => assert!(
            (n - expected as f64).abs() < 1e-9,
            "expected ~{expected}, got {n}",
        ),
        other => panic!("expected integer-like {expected}, got {other:?}"),
    }
}

#[test]
fn hour_on_duration_cell_returns_fraction_hours() {
    assert_int_like(run("=HOUR(A1)", dur_2d_14h_30m_45s()), 14);
}

#[test]
fn minute_on_duration_cell_returns_fraction_minutes() {
    assert_int_like(run("=MINUTE(A1)", dur_2d_14h_30m_45s()), 30);
}

#[test]
fn second_on_duration_cell_returns_fraction_seconds() {
    assert_int_like(run("=SECOND(A1)", dur_2d_14h_30m_45s()), 45);
}

#[test]
fn weekday_on_duration_cell_does_not_value_error() {
    let r = run(
        "=WEEKDAY(A1)",
        LiteralValue::Duration(Duration::days(45657)),
    );
    match r {
        Some(LiteralValue::Int(n)) => assert!((1..=7).contains(&n), "weekday out of range: {n}"),
        Some(LiteralValue::Number(n)) => {
            assert!((1.0..=7.0).contains(&n), "weekday out of range: {n}")
        }
        other => panic!("expected weekday integer, got {other:?}"),
    }
}