use async_trait::async_trait;
use mecha10_behavior_runtime::prelude::*;
#[derive(Debug)]
struct TestBehavior {
name: String,
_speed: f64,
}
#[async_trait]
impl BehaviorNode for TestBehavior {
async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
Ok(NodeStatus::Success)
}
fn name(&self) -> &str {
&self.name
}
}
fn create_test_registry() -> NodeRegistry {
let mut registry = NodeRegistry::new();
registry.register("test_behavior", |config| {
let _speed = config.get("speed").and_then(|v| v.as_f64()).unwrap_or(1.0);
Ok(Box::new(TestBehavior {
name: "test_behavior".to_string(),
_speed,
}))
});
registry.register("move", |config| {
let _speed = config.get("speed").and_then(|v| v.as_f64()).unwrap_or(1.0);
Ok(Box::new(TestBehavior {
name: "move".to_string(),
_speed,
}))
});
registry
}
#[test]
fn test_load_simple_node() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "node",
"node": "test_behavior"
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "test_behavior");
}
#[test]
fn test_load_sequence() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "sequence",
"children": [
{
"type": "node",
"node": "test_behavior"
},
{
"type": "node",
"node": "move"
}
]
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "sequence");
}
#[test]
fn test_load_with_config_ref() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "node",
"node": "move",
"config_ref": "fast_move"
},
"configs": {
"fast_move": {
"speed": 2.5
}
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "move");
}
#[test]
fn test_load_with_inline_config() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "node",
"node": "move",
"config": {
"speed": 3.0
}
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "move");
}
#[test]
fn test_load_nested_composition() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "selector",
"children": [
{
"type": "sequence",
"children": [
{
"type": "node",
"node": "test_behavior"
}
]
},
{
"type": "node",
"node": "move"
}
]
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "selector");
}
#[test]
fn test_load_parallel() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "parallel",
"policy": "require_all",
"children": [
{
"type": "node",
"node": "test_behavior"
},
{
"type": "node",
"node": "move"
}
]
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "parallel");
}
#[test]
fn test_load_missing_node_type() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "node",
"node": "unknown_behavior"
}
}"#;
let result = loader.load_from_json(json);
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains("not registered") || error_msg.contains("unknown_behavior"),
"Expected error about unregistered node, got: {}",
error_msg
);
}
#[test]
fn test_load_missing_config_ref() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "node",
"node": "move",
"config_ref": "missing_config"
}
}"#;
let result = loader.load_from_json(json);
assert!(result.is_err());
let error_msg = format!("{:?}", result.unwrap_err());
assert!(
error_msg.contains("not found") || error_msg.contains("missing_config"),
"Expected error about missing config, got: {}",
error_msg
);
}
#[test]
fn test_empty_sequence() {
let registry = create_test_registry();
let loader = BehaviorLoader::new(registry);
let json = r#"{
"name": "test",
"root": {
"type": "sequence",
"children": []
}
}"#;
let behavior = loader.load_from_json(json).unwrap();
assert_eq!(behavior.name(), "sequence");
}