tests.rs raw

use guiduck_component_core::expr::Expr;
use guiduck_core::component::DynSignal;
use guiduck_core::signals::Signal;

use super::*;

fn expr(source: &str) -> Expr {
    let doc = guiduck_component_core::sexpr::read(source).expect("reads");
    guiduck_component_core::expr::from_sexpr(&doc.values[0], source).expect("valid")
}

fn cx_with(count: i32, busy: bool) -> DynCx {
    let mut cx = DynCx::default();
    cx.signals
        .insert("count".into(), DynSignal::I32(Signal::new(count)));
    cx.signals
        .insert("busy".into(), DynSignal::Bool(Signal::new(busy)));
    cx.props
        .insert("step".into(), DynSignal::I64(Signal::new(3)));
    cx.props
        .insert("label".into(), DynSignal::Str(Signal::new("Items".into())));
    cx
}

#[test]
fn arithmetic_and_comparison() {
    let cx = cx_with(7, false);
    assert_eq!(eval(&expr("(+ count step)"), &cx), Value::I64(10));
    assert_eq!(eval(&expr("(* count 2)"), &cx), Value::I64(14));
    assert_eq!(eval(&expr("(> count 5)"), &cx), Value::Bool(true));
    assert_eq!(eval(&expr("(= count 7)"), &cx), Value::Bool(true));
    assert_eq!(
        eval(&expr("(/ count 0)"), &cx),
        Value::I64(0),
        "no div-by-zero panic"
    );
    assert_eq!(eval(&expr("(+ 1.5 count)"), &cx), Value::F64(8.5));
}

#[test]
fn boolean_logic_short_circuits() {
    let cx = cx_with(1, true);
    assert_eq!(
        eval(&expr("(and busy (> count 0))"), &cx),
        Value::Bool(true)
    );
    assert_eq!(eval(&expr("(not busy)"), &cx), Value::Bool(false));
    assert_eq!(eval(&expr("(or busy (/ 1 0))"), &cx), Value::Bool(true));
}

#[test]
fn templates_interpolate() {
    let cx = cx_with(4, false);
    assert_eq!(
        eval(&expr(r#""{label}: {count} of {step}""#), &cx),
        Value::Str("Items: 4 of 3".into())
    );
}

#[test]
fn if_selects_branches() {
    let cx = cx_with(0, true);
    assert_eq!(
        eval(&expr(r##"(if busy "#111111" "#222222")"##), &cx),
        Value::Str("#111111".into())
    );
}