use super::*;
#[test]
fn test_format_macro_debug_format() {
let mut interp = Interpreter::new();
let format_macro = Expr {
kind: ExprKind::MacroInvocation {
name: "format".to_string(),
args: vec![make_string("Debug: {:?}"), make_int(42)],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&format_macro).expect("should evaluate");
if let Value::String(s) = result {
assert!(s.contains("42"));
} else {
panic!("Expected String");
}
}
#[test]
fn test_if_let_with_else_branch() {
let mut interp = Interpreter::new();
let if_let = Expr {
kind: ExprKind::IfLet {
pattern: Pattern::Identifier("x".to_string()),
expr: Box::new(make_int(42)),
then_branch: Box::new(make_ident("x")),
else_branch: Some(Box::new(make_int(0))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&if_let).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_if_let_no_match_no_else() {
let mut interp = Interpreter::new();
let if_let = Expr {
kind: ExprKind::IfLet {
pattern: Pattern::Tuple(vec![
Pattern::Identifier("x".to_string()),
Pattern::Identifier("y".to_string()),
]),
expr: Box::new(make_int(42)),
then_branch: Box::new(make_int(1)),
else_branch: None,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&if_let).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_if_let_no_match_with_else() {
let mut interp = Interpreter::new();
let if_let = Expr {
kind: ExprKind::IfLet {
pattern: Pattern::Tuple(vec![
Pattern::Identifier("x".to_string()),
Pattern::Identifier("y".to_string()),
]),
expr: Box::new(make_int(42)),
then_branch: Box::new(make_int(1)),
else_branch: Some(Box::new(make_int(100))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&if_let).expect("should evaluate");
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_module_declaration_returns_error() {
let mut interp = Interpreter::new();
let mod_decl = Expr {
kind: ExprKind::ModuleDeclaration {
name: "unresolved_module".to_string(),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&mod_decl);
assert!(result.is_err());
}
#[test]
fn test_pipeline_with_method_call() {
let mut interp = Interpreter::new();
interp.set_variable(
"arr",
Value::Array(vec![Value::Integer(3), Value::Integer(1), Value::Integer(2)].into()),
);
let pipeline = Expr {
kind: ExprKind::Pipeline {
expr: Box::new(make_ident("arr")),
stages: vec![crate::frontend::ast::PipelineStage {
op: Box::new(make_ident("len")),
span: Span::default(),
}],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&pipeline).expect("should evaluate");
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_try_operator_on_non_result() {
let mut interp = Interpreter::new();
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_int(42)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let _result = interp.eval_expr(&try_expr);
}
#[test]
fn test_ternary_with_complex_expressions() {
let mut interp = Interpreter::new();
let ternary = Expr {
kind: ExprKind::Ternary {
condition: Box::new(make_bool(true)),
true_expr: Box::new(make_binary(make_int(1), AstBinaryOp::Add, make_int(2))),
false_expr: Box::new(make_binary(make_int(3), AstBinaryOp::Add, make_int(4))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&ternary).expect("should evaluate");
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_ternary_false_branch_coverage() {
let mut interp = Interpreter::new();
let ternary = Expr {
kind: ExprKind::Ternary {
condition: Box::new(make_bool(false)),
true_expr: Box::new(make_int(1)),
false_expr: Box::new(make_int(2)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&ternary).expect("should evaluate");
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_macro_invocation_unknown_macro() {
let mut interp = Interpreter::new();
let unknown_macro = Expr {
kind: ExprKind::MacroInvocation {
name: "unknown_macro".to_string(),
args: vec![make_bool(true)],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&unknown_macro);
assert!(result.is_err());
}
#[test]
fn test_macro_invocation_println_no_args() {
let mut interp = Interpreter::new();
let println_macro = Expr {
kind: ExprKind::MacroInvocation {
name: "println".to_string(),
args: vec![],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&println_macro).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_macro_invocation_println_one_arg() {
let mut interp = Interpreter::new();
let println_macro = Expr {
kind: ExprKind::MacroInvocation {
name: "println".to_string(),
args: vec![make_int(42)],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&println_macro).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_macro_invocation_vec_two_elements() {
let mut interp = Interpreter::new();
let vec_macro = Expr {
kind: ExprKind::MacroInvocation {
name: "vec".to_string(),
args: vec![make_int(10), make_int(20)],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&vec_macro).expect("should evaluate");
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 2);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_literal_byte() {
let mut interp = Interpreter::new();
let byte_lit = Expr {
kind: ExprKind::Literal(Literal::Byte(255)),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&byte_lit).expect("should evaluate");
assert_eq!(result, Value::Byte(255));
}
#[test]
fn test_literal_char() {
let mut interp = Interpreter::new();
let char_lit = Expr {
kind: ExprKind::Literal(Literal::Char('x')),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&char_lit).expect("should evaluate");
assert_eq!(result, Value::String("x".into()));
}
#[test]
fn test_literal_unit() {
let mut interp = Interpreter::new();
let unit_lit = Expr {
kind: ExprKind::Literal(Literal::Unit),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&unit_lit).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_literal_null() {
let mut interp = Interpreter::new();
let null_lit = Expr {
kind: ExprKind::Literal(Literal::Null),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&null_lit).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_continue_expression() {
let mut interp = Interpreter::new();
let cont = Expr {
kind: ExprKind::Continue { label: None },
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&cont);
assert!(result.is_err());
}
#[test]
fn test_break_with_value_coverage() {
let mut interp = Interpreter::new();
let brk = Expr {
kind: ExprKind::Break {
label: None,
value: Some(Box::new(make_int(42))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&brk);
assert!(result.is_err());
}
#[test]
fn test_break_without_value_coverage() {
let mut interp = Interpreter::new();
let brk = Expr {
kind: ExprKind::Break {
label: None,
value: None,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&brk);
assert!(result.is_err());
}
#[test]
fn test_range_inclusive_cov5() {
let mut interp = Interpreter::new();
let range = Expr {
kind: ExprKind::Range {
start: Box::new(make_int(1)),
end: Box::new(make_int(5)),
inclusive: true,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&range).expect("should evaluate");
if let Value::Range { inclusive, .. } = result {
assert!(inclusive);
} else {
panic!("Expected Range");
}
}
#[test]
fn test_range_exclusive_cov5() {
let mut interp = Interpreter::new();
let range = Expr {
kind: ExprKind::Range {
start: Box::new(make_int(0)),
end: Box::new(make_int(10)),
inclusive: false,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&range).expect("should evaluate");
if let Value::Range { inclusive, .. } = result {
assert!(!inclusive);
} else {
panic!("Expected Range");
}
}
#[test]
fn test_array_init_expr() {
let mut interp = Interpreter::new();
let arr_init = Expr {
kind: ExprKind::ArrayInit {
value: Box::new(make_int(0)),
size: Box::new(make_int(5)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&arr_init).expect("should evaluate");
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 5);
assert_eq!(arr[0], Value::Integer(0));
} else {
panic!("Expected Array");
}
}
#[test]
fn test_lookup_option_none() {
let interp = Interpreter::new();
let result = interp
.lookup_variable("Option::None")
.expect("should lookup");
if let Value::EnumVariant {
enum_name,
variant_name,
..
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "None");
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_return_with_value() {
let mut interp = Interpreter::new();
let ret = Expr {
kind: ExprKind::Return {
value: Some(Box::new(make_int(100))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&ret);
assert!(result.is_err());
}
#[test]
fn test_return_without_value() {
let mut interp = Interpreter::new();
let ret = Expr {
kind: ExprKind::Return { value: None },
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&ret);
assert!(result.is_err());
}
#[test]
fn test_loop_with_break_value_cov5() {
let mut interp = Interpreter::new();
interp.set_variable("counter", Value::Integer(0));
let loop_expr = Expr {
kind: ExprKind::Loop {
label: None,
body: Box::new(Expr {
kind: ExprKind::Break {
label: None,
value: Some(Box::new(make_int(42))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&loop_expr).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_throw_expression_err() {
let mut interp = Interpreter::new();
let throw = Expr {
kind: ExprKind::Throw {
expr: Box::new(make_string("error message")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&throw);
assert!(result.is_err());
}
#[test]
fn test_compound_assign_add_coverage() {
let mut interp = Interpreter::new();
interp.set_variable("x", Value::Integer(10));
let compound = Expr {
kind: ExprKind::CompoundAssign {
target: Box::new(make_ident("x")),
op: AstBinaryOp::Add,
value: Box::new(make_int(5)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&compound).expect("should evaluate");
assert_eq!(result, Value::Integer(15));
}
#[test]
fn test_compound_assign_subtract_coverage() {
let mut interp = Interpreter::new();
interp.set_variable("x", Value::Integer(20));
let compound = Expr {
kind: ExprKind::CompoundAssign {
target: Box::new(make_ident("x")),
op: AstBinaryOp::Subtract,
value: Box::new(make_int(8)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&compound).expect("should evaluate");
assert_eq!(result, Value::Integer(12));
}
#[test]
fn test_tuple_empty() {
let mut interp = Interpreter::new();
let tuple = Expr {
kind: ExprKind::Tuple(vec![]),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&tuple).expect("should evaluate");
if let Value::Tuple(t) = result {
assert!(t.is_empty());
} else {
panic!("Expected Tuple");
}
}
#[test]
fn test_tuple_single_element() {
let mut interp = Interpreter::new();
let tuple = Expr {
kind: ExprKind::Tuple(vec![make_int(42)]),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&tuple).expect("should evaluate");
if let Value::Tuple(t) = result {
assert_eq!(t.len(), 1);
assert_eq!(t[0], Value::Integer(42));
} else {
panic!("Expected Tuple");
}
}
#[test]
fn test_null_coalesce_with_nil() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(Expr {
kind: ExprKind::Literal(Literal::Null),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}),
op: AstBinaryOp::NullCoalesce,
right: Box::new(make_int(42)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_null_coalesce_with_value() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(make_int(10)),
op: AstBinaryOp::NullCoalesce,
right: Box::new(make_int(42)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should evaluate");
assert_eq!(result, Value::Integer(10));
}
#[test]
fn test_in_operator_string_contains() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(Expr {
kind: ExprKind::Literal(Literal::String("ell".to_string())),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}),
op: AstBinaryOp::In,
right: Box::new(Expr {
kind: ExprKind::Literal(Literal::String("hello".to_string())),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_in_operator_array_contains() {
let mut interp = Interpreter::new();
let arr = Expr {
kind: ExprKind::List(vec![make_int(1), make_int(2), make_int(3)]),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(make_int(2)),
op: AstBinaryOp::In,
right: Box::new(arr),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_in_operator_tuple_contains() {
let mut interp = Interpreter::new();
let tup = Expr {
kind: ExprKind::Tuple(vec![make_int(10), make_int(20), make_int(30)]),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(make_int(20)),
op: AstBinaryOp::In,
right: Box::new(tup),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should evaluate");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_in_operator_unsupported_type() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::Binary {
left: Box::new(make_int(1)),
op: AstBinaryOp::In,
right: Box::new(make_int(42)), },
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_eval_contains_object_key() {
let interp = Interpreter::new();
let mut map = std::collections::HashMap::new();
map.insert("key1".to_string(), Value::Integer(1));
map.insert("key2".to_string(), Value::Integer(2));
let obj = Value::Object(std::sync::Arc::new(map));
let element = Value::from_string("key1".to_string());
let result = interp.eval_contains(&element, &obj).expect("should work");
assert!(result);
}
#[test]
fn test_eval_contains_object_non_string_key() {
let interp = Interpreter::new();
let mut map = std::collections::HashMap::new();
map.insert("42".to_string(), Value::Integer(1));
let obj = Value::Object(std::sync::Arc::new(map));
let element = Value::Integer(42);
let result = interp.eval_contains(&element, &obj).expect("should work");
assert!(result);
}
#[test]
fn test_while_let_with_break() {
let mut interp = Interpreter::new();
let while_let = Expr {
kind: ExprKind::WhileLet {
label: None,
pattern: Pattern::Identifier("x".to_string()),
expr: Box::new(make_int(1)),
body: Box::new(Expr {
kind: ExprKind::Break {
label: None,
value: Some(Box::new(make_int(100))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&while_let).expect("should evaluate");
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_try_operator_object_ok() {
let mut interp = Interpreter::new();
let mut obj_map = std::collections::HashMap::new();
obj_map.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
obj_map.insert("type".to_string(), Value::from_string("Ok".to_string()));
obj_map.insert(
"data".to_string(),
Value::Array(std::sync::Arc::from(vec![Value::Integer(42)])),
);
interp.env_set(
"result".to_string(),
Value::Object(std::sync::Arc::new(obj_map)),
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr).expect("should unwrap Ok");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_try_operator_object_err() {
let mut interp = Interpreter::new();
let mut obj_map = std::collections::HashMap::new();
obj_map.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
obj_map.insert("type".to_string(), Value::from_string("Err".to_string()));
obj_map.insert(
"data".to_string(),
Value::Array(std::sync::Arc::from(vec![Value::from_string(
"error".to_string(),
)])),
);
interp.env_set(
"result".to_string(),
Value::Object(std::sync::Arc::new(obj_map)),
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_try_operator_object_missing_type() {
let mut interp = Interpreter::new();
let mut obj_map = std::collections::HashMap::new();
obj_map.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
interp.env_set(
"result".to_string(),
Value::Object(std::sync::Arc::new(obj_map)),
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_format_macro_missing_values() {
let mut interp = Interpreter::new();
let macro_expr = Expr {
kind: ExprKind::MacroInvocation {
name: "format".to_string(),
args: vec![
Expr {
kind: ExprKind::Literal(Literal::String("{} {} {}".to_string())),
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
},
make_int(1),
],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(¯o_expr).expect("should evaluate");
if let Value::String(s) = result {
assert!(s.contains("{}"));
} else {
panic!("Expected string");
}
}
#[test]
fn test_lookup_option_none_variant() {
let interp = Interpreter::new();
let result = interp
.lookup_variable("Option::None")
.expect("should lookup");
if let Value::EnumVariant {
enum_name,
variant_name,
data,
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "None");
assert!(data.is_none());
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_env_pop_last_scope() {
let mut interp = Interpreter::new();
let result = interp.env_pop();
assert!(result.is_none());
}
#[test]
fn test_env_set_mut_create_new() {
let mut interp = Interpreter::new();
interp.env_set_mut("new_var".to_string(), Value::Integer(100));
let result = interp
.lookup_variable("new_var")
.expect("should find variable");
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_type_cast_float_to_float() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::TypeCast {
expr: Box::new(make_float(3.14)),
target_type: "f64".to_string(),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should cast");
assert_eq!(result, Value::Float(3.14));
}
#[test]
fn test_type_cast_float_to_int() {
let mut interp = Interpreter::new();
let expr = Expr {
kind: ExprKind::TypeCast {
expr: Box::new(make_float(3.9)),
target_type: "i32".to_string(),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).expect("should cast");
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_await_expr_evaluates_inner_coverage() {
let mut interp = Interpreter::new();
let await_expr = Expr {
kind: ExprKind::Await {
expr: Box::new(make_int(42)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&await_expr).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_list_comprehension_non_iterable() {
let mut interp = Interpreter::new();
let comprehension = Expr {
kind: ExprKind::ListComprehension {
element: Box::new(make_ident("x")),
clauses: vec![ComprehensionClause {
variable: "x".to_string(),
iterable: Box::new(make_int(42)),
condition: None,
}],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&comprehension);
assert!(result.is_err());
}
#[test]
fn test_pipeline_with_closure() {
let mut interp = Interpreter::new();
let _ = interp.eval_string("fun double(x) { x * 2 }");
let result = interp.eval_string("5 |> double").expect("should evaluate");
assert_eq!(result, Value::Integer(10));
}
#[test]
fn test_stack_push_pop() {
let mut interp = Interpreter::new();
interp.push(Value::Integer(42)).expect("push should work");
interp.push(Value::Integer(100)).expect("push should work");
let popped = interp.pop().expect("pop should work");
assert_eq!(popped, Value::Integer(100));
let popped2 = interp.pop().expect("pop should work");
assert_eq!(popped2, Value::Integer(42));
}
#[test]
fn test_stack_underflow() {
let mut interp = Interpreter::new();
let result = interp.pop();
assert!(result.is_err());
}
#[test]
fn test_stack_peek() {
let mut interp = Interpreter::new();
interp.push(Value::Integer(10)).expect("push");
interp.push(Value::Integer(20)).expect("push");
interp.push(Value::Integer(30)).expect("push");
let top = interp.peek(0).expect("peek");
assert_eq!(top, Value::Integer(30));
let second = interp.peek(1).expect("peek");
assert_eq!(second, Value::Integer(20));
let third = interp.peek(2).expect("peek");
assert_eq!(third, Value::Integer(10));
}
#[test]
fn test_stack_peek_underflow() {
let mut interp = Interpreter::new();
interp.push(Value::Integer(1)).expect("push");
let result = interp.peek(5); assert!(result.is_err());
}
#[test]
fn test_binary_op_add_stack() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(10)).expect("push");
interp.push(Value::Integer(32)).expect("push");
interp.binary_op(BinaryOp::Add).expect("add");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_binary_op_sub_stack() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(50)).expect("push");
interp.push(Value::Integer(8)).expect("push");
interp.binary_op(BinaryOp::Sub).expect("sub");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_binary_op_mul_stack() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(6)).expect("push");
interp.push(Value::Integer(7)).expect("push");
interp.binary_op(BinaryOp::Mul).expect("mul");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_binary_op_div_stack() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(84)).expect("push");
interp.push(Value::Integer(2)).expect("push");
interp.binary_op(BinaryOp::Div).expect("div");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_binary_op_eq() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(42)).expect("push");
interp.push(Value::Integer(42)).expect("push");
interp.binary_op(BinaryOp::Eq).expect("eq");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_binary_op_lt() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(10)).expect("push");
interp.push(Value::Integer(20)).expect("push");
interp.binary_op(BinaryOp::Lt).expect("lt");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_binary_op_gt() {
use crate::runtime::interpreter::BinaryOp;
let mut interp = Interpreter::new();
interp.push(Value::Integer(20)).expect("push");
interp.push(Value::Integer(10)).expect("push");
interp.binary_op(BinaryOp::Gt).expect("gt");
let result = interp.pop().expect("pop");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_json_parse_object() {
let interp = Interpreter::new();
let result = interp.json_parse(r#"{"key": 42}"#).expect("should parse");
if let Value::Object(obj) = result {
assert_eq!(obj.get("key"), Some(&Value::Integer(42)));
} else {
panic!("Expected Object");
}
}
#[test]
fn test_json_parse_array() {
let interp = Interpreter::new();
let result = interp.json_parse(r#"[1, 2, 3]"#).expect("should parse");
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 3);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_json_stringify() {
let interp = Interpreter::new();
let mut map = std::collections::HashMap::new();
map.insert("x".to_string(), Value::Integer(10));
let obj = Value::Object(std::sync::Arc::new(map));
let result = interp.json_stringify(&obj).expect("should stringify");
if let Value::String(s) = result {
assert!(s.contains("x") && s.contains("10"));
} else {
panic!("Expected String");
}
}
#[test]
fn test_get_field_cached_string_len() {
let mut interp = Interpreter::new();
let s = Value::from_string("hello".to_string());
let result = interp.get_field_cached(&s, "len").expect("should get len");
assert_eq!(result, Value::Integer(5));
}
#[test]
fn test_get_field_cached_array_len() {
let mut interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![
Value::Integer(1),
Value::Integer(2),
]));
let result = interp
.get_field_cached(&arr, "len")
.expect("should get len");
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_get_field_cached_array_first() {
let mut interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![
Value::Integer(10),
Value::Integer(20),
]));
let result = interp
.get_field_cached(&arr, "first")
.expect("should get first");
assert_eq!(result, Value::Integer(10));
}
#[test]
fn test_get_field_cached_array_last() {
let mut interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![
Value::Integer(10),
Value::Integer(20),
]));
let result = interp
.get_field_cached(&arr, "last")
.expect("should get last");
assert_eq!(result, Value::Integer(20));
}
#[test]
fn test_get_field_cached_array_is_empty() {
let mut interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![]));
let result = interp
.get_field_cached(&arr, "is_empty")
.expect("should get is_empty");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_get_field_cached_type() {
let mut interp = Interpreter::new();
let val = Value::Integer(42);
let result = interp
.get_field_cached(&val, "type")
.expect("should get type");
if let Value::String(s) = result {
assert!(s.contains("int"));
} else {
panic!("Expected String");
}
}
#[test]
fn test_get_field_cached_cache_hit() {
let mut interp = Interpreter::new();
let s = Value::from_string("test".to_string());
let _ = interp.get_field_cached(&s, "len");
let result = interp
.get_field_cached(&s, "len")
.expect("should get len from cache");
assert_eq!(result, Value::Integer(4));
}
#[test]
fn test_clear_caches_coverage() {
let mut interp = Interpreter::new();
let s = Value::from_string("test".to_string());
let _ = interp.get_field_cached(&s, "len");
interp.clear_caches();
let stats = interp.get_cache_stats();
assert!(stats.is_empty());
}
#[test]
fn test_match_tuple_pattern() {
let interp = Interpreter::new();
let patterns = vec![
Pattern::Identifier("a".to_string()),
Pattern::Identifier("b".to_string()),
];
let tuple_val = Value::Tuple(std::sync::Arc::from(vec![
Value::Integer(1),
Value::Integer(2),
]));
let result = interp
.match_tuple_pattern(&patterns, &tuple_val)
.expect("should match");
assert!(result);
}
#[test]
fn test_match_tuple_pattern_mismatch() {
let interp = Interpreter::new();
let patterns = vec![Pattern::Identifier("a".to_string())];
let tuple_val = Value::Tuple(std::sync::Arc::from(vec![
Value::Integer(1),
Value::Integer(2),
]));
let result = interp
.match_tuple_pattern(&patterns, &tuple_val)
.expect("should not match");
assert!(!result); }
#[test]
fn test_match_list_pattern() {
let interp = Interpreter::new();
let patterns = vec![Pattern::Identifier("x".to_string())];
let arr_val = Value::Array(std::sync::Arc::from(vec![Value::Integer(10)]));
let result = interp
.match_list_pattern(&patterns, &arr_val)
.expect("should match");
assert!(result);
}
#[test]
fn test_match_or_pattern() {
let interp = Interpreter::new();
let patterns = vec![
Pattern::Literal(Literal::Integer(1, None)),
Pattern::Literal(Literal::Integer(2, None)),
];
let val = Value::Integer(2);
let result = interp
.match_or_pattern(&patterns, &val)
.expect("should match");
assert!(result);
}
#[test]
fn test_push_pop_scope_coverage() {
let mut interp = Interpreter::new();
interp.push_scope();
interp.env_set("scoped_var".to_string(), Value::Integer(42));
let lookup = interp.lookup_variable("scoped_var");
assert!(lookup.is_ok());
interp.pop_scope();
let lookup_after = interp.lookup_variable("scoped_var");
assert!(lookup_after.is_err());
}
#[test]
fn test_apply_binary_op_add() {
let interp = Interpreter::new();
let result = interp
.apply_binary_op(&Value::Integer(10), AstBinaryOp::Add, &Value::Integer(32))
.expect("should add");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_apply_binary_op_compare() {
let interp = Interpreter::new();
let result = interp
.apply_binary_op(&Value::Integer(10), AstBinaryOp::Less, &Value::Integer(20))
.expect("should compare");
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_set_variable_string_coverage() {
let mut interp = Interpreter::new();
interp.set_variable_string("my_var".to_string(), Value::Integer(123));
let result = interp.lookup_variable("my_var").expect("should find");
assert_eq!(result, Value::Integer(123));
}
#[test]
fn test_compute_field_access_string_to_upper() {
let interp = Interpreter::new();
let s = Value::from_string("hello".to_string());
let result = interp
.compute_field_access(&s, "to_upper")
.expect("should work");
assert_eq!(result, Value::from_string("HELLO".to_string()));
}
#[test]
fn test_compute_field_access_string_to_lower() {
let interp = Interpreter::new();
let s = Value::from_string("HELLO".to_string());
let result = interp
.compute_field_access(&s, "to_lower")
.expect("should work");
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_compute_field_access_string_trim() {
let interp = Interpreter::new();
let s = Value::from_string(" hello ".to_string());
let result = interp
.compute_field_access(&s, "trim")
.expect("should work");
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_compute_field_access_unknown_field() {
let interp = Interpreter::new();
let s = Value::from_string("hello".to_string());
let result = interp.compute_field_access(&s, "unknown_field");
assert!(result.is_err());
}
#[test]
fn test_compute_field_access_empty_array_first() {
let interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![]));
let result = interp.compute_field_access(&arr, "first");
assert!(result.is_err()); }
#[test]
fn test_compute_field_access_empty_array_last() {
let interp = Interpreter::new();
let arr = Value::Array(std::sync::Arc::from(vec![]));
let result = interp.compute_field_access(&arr, "last");
assert!(result.is_err()); }
#[test]
fn test_try_operator_enum_ok() {
let mut interp = Interpreter::new();
interp.env_set(
"result".to_string(),
Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Ok".to_string(),
data: Some(vec![Value::Integer(42)]),
},
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr).expect("should unwrap Ok");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_try_operator_enum_err() {
let mut interp = Interpreter::new();
interp.env_set(
"result".to_string(),
Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Err".to_string(),
data: Some(vec![Value::from_string("error".to_string())]),
},
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err()); }
#[test]
fn test_try_operator_enum_ok_no_data() {
let mut interp = Interpreter::new();
interp.env_set(
"result".to_string(),
Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Ok".to_string(),
data: None, },
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err()); }
#[test]
fn test_try_operator_enum_unknown_variant() {
let mut interp = Interpreter::new();
interp.env_set(
"result".to_string(),
Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Unknown".to_string(), data: None,
},
);
let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_try_operator_not_result() {
let mut interp = Interpreter::new();
interp.env_set("result".to_string(), Value::Integer(42)); let try_expr = Expr {
kind: ExprKind::Try {
expr: Box::new(make_ident("result")),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_lazy_expr() {
let mut interp = Interpreter::new();
let lazy_expr = Expr {
kind: ExprKind::Lazy {
expr: Box::new(make_int(42)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&lazy_expr).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_async_block_expr() {
let mut interp = Interpreter::new();
let async_expr = Expr {
kind: ExprKind::AsyncBlock {
body: Box::new(make_int(100)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&async_expr).expect("should evaluate");
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_if_let_with_simple_pattern() {
let mut interp = Interpreter::new();
interp.env_set("val".to_string(), Value::Integer(42));
let if_let = Expr {
kind: ExprKind::IfLet {
pattern: Pattern::Identifier("x".to_string()),
expr: Box::new(make_ident("val")),
then_branch: Box::new(make_ident("x")),
else_branch: Some(Box::new(make_int(0))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&if_let).expect("should evaluate");
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_if_let_no_match_no_else_coverage() {
let mut interp = Interpreter::new();
interp.env_set("val".to_string(), Value::Nil);
let if_let = Expr {
kind: ExprKind::IfLet {
pattern: Pattern::Literal(Literal::Integer(1, None)),
expr: Box::new(make_ident("val")),
then_branch: Box::new(make_int(100)),
else_branch: None, },
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&if_let).expect("should evaluate");
assert_eq!(result, Value::Nil);
}
#[test]
fn test_pipeline_with_method() {
let mut interp = Interpreter::new();
let result = interp.eval_string(r#""hello" |> upper"#);
assert!(result.is_ok() || result.is_err()); }
#[test]
fn test_pipeline_with_call_args() {
let mut interp = Interpreter::new();
let result = interp.eval_string(r#"[1, 2, 3] |> join(",")"#);
if let Ok(Value::String(s)) = result {
assert!(s.contains(","));
}
}
#[test]
fn test_clear_stdout_has_stdout() {
let mut interp = Interpreter::new();
let _ = interp.eval_string(r#"println!("test")"#);
let has_output_before = interp.has_stdout();
interp.clear_stdout();
let has_output_after = interp.has_stdout();
assert!(has_output_before || !has_output_after);
}
#[test]
fn test_get_stdout_method() {
let mut interp = Interpreter::new();
let _ = interp.eval_string(r#"println!("hello")"#);
let output = interp.get_stdout();
assert!(output.is_empty() || output.contains("hello"));
}
#[test]
fn test_module_expression_simple() {
let mut interp = Interpreter::new();
let module_expr = Expr {
kind: ExprKind::Module {
name: "MyModule".to_string(),
body: Box::new(make_int(42)), },
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&module_expr);
assert!(result.is_ok()); }
#[test]
fn test_interpreter_default_impl() {
let _interp = Interpreter::default();
}