flowcode-core 0.4.1-alpha

Core execution engine for FlowCode data scripting language
Documentation
use flowcode_core::executor::{ExecuteResult, Executor};
use flowcode_core::parser::ParsedCommand;
use flowcode_core::logger::Logger;
use flowcode_core::error::FCError;
use flowcode_core::ast::ArgValue;

// Helper to shorten ParsedCommand creation in tests
fn pc(name: &str, args: Vec<ArgValue>) -> ParsedCommand {
    ParsedCommand { name: name.to_string(), args }
}

#[test]
fn test_execute_combine_success_and_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc("combine", vec![ArgValue::Number(10.0), ArgValue::Number(20.0), ArgValue::Number(30.0)]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Success("60".to_string())
    );
    assert_eq!(logger.get_logs().len(), 2);
    assert_eq!(
        logger.get_logs()[0],
        "Executing COMBINE"
    );
    assert_eq!(
        logger.get_logs()[1],
        "Executed COMBINE with args [TypedValue { kind: Number, value: Number(10.0) }, TypedValue { kind: Number, value: Number(20.0) }, TypedValue { kind: Number, value: Number(30.0) }] -> 60"
    );
}

#[test]
fn test_execute_combine_no_args_and_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc("combine", vec![]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Success("-0".to_string())
    );
    assert_eq!(logger.get_logs().len(), 2);
    assert_eq!(
        logger.get_logs()[0],
        "Executing COMBINE"
    );
    assert_eq!(
        logger.get_logs()[1],
        "Executed COMBINE with args [] -> -0"
    );
}

#[test]
fn test_execute_combine_invalid_arg_no_log_for_success() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc(
        "combine",
        vec![ArgValue::Number(10.0), ArgValue::String("abc".to_string()), ArgValue::Number(20.0)],
    );
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Error(FCError::InvalidArgument("combine command requires numeric arguments".to_string()))
    );
    assert_eq!(logger.get_logs().len(), 2);
    assert_eq!(
        logger.get_logs()[0],
        "Executing COMBINE"
    );
    assert_eq!(
        logger.get_logs()[1],
        "Attempted COMBINE with invalid args: [TypedValue { kind: Number, value: Number(10.0) }, TypedValue { kind: String, value: String(\"abc\") }, TypedValue { kind: Number, value: Number(20.0) }]"
    );
}

#[test]
fn test_execute_predict_success_and_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc(
        "predict",
        vec![
            ArgValue::Number(10.0),
            ArgValue::Number(20.0),
            ArgValue::Number(30.0),
            ArgValue::Number(40.0),
        ],
    );
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Success(format!("Prediction: {}", 50.0))
    );
    assert_eq!(logger.get_logs().len(), 2);
    assert_eq!(
        logger.get_logs()[0],
        "Executing PREDICT"
    );
    assert_eq!(
        logger.get_logs()[1],
        "Executed PREDICT with args [TypedValue { kind: Number, value: Number(10.0) }, TypedValue { kind: Number, value: Number(20.0) }, TypedValue { kind: Number, value: Number(30.0) }, TypedValue { kind: Number, value: Number(40.0) }] -> Prediction: 50"
    );
}

#[test]
fn test_execute_predict_insufficient_data_and_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc("predict", vec![ArgValue::Number(10.0)]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Error(FCError::InsufficientData("predict command requires at least two numeric arguments".to_string()))
    );
    assert_eq!(logger.get_logs().len(), 2);
    assert_eq!(
        logger.get_logs()[0],
        "Executing PREDICT"
    );
    assert_eq!(
        logger.get_logs()[1],
        "Attempted PREDICT with insufficient args: [TypedValue { kind: Number, value: Number(10.0) }]"
    );
}

#[test]
fn test_execute_show_no_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc("show", vec![]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Success("Executing SHOW".to_string())
    );
    assert_eq!(logger.get_logs().len(), 1);
    assert_eq!(
        logger.get_logs()[0],
        "Executing SHOW"
    );
}

#[test]
fn test_execute_show_with_logs() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    logger.log_action("Log 1".to_string());
    logger.log_action("Log 2: another event".to_string());

    let command = pc("show", vec![]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Success("Log 1\nLog 2: another event\nExecuting SHOW".to_string())
    );
    assert_eq!(logger.get_logs().len(), 3);
    assert_eq!(
        logger.get_logs()[2],
        "Executing SHOW"
    );
}

#[test]
fn test_execute_show_with_args_error() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc("show", vec![ArgValue::String("unexpected".to_string())]);
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Error(FCError::InvalidArgument("show command does not take arguments".to_string()))
    );
    assert_eq!(logger.get_logs().len(), 1);
    assert_eq!(
        logger.get_logs()[0],
        "Executing SHOW"
    );
}

#[test]
fn test_execute_unknown_command() {
    let executor = Executor::new();
    let mut logger = Logger::new(10);
    let command = pc(
        "fly",
        vec![ArgValue::String("to".to_string()), ArgValue::String("moon".to_string())],
    );
    assert_eq!(
        executor.execute_command(&command, &mut logger),
        ExecuteResult::Error(FCError::UnknownCommand("Command 'fly' is recognized but not implemented.".to_string()))
    );
    assert_eq!(logger.get_logs().len(), 1);
    assert_eq!(
        logger.get_logs()[0],
        "Executing FLY"
    );
}