use assert_cmd::Command;
use predicates::prelude::*;
fn ruchy_cmd() -> Command {
assert_cmd::cargo::cargo_bin_cmd!("ruchy")
}
#[test]
fn test_eval_basic() {
ruchy_cmd()
.arg("-e")
.arg("println(42)")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_long_form() {
ruchy_cmd()
.arg("--eval")
.arg("println(21 + 21)")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_format_text_default() {
ruchy_cmd()
.arg("-e")
.arg("2 + 2")
.assert()
.success()
.stdout(predicate::str::contains("4"));
}
#[test]
fn test_eval_format_text_explicit() {
ruchy_cmd()
.arg("-e")
.arg("println(2 + 2)")
.arg("--format")
.arg("text")
.assert()
.success()
.stdout(predicate::str::contains("4"));
}
#[test]
fn test_eval_format_json_success() {
ruchy_cmd()
.arg("-e")
.arg("2 + 2")
.arg("--format")
.arg("json")
.assert()
.success();
}
#[test]
fn test_eval_format_json_error() {
ruchy_cmd()
.arg("-e")
.arg("undefined_var")
.arg("--format")
.arg("json")
.assert()
.failure()
.stdout(predicate::str::contains("success").and(predicate::str::contains("false")));
}
#[test]
fn test_eval_verbose_short() {
ruchy_cmd()
.arg("-e")
.arg("println(42)")
.arg("-v")
.assert()
.success()
.stderr(predicate::str::contains("Parsing expression"))
.stderr(predicate::str::contains("Evaluation successful"));
}
#[test]
fn test_eval_verbose_long() {
ruchy_cmd()
.arg("-e")
.arg("println(21 + 21)")
.arg("--verbose")
.assert()
.success()
.stderr(predicate::str::contains(
"Parsing expression: println(21 + 21)",
))
.stderr(predicate::str::contains("Evaluation successful"));
}
#[test]
fn test_eval_verbose_error() {
ruchy_cmd()
.arg("-e")
.arg("parse_int(\"invalid\")")
.arg("-v")
.assert()
.failure()
.stderr(predicate::str::contains("Parsing expression"))
.stderr(predicate::str::contains("Evaluation failed"));
}
#[test]
fn test_eval_trace_basic() {
ruchy_cmd()
.arg("-e")
.arg("let x = 42; println(x)")
.arg("--trace")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_trace_function_call() {
ruchy_cmd()
.arg("-e")
.arg("fun add(a, b) { a + b }; println(add(10, 32))")
.arg("--trace")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_vm_mode_ast_default() {
ruchy_cmd()
.arg("-e")
.arg("println(2 + 2)")
.assert()
.success()
.stdout(predicate::str::contains("4"));
}
#[test]
fn test_eval_vm_mode_ast_explicit() {
ruchy_cmd()
.arg("-e")
.arg("println(10 * 4 + 2)")
.arg("--vm-mode")
.arg("ast")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_vm_mode_bytecode() {
ruchy_cmd()
.arg("-e")
.arg("println(21 * 2)")
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_vm_mode_bytecode_loop() {
ruchy_cmd()
.arg("-e")
.arg("let mut sum = 0; for i in 0..10 { sum = sum + i }; println(sum)")
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.stdout(predicate::str::contains("45")); }
#[test]
fn test_eval_vm_mode_bytecode_function() {
ruchy_cmd()
.arg("-e")
.arg("fun double(x) { x * 2 }; println(double(21))")
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_all_flags_combined_ast() {
ruchy_cmd()
.arg("-e")
.arg("println(42)")
.arg("--format")
.arg("text")
.arg("-v")
.arg("--trace")
.arg("--vm-mode")
.arg("ast")
.assert()
.success()
.stdout(predicate::str::contains("42"))
.stderr(predicate::str::contains("Parsing expression"))
.stderr(predicate::str::contains("Evaluation successful"));
}
#[test]
fn test_eval_all_flags_combined_bytecode() {
ruchy_cmd()
.arg("-e")
.arg("println(21 + 21)")
.arg("--format")
.arg("text")
.arg("--verbose")
.arg("--trace")
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.stdout(predicate::str::contains("42"))
.stderr(predicate::str::contains("Parsing expression"))
.stderr(predicate::str::contains("Evaluation successful"));
}
#[test]
fn test_eval_json_verbose_ast() {
ruchy_cmd()
.arg("-e")
.arg("undefined_var")
.arg("--format")
.arg("json")
.arg("-v")
.arg("--vm-mode")
.arg("ast")
.assert()
.failure()
.stdout(predicate::str::contains("\"success\":false"))
.stderr(predicate::str::contains("Evaluation failed"));
}
#[test]
fn test_eval_json_trace_bytecode() {
ruchy_cmd()
.arg("-e")
.arg("println(100 - 58)")
.arg("--format")
.arg("text")
.arg("--trace")
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_empty_expression() {
ruchy_cmd()
.arg("-e")
.arg("")
.assert()
.failure() .stderr(predicate::str::contains("Empty program"));
}
#[test]
fn test_eval_whitespace_only() {
ruchy_cmd()
.arg("-e")
.arg(" \n\t ")
.assert()
.failure() .stderr(predicate::str::contains("Empty program"));
}
#[test]
fn test_eval_syntax_error() {
ruchy_cmd().arg("-e").arg("let x = ").assert().failure();
}
#[test]
fn test_eval_runtime_error_verbose() {
ruchy_cmd()
.arg("-e")
.arg("parse_float(\"not_a_float\")")
.arg("-v")
.assert()
.failure()
.stderr(predicate::str::contains("Evaluation failed"));
}
#[test]
fn test_eval_multiline_expression() {
ruchy_cmd()
.arg("-e")
.arg("let x = 21;\nlet y = 21;\nprintln(x + y)")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_eval_main_function() {
ruchy_cmd()
.arg("-e")
.arg("fun main() { println(42) }")
.assert()
.success()
.stdout(predicate::str::contains("42"));
}
#[test]
fn test_property_vm_mode_equivalence() {
let code = "let x = 10; let y = 32; println(x + y)";
let ast_output = ruchy_cmd()
.arg("-e")
.arg(code)
.arg("--vm-mode")
.arg("ast")
.assert()
.success()
.get_output()
.stdout
.clone();
let bytecode_output = ruchy_cmd()
.arg("-e")
.arg(code)
.arg("--vm-mode")
.arg("bytecode")
.assert()
.success()
.get_output()
.stdout
.clone();
assert_eq!(
ast_output,
bytecode_output,
"VM modes produced different output: ast={:?}, bytecode={:?}",
String::from_utf8_lossy(&ast_output),
String::from_utf8_lossy(&bytecode_output)
);
}