use super::*;
use crate::frontend::ast::{Expr, ExprKind, Literal, Span};
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Mutex;
fn make_interpreter() -> Interpreter {
Interpreter::new()
}
fn make_expr(kind: ExprKind) -> Expr {
Expr {
kind,
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}
}
fn make_closure(params: Vec<(String, Option<Arc<Expr>>)>, body: Expr) -> Value {
Value::Closure {
params,
body: Arc::new(body),
env: Rc::new(RefCell::new(HashMap::new())),
}
}
fn make_handler(message_type: &str, params: Vec<String>, body: Expr) -> Value {
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string(message_type.to_string()),
);
handler_obj.insert(
"params".to_string(),
Value::Array(Arc::from(
params
.iter()
.map(|p| Value::from_string(p.clone()))
.collect::<Vec<_>>(),
)),
);
handler_obj.insert(
"body".to_string(),
make_closure(params.into_iter().map(|p| (p, None)).collect(), body),
);
Value::Object(Arc::new(handler_obj))
}
fn make_handler_with_types(
message_type: &str,
params: Vec<String>,
param_types: Vec<&str>,
body: Expr,
) -> Value {
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string(message_type.to_string()),
);
handler_obj.insert(
"params".to_string(),
Value::Array(Arc::from(
params
.iter()
.map(|p| Value::from_string(p.clone()))
.collect::<Vec<_>>(),
)),
);
handler_obj.insert(
"param_types".to_string(),
Value::Array(Arc::from(
param_types
.iter()
.map(|t| Value::from_string(t.to_string()))
.collect::<Vec<_>>(),
)),
);
handler_obj.insert(
"body".to_string(),
make_closure(params.into_iter().map(|p| (p, None)).collect(), body),
);
Value::Object(Arc::new(handler_obj))
}
fn make_message(msg_type: &str, data: Vec<Value>) -> Value {
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert("type".to_string(), Value::from_string(msg_type.to_string()));
msg_obj.insert("data".to_string(), Value::Array(Arc::from(data)));
Value::Object(Arc::new(msg_obj))
}
#[test]
fn test_actor_instance_send_empty() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp.eval_actor_instance_method(&instance, "TestActor", "send", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("requires a message"));
}
#[test]
fn test_actor_instance_stop() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "stop", &[])
.unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_actor_instance_ask_empty() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp.eval_actor_instance_method(&instance, "TestActor", "ask", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("requires a message"));
}
#[test]
fn test_actor_instance_ask_echo() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let msg = Value::Integer(42);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_actor_instance_ask_message_no_handler() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert(
"type".to_string(),
Value::from_string("TestMsg".to_string()),
);
msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: TestMsg".to_string()));
}
#[test]
fn test_actor_instance_unknown_method() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp.eval_actor_instance_method(&instance, "TestActor", "unknown", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Unknown actor method"));
}
#[test]
fn test_process_actor_message_sync_no_handler() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert(
"type".to_string(),
Value::from_string("NoHandler".to_string()),
);
msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp.process_actor_message_sync(&instance, &msg);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No handler found"));
}
#[test]
fn test_process_actor_message_sync_mut_no_handler() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let instance_rc = Arc::new(Mutex::new(instance));
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert(
"type".to_string(),
Value::from_string("NoHandler".to_string()),
);
msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No handler found"));
}
#[test]
fn test_struct_instance_method_not_closure_error() {
let mut interp = make_interpreter();
interp.set_variable("TestStruct::method", Value::Integer(42));
let instance = HashMap::new();
let result = interp.eval_struct_instance_method(&instance, "TestStruct", "method", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("not a method closure"));
}
#[test]
fn test_object_method_missing_type() {
let interp = make_interpreter();
let obj = HashMap::new();
let result = interp.eval_object_method(&obj, "test", &[], true);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("missing __type marker"));
}
#[test]
fn test_object_method_unknown_type() {
let interp = make_interpreter();
let mut obj = HashMap::new();
obj.insert(
"__type".to_string(),
Value::from_string("UnknownType".to_string()),
);
let result = interp.eval_object_method(&obj, "test", &[], true);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Unknown object type"));
}
#[test]
fn test_actor_instance_send_sync_no_handler() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert(
"type".to_string(),
Value::from_string("TestMsg".to_string()),
);
msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp.eval_actor_instance_method(&instance, "TestActor", "send", &[msg]);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("No handler found"));
}
#[test]
fn test_actor_instance_ask_message_object_wrong_type() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("NotMessage".to_string()),
);
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_struct_instance_method_closure_not_found() {
let mut interp = make_interpreter();
interp.set_variable("Point::display", Value::Integer(42));
let instance = HashMap::new();
let result = interp.eval_struct_instance_method(&instance, "Point", "display", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("not a method closure"));
}
#[test]
fn test_process_actor_message_sync_with_handler() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let handler = make_handler("TestMsg", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("TestMsg", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_process_actor_message_sync_mut_with_handler() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::String("success".to_string())));
let handler = make_handler("Ping", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Ping", vec![]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::from_string("success".to_string()));
}
#[test]
fn test_process_actor_message_sync_mut_type_validation_pass() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(100, None)));
let handler =
make_handler_with_types("SetValue", vec!["value".to_string()], vec!["i32"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetValue", vec![Value::Integer(42)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_process_actor_message_sync_mut_type_validation_fail() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(100, None)));
let handler =
make_handler_with_types("SetValue", vec!["value".to_string()], vec!["i32"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetValue", vec![Value::from_string("wrong".to_string())]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Type error"));
}
#[test]
fn test_struct_instance_method_wrong_arg_count() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let closure = make_closure(
vec![("self".to_string(), None), ("x".to_string(), None)],
body,
);
interp.set_variable("TestStruct::method", closure);
let instance = HashMap::new();
let result = interp.eval_struct_instance_method(&instance, "TestStruct", "method", &[]);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("expects"));
}
#[test]
fn test_struct_instance_method_success() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(99, None)));
let closure = make_closure(vec![("self".to_string(), None)], body);
interp.set_variable("Point::get_value", closure);
let instance = HashMap::new();
let result = interp
.eval_struct_instance_method(&instance, "Point", "get_value", &[])
.unwrap();
assert_eq!(result, Value::Integer(99));
}
#[test]
fn test_actor_instance_send_simple_value() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::String("handled".to_string())));
let handler = make_handler("Message", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[Value::Integer(42)],
);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_with_params() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(200, None)));
let handler = make_handler("Add", vec!["x".to_string()], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Add", vec![Value::Integer(50)]);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(200));
}
#[test]
fn test_process_actor_message_sync_multiple_handlers() {
let mut interp = make_interpreter();
let body1 = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler1 = make_handler("First", vec![], body1);
let body2 = make_expr(ExprKind::Literal(Literal::Integer(2, None)));
let handler2 = make_handler("Second", vec![], body2);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler1, handler2])),
);
let msg = make_message("Second", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_actor_instance_send_message_object() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Bool(true)));
let handler = make_handler("Ping", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Ping", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "send", &[msg])
.unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_struct_instance_method_fallback() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result =
interp.eval_struct_instance_method(&instance, "Unknown", "unknown_method", &[]);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_mut_any_type() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::String("ok".to_string())));
let handler =
make_handler_with_types("Accept", vec!["value".to_string()], vec!["Any"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Accept", vec![Value::from_string("anything".to_string())]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::from_string("ok".to_string()));
}
#[test]
fn test_process_actor_message_sync_mut_string_type() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler =
make_handler_with_types("SetName", vec!["name".to_string()], vec!["String"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetName", vec![Value::from_string("test".to_string())]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
fn make_ask_handler(message_type: &str, params: Vec<String>, body: Expr) -> Value {
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string(message_type.to_string()),
);
handler_obj.insert(
"params".to_string(),
Value::Array(Arc::from(
params
.iter()
.map(|p| Value::from_string(p.clone()))
.collect::<Vec<_>>(),
)),
);
handler_obj.insert(
"handler".to_string(),
make_closure(params.into_iter().map(|p| (p, None)).collect(), body),
);
Value::Object(Arc::new(handler_obj))
}
#[test]
fn test_actor_ask_with_handler_closure() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(999, None)));
let handler = make_ask_handler("Query", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::Integer(999));
}
#[test]
fn test_actor_ask_with_handler_params() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::String("handled".to_string())));
let handler = make_ask_handler("Greet", vec!["name".to_string()], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Greet", vec![Value::from_string("Alice".to_string())]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("handled".to_string()));
}
#[test]
fn test_actor_ask_message_with_data_no_handler() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler = make_ask_handler("OtherMsg", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("TestQuery", vec![Value::Integer(42)]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(
result,
Value::from_string("Received: TestQuery".to_string())
);
}
#[test]
fn test_actor_ask_handlers_not_array() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert("__handlers".to_string(), Value::Integer(42));
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_ask_handler_not_object() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![
Value::Integer(123), ])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_ask_handler_missing_message_type() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert("handler".to_string(), Value::Integer(1));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_ask_handler_type_mismatch() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler = make_ask_handler("DifferentType", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_ask_handler_missing_closure() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Query".to_string()),
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_ask_message_missing_type_field() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_actor_ask_message_missing_data_field() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert("type".to_string(), Value::from_string("Query".to_string()));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_actor_ask_message_type_not_string() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert("type".to_string(), Value::Integer(123)); msg_obj.insert("data".to_string(), Value::Array(Arc::from(vec![])));
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_actor_ask_message_data_not_array() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Message".to_string()),
);
msg_obj.insert("type".to_string(), Value::from_string("Query".to_string()));
msg_obj.insert("data".to_string(), Value::Integer(42)); let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_process_actor_message_sync_handler_body_not_closure() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Test".to_string()),
);
handler_obj.insert("body".to_string(), Value::Integer(42));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_mut_handler_body_not_closure() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Test".to_string()),
);
handler_obj.insert("body".to_string(), Value::Integer(42));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_handler_missing_type() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
handler_obj.insert("body".to_string(), make_closure(vec![], body));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_mut_handler_missing_type() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
handler_obj.insert("body".to_string(), make_closure(vec![], body));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_handler_not_object() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![
Value::Integer(42), ])),
);
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_mut_handler_not_object() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![
Value::Integer(42), ])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_handler_type_not_string() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert("message_type".to_string(), Value::Integer(123)); let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
handler_obj.insert("body".to_string(), make_closure(vec![], body));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Test", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg);
assert!(result.is_err());
}
#[test]
fn test_struct_instance_method_with_args() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let closure = make_closure(
vec![
("self".to_string(), None),
("x".to_string(), None),
("y".to_string(), None),
],
body,
);
interp.set_variable("TestStruct::method", closure);
let instance = HashMap::new();
let result = interp
.eval_struct_instance_method(
&instance,
"TestStruct",
"method",
&[Value::Integer(1), Value::Integer(2)],
)
.unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_object_method_with_args() {
let interp = make_interpreter();
let mut obj = HashMap::new();
obj.insert(
"__type".to_string(),
Value::from_string("SomeType".to_string()),
);
let result = interp.eval_object_method(&obj, "method", &[Value::Integer(1)], false);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_with_fields() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let handler = make_handler("Query", vec![], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
instance.insert("count".to_string(), Value::Integer(10)); instance.insert("__private".to_string(), Value::Integer(20));
let msg = make_message("Query", vec![]);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_process_actor_message_sync_mut_float_type() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler =
make_handler_with_types("SetFloat", vec!["value".to_string()], vec!["f64"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetFloat", vec![Value::Float(3.14)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_mut_bool_type() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler =
make_handler_with_types("SetBool", vec!["value".to_string()], vec!["bool"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetBool", vec![Value::Bool(true)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_mut_float_type_mismatch() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler =
make_handler_with_types("SetFloat", vec!["value".to_string()], vec!["f64"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetFloat", vec![Value::Integer(42)]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Type error"));
}
#[test]
fn test_process_actor_message_sync_mut_str_type_alias() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler =
make_handler_with_types("SetStr", vec!["value".to_string()], vec!["str"], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("SetStr", vec![Value::from_string("hello".to_string())]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_mut_multiple_params() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(100, None)));
let handler = make_handler_with_types(
"MultiParam",
vec!["a".to_string(), "b".to_string()],
vec!["i32", "String"],
body,
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message(
"MultiParam",
vec![Value::Integer(1), Value::from_string("test".to_string())],
);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_process_actor_message_sync_multiple_params() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(200, None)));
let handler = make_handler(
"MultiParam",
vec!["a".to_string(), "b".to_string(), "c".to_string()],
body,
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message(
"MultiParam",
vec![Value::Integer(1), Value::Integer(2), Value::Integer(3)],
);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(200));
}
#[test]
fn test_process_actor_message_sync_mut_param_types_not_array() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Test".to_string()),
);
handler_obj.insert("param_types".to_string(), Value::Integer(42)); handler_obj.insert(
"body".to_string(),
make_closure(vec![("x".to_string(), None)], body),
);
let handler = Value::Object(Arc::new(handler_obj));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![Value::Integer(1)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_mut_param_type_not_string() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Test".to_string()),
);
handler_obj.insert(
"param_types".to_string(),
Value::Array(Arc::from(vec![
Value::Integer(42), ])),
);
handler_obj.insert(
"body".to_string(),
make_closure(vec![("x".to_string(), None)], body),
);
let handler = Value::Object(Arc::new(handler_obj));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![Value::Integer(1)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_mut_custom_type() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler = make_handler_with_types(
"CustomType",
vec!["value".to_string()],
vec!["MyCustomType"],
body,
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("CustomType", vec![Value::Integer(42)]);
let result = interp.process_actor_message_sync_mut(&instance_rc, &msg);
assert!(result.is_err());
}
#[test]
fn test_process_actor_message_sync_mut_fewer_args() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler = make_handler_with_types(
"Test",
vec!["a".to_string(), "b".to_string()],
vec!["i32", "i32"],
body,
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let instance_rc = Arc::new(Mutex::new(instance));
let msg = make_message("Test", vec![Value::Integer(1)]);
let result = interp
.process_actor_message_sync_mut(&instance_rc, &msg)
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_process_actor_message_sync_fewer_args() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler = make_handler("Test", vec!["a".to_string(), "b".to_string()], body);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let msg = make_message("Test", vec![Value::Integer(1)]);
let result = interp.process_actor_message_sync(&instance, &msg).unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_actor_ask_multiple_handlers_second_matches() {
let mut interp = make_interpreter();
let body1 = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let handler1 = make_ask_handler("First", vec![], body1);
let body2 = make_expr(ExprKind::Literal(Literal::Integer(2, None)));
let handler2 = make_ask_handler("Second", vec![], body2);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler1, handler2])),
);
let msg = make_message("Second", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_struct_instance_method_extra_args_ignored() {
let mut interp = make_interpreter();
let body = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let closure = make_closure(
vec![("self".to_string(), None), ("x".to_string(), None)],
body,
);
interp.set_variable("TestStruct::method", closure);
let instance = HashMap::new();
let result = interp
.eval_struct_instance_method(&instance, "TestStruct", "method", &[Value::Integer(1)])
.unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_actor_ask_handler_value_not_closure() {
let mut interp = make_interpreter();
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Query".to_string()),
);
handler_obj.insert("handler".to_string(), Value::Integer(42));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![Value::Object(Arc::new(handler_obj))])),
);
let msg = make_message("Query", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Query".to_string()));
}
#[test]
fn test_actor_stop_method() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "stop", &[])
.unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_actor_send_empty_args_error() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result =
interp.eval_actor_instance_method(&instance, "TestActor", "send", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("send() requires a message argument"));
}
#[test]
fn test_actor_ask_empty_args_error() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result =
interp.eval_actor_instance_method(&instance, "TestActor", "ask", &[]);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("ask() requires a message argument"));
}
#[test]
fn test_actor_send_simple_value_sync() {
let mut interp = make_interpreter();
let handler = make_handler(
"Message",
vec!["data".to_string()],
make_expr(ExprKind::Literal(Literal::Integer(42, None))),
);
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler])),
);
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[Value::Integer(100)],
);
assert!(result.is_err(), "Should reject non-Message value");
let err_msg = result.unwrap_err().to_string();
assert!(
err_msg.contains("Invalid message format"),
"Error should mention invalid message format: {err_msg}"
);
}
#[test]
fn test_actor_send_with_object_msg_non_message_type() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![])),
);
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("SomethingElse".to_string()),
);
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[msg],
);
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_actor_ask_with_non_object_msg() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let result = interp
.eval_actor_instance_method(
&instance,
"TestActor",
"ask",
&[Value::Integer(42)],
);
assert!(result.is_ok() || result.is_err());
}
#[test]
fn test_actor_ask_with_handler_closure_cov() {
let mut interp = make_interpreter();
let handler_body = make_expr(ExprKind::Literal(Literal::Integer(99, None)));
let handler_closure = make_closure(
vec![("name".to_string(), None)],
handler_body,
);
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("Greet".to_string()),
);
handler_obj.insert("handler".to_string(), handler_closure);
let handler_value = Value::Object(Arc::new(handler_obj));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler_value])),
);
let msg = make_message("Greet", vec![Value::from_string("Alice".to_string())]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::Integer(99));
}
#[test]
fn test_actor_ask_no_matching_handler_cov() {
let mut interp = make_interpreter();
let handler_body = make_expr(ExprKind::Literal(Literal::Integer(0, None)));
let handler_closure = make_closure(vec![], handler_body);
let mut handler_obj = HashMap::new();
handler_obj.insert(
"message_type".to_string(),
Value::from_string("OtherMsg".to_string()),
);
handler_obj.insert("handler".to_string(), handler_closure);
let handler_value = Value::Object(Arc::new(handler_obj));
let mut instance = HashMap::new();
instance.insert(
"__handlers".to_string(),
Value::Array(Arc::from(vec![handler_value])),
);
let msg = make_message("Greet", vec![]);
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg])
.unwrap();
assert_eq!(result, Value::from_string("Received: Greet".to_string()));
}
#[test]
fn test_actor_ask_obj_not_message_type_cov() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("NotMessage".to_string()),
);
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_actor_ask_obj_no_type_field_cov() {
let mut interp = make_interpreter();
let instance = HashMap::new();
let msg_obj = HashMap::new();
let msg = Value::Object(Arc::new(msg_obj));
let result = interp
.eval_actor_instance_method(&instance, "TestActor", "ask", &[msg.clone()])
.unwrap();
assert_eq!(result, msg);
}
#[test]
fn test_actor_send_simple_to_async_cov() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__actor_id".to_string(),
Value::from_string("nonexistent_actor_cov_1".to_string()),
);
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[Value::Integer(42)],
);
assert!(result.is_err());
}
#[test]
fn test_actor_send_message_obj_to_async_cov() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__actor_id".to_string(),
Value::from_string("nonexistent_actor_cov_2".to_string()),
);
let msg = make_message("Ping", vec![Value::from_string("data".to_string())]);
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[msg],
);
assert!(result.is_err());
}
#[test]
fn test_actor_send_obj_no_type_to_async_cov() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__actor_id".to_string(),
Value::from_string("nonexistent_cov_3".to_string()),
);
let msg_obj = HashMap::new();
let msg = Value::Object(Arc::new(msg_obj));
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[msg],
);
assert!(result.is_err());
}
#[test]
fn test_actor_send_obj_not_message_type_to_async_cov() {
let mut interp = make_interpreter();
let mut instance = HashMap::new();
instance.insert(
"__actor_id".to_string(),
Value::from_string("nonexistent_cov_4".to_string()),
);
let mut msg_obj = HashMap::new();
msg_obj.insert(
"__type".to_string(),
Value::from_string("Other".to_string()),
);
let msg = Value::Object(Arc::new(msg_obj));
let result = interp.eval_actor_instance_method(
&instance,
"TestActor",
"send",
&[msg],
);
assert!(result.is_err());
}