use crate::IntentPacket;
#[derive(Debug, Clone)]
pub struct IntentNode {
pub intent: IntentPacket,
pub children: Vec<IntentNode>,
}
impl IntentNode {
pub fn leaf(intent: IntentPacket) -> Self {
Self {
intent,
children: Vec::new(),
}
}
pub fn walk<'a>(&'a self, f: &mut impl FnMut(&'a IntentNode)) {
f(self);
for child in &self.children {
child.walk(f);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::{Duration, Utc};
fn future() -> chrono::DateTime<Utc> {
Utc::now() + Duration::hours(1)
}
#[test]
fn leaf_has_no_children() {
let node = IntentNode::leaf(IntentPacket::new("task", future()));
assert!(node.children.is_empty());
assert_eq!(node.intent.outcome, "task");
}
#[test]
fn walk_visits_single_leaf() {
let node = IntentNode::leaf(IntentPacket::new("only", future()));
let mut visited = Vec::new();
node.walk(&mut |n| visited.push(n.intent.outcome.clone()));
assert_eq!(visited, vec!["only"]);
}
#[test]
fn walk_visits_depth_first() {
let child_a = IntentNode::leaf(IntentPacket::new("a", future()));
let child_b = IntentNode::leaf(IntentPacket::new("b", future()));
let grandchild = IntentNode::leaf(IntentPacket::new("gc", future()));
let child_c = IntentNode {
intent: IntentPacket::new("c", future()),
children: vec![grandchild],
};
let root = IntentNode {
intent: IntentPacket::new("root", future()),
children: vec![child_a, child_b, child_c],
};
let mut visited = Vec::new();
root.walk(&mut |n| visited.push(n.intent.outcome.clone()));
assert_eq!(visited, vec!["root", "a", "b", "c", "gc"]);
}
#[test]
fn walk_empty_tree() {
let root = IntentNode::leaf(IntentPacket::new("alone", future()));
let mut count = 0;
root.walk(&mut |_| count += 1);
assert_eq!(count, 1);
}
#[test]
fn walk_deep_tree() {
let mut current = IntentNode::leaf(IntentPacket::new("leaf", future()));
for i in 0..10 {
current = IntentNode {
intent: IntentPacket::new(format!("level-{i}"), future()),
children: vec![current],
};
}
let mut count = 0;
current.walk(&mut |_| count += 1);
assert_eq!(count, 11);
}
#[test]
fn walk_wide_tree() {
let children: Vec<IntentNode> = (0..5)
.map(|i| IntentNode::leaf(IntentPacket::new(format!("child-{i}"), future())))
.collect();
let root = IntentNode {
intent: IntentPacket::new("root", future()),
children,
};
let mut count = 0;
root.walk(&mut |_| count += 1);
assert_eq!(count, 6);
}
#[test]
fn clone_preserves_structure() {
let child = IntentNode::leaf(IntentPacket::new("child", future()));
let parent = IntentNode {
intent: IntentPacket::new("parent", future()),
children: vec![child],
};
let cloned = parent.clone();
assert_eq!(cloned.children.len(), 1);
assert_eq!(cloned.children[0].intent.outcome, "child");
}
}