use ruchy::frontend::{ast::*, Parser};
use ruchy::runtime::interpreter::{Interpreter, Value};
use std::rc::Rc;
#[test]
fn test_parse_and_eval_integer() {
let mut parser = Parser::new("42");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_parse_and_eval_addition() {
let mut parser = Parser::new("10 + 32");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_parse_and_eval_boolean() {
let mut parser = Parser::new("true");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(true));
let mut parser = Parser::new("false");
let expr = parser.parse().expect("Failed to parse");
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(false));
}
#[test]
fn test_parse_and_eval_comparison() {
let mut parser = Parser::new("5 > 3");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_parse_and_eval_string() {
let mut parser = Parser::new(r#""hello world""#);
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::String(Rc::new("hello world".to_string())));
}
#[test]
fn test_parse_and_eval_parentheses() {
let mut parser = Parser::new("(2 + 3) * 4");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Integer(20));
}
#[test]
fn test_parse_and_eval_nested_arithmetic() {
let mut parser = Parser::new("1 + 2 * 3 - 4");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_parse_and_eval_logical_and() {
let mut parser = Parser::new("true && false");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(false));
}
#[test]
fn test_parse_and_eval_logical_or() {
let mut parser = Parser::new("false || true");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_parse_and_eval_equality() {
let mut parser = Parser::new("42 == 42");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(true));
let mut parser = Parser::new("42 != 24");
let expr = parser.parse().expect("Failed to parse");
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_parse_and_eval_unary_negation() {
let mut parser = Parser::new("-42");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Integer(-42));
}
#[test]
fn test_parse_and_eval_unary_not() {
let mut parser = Parser::new("!true");
let expr = parser.parse().expect("Failed to parse");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&expr).expect("Failed to evaluate");
assert_eq!(result, Value::Bool(false));
}
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_parse_eval_integer(n in i32::MIN/2..i32::MAX/2) {
let input = n.to_string();
let mut parser = Parser::new(&input);
if let Ok(expr) = parser.parse() {
let mut interpreter = Interpreter::new();
if let Ok(result) = interpreter.eval_expr(&expr) {
prop_assert_eq!(result, Value::Integer(n as i64));
}
}
}
#[test]
fn prop_parse_eval_addition(a in -1000i32..1000, b in -1000i32..1000) {
let input = format!("{} + {}", a, b);
let mut parser = Parser::new(&input);
if let Ok(expr) = parser.parse() {
let mut interpreter = Interpreter::new();
if let Ok(result) = interpreter.eval_expr(&expr) {
prop_assert_eq!(result, Value::Integer((a + b) as i64));
}
}
}
#[test]
fn prop_parse_eval_subtraction(a in -1000i32..1000, b in -1000i32..1000) {
let input = format!("{} - {}", a, b);
let mut parser = Parser::new(&input);
if let Ok(expr) = parser.parse() {
let mut interpreter = Interpreter::new();
if let Ok(result) = interpreter.eval_expr(&expr) {
prop_assert_eq!(result, Value::Integer((a - b) as i64));
}
}
}
}
}