use bonsai_bt::Behavior::{
self, Action, AlwaysSucceed, If, Invert, Select, Sequence, Wait, WaitForever, While, WhileAll,
};
#[derive(Clone, Debug)]
enum Act {
A,
B,
C,
D,
}
#[test]
fn node_metas_subtree_sizes() {
use bonsai_bt::Action;
use Act::*;
let behavior = Sequence(vec![Action(A), Sequence(vec![Action(B), Action(C)]), Action(D)]);
let metas = bonsai_bt::telemetry::build_node_metas(&behavior);
assert_eq!(metas.len(), 6, "tree has 6 nodes");
assert_eq!(metas[0].subtree_size, 6, "outer Sequence spans all 6 nodes");
assert_eq!(metas[1].subtree_size, 1, "Action(A) is a leaf");
assert_eq!(metas[2].subtree_size, 3, "inner Sequence spans 3 nodes");
assert_eq!(metas[3].subtree_size, 1, "Action(B) is a leaf");
assert_eq!(metas[4].subtree_size, 1, "Action(C) is a leaf");
assert_eq!(metas[5].subtree_size, 1, "Action(D) is a leaf");
}
#[test]
fn node_metas_ids_match_tree_definition() {
use bonsai_bt::telemetry::{build_node_metas, TreeDefinition};
use bonsai_bt::Action;
use Act::*;
let behavior = Sequence(vec![Action(A), Sequence(vec![Action(B), Action(C)]), Action(D)]);
let metas = build_node_metas(&behavior);
let def = TreeDefinition::build(&behavior);
fn collect_ids(node: &bonsai_bt::telemetry::TreeNode, ids: &mut Vec<usize>) {
ids.push(node.id);
for child in &node.children {
collect_ids(child, ids);
}
}
let mut ids = Vec::new();
collect_ids(&def.root, &mut ids);
assert_eq!(ids.len(), metas.len(), "same number of nodes");
for (idx, id) in ids.iter().enumerate() {
assert_eq!(*id, idx, "preorder index {idx} must equal TreeDefinition id");
}
}
#[test]
fn node_metas_subtree_sizes_all_variants() {
use bonsai_bt::telemetry::build_node_metas;
use Act::*;
let cases: Vec<(Behavior<Act>, Vec<usize>)> = vec![
(Action(A), vec![1]),
(Wait(0.5), vec![1]),
(WaitForever, vec![1]),
(Sequence(vec![]), vec![1]),
(Invert(Box::new(Action(A))), vec![2, 1]),
(AlwaysSucceed(Box::new(Action(A))), vec![2, 1]),
(
If(Box::new(Action(A)), Box::new(Action(B)), Box::new(Action(C))),
vec![4, 1, 1, 1],
),
(
If(
Box::new(Action(A)),
Box::new(Sequence(vec![Action(B), Action(C)])),
Box::new(Action(D)),
),
vec![6, 1, 3, 1, 1, 1],
),
(While(Box::new(Action(A)), vec![Action(B)]), vec![3, 1, 1]),
(While(Box::new(Action(A)), vec![Action(B), Action(C)]), vec![4, 1, 1, 1]),
(WhileAll(Box::new(Action(A)), vec![Action(B)]), vec![3, 1, 1]),
];
for (i, (behavior, expected)) in cases.into_iter().enumerate() {
let metas = build_node_metas(&behavior);
let got: Vec<usize> = metas.iter().map(|m| m.subtree_size).collect();
assert_eq!(got, expected, "case {i}");
}
}
#[test]
fn memoryless_variants_appear_in_tree_definition() {
use bonsai_bt::telemetry::TreeDefinition;
use Act::{A, B, C};
let tree: Behavior<Act> = Sequence(vec![Action(A), Select(vec![Action(B), Action(C)]).memory(false)]).memory(false);
let def = TreeDefinition::build(&tree);
assert_eq!(def.root.node_type, "MemorylessSequence");
assert_eq!(def.root.children.len(), 2);
assert_eq!(def.root.children[0].node_type, "Action");
assert_eq!(def.root.children[1].node_type, "MemorylessSelector");
assert_eq!(def.root.children[1].children.len(), 2);
}