use ruchy::backend::transpiler::Transpiler;
use ruchy::frontend::{ast::*, Parser};
use ruchy::runtime::interpreter::{Interpreter, Value};
use std::rc::Rc;
#[test]
fn test_complex_arithmetic() {
let mut parser = Parser::new("(10 + 20) * 3 - 15 / 5");
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(87));
}
#[test]
fn test_nested_parentheses() {
let mut parser = Parser::new("((2 + 3) * (4 + 5))");
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(45));
}
#[test]
fn test_boolean_short_circuit_and() {
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(false));
}
#[test]
fn test_boolean_short_circuit_or() {
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(true));
}
#[test]
fn test_comparison_chain() {
let mut parser = Parser::new("1 < 2 && 3 > 2");
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_mixed_operations() {
let mut parser = Parser::new("10 + 5 > 12");
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_double_negation() {
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));
}
#[test]
fn test_negative_number_arithmetic() {
let mut parser = Parser::new("-5 + 10");
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(5));
}
#[test]
fn test_modulo_operation() {
let mut parser = Parser::new("17 % 5");
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(2));
}
#[test]
fn test_string_concatenation_placeholder() {
let mut parser = Parser::new(r#""hello""#);
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".to_string())));
}
#[test]
fn test_transpiler_arithmetic() {
let transpiler = Transpiler::new();
let left = Expr {
kind: ExprKind::Literal(Literal::Integer(5)),
span: Span::new(0, 1),
attributes: vec![],
};
let right = Expr {
kind: ExprKind::Literal(Literal::Integer(3)),
span: Span::new(4, 5),
attributes: vec![],
};
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(left),
op: BinaryOp::Add,
right: Box::new(right),
},
span: Span::new(0, 5),
attributes: vec![],
};
let result = transpiler.transpile(&expr);
assert!(result.is_ok());
}
#[test]
fn test_parser_precedence_multiply_before_add() {
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(14));
}
#[test]
fn test_parser_precedence_comparison_after_arithmetic() {
let mut parser = Parser::new("2 + 3 < 6");
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_zero_operations() {
let mut parser = Parser::new("0 + 0");
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(0));
}
#[test]
fn test_large_numbers() {
let mut parser = Parser::new("1000000 + 1");
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(1000001));
}
#[test]
fn test_multiple_comparison_operations() {
let mut parser = Parser::new("5 > 3 == 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_equality_of_booleans() {
let mut parser = Parser::new("true == 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_inequality_of_numbers() {
let mut parser = Parser::new("10 != 20");
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));
}
#[cfg(test)]
mod property_tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn prop_addition_commutative(a in -1000i32..1000, b in -1000i32..1000) {
let expr1 = format!("{} + {}", a, b);
let expr2 = format!("{} + {}", b, a);
let mut parser1 = Parser::new(&expr1);
let mut parser2 = Parser::new(&expr2);
if let (Ok(e1), Ok(e2)) = (parser1.parse(), parser2.parse()) {
let mut interpreter = Interpreter::new();
if let (Ok(r1), Ok(r2)) = (interpreter.eval_expr(&e1), interpreter.eval_expr(&e2)) {
prop_assert_eq!(r1, r2);
}
}
}
#[test]
fn prop_zero_identity(n in -10000i64..10000) {
let expr = format!("{} + 0", n);
let mut parser = Parser::new(&expr);
if let Ok(e) = parser.parse() {
let mut interpreter = Interpreter::new();
if let Ok(result) = interpreter.eval_expr(&e) {
prop_assert_eq!(result, Value::Integer(n));
}
}
}
}
}