1crate::ix!();
3
4impl TreeDepthMeasurer for Skeleton {
5 fn measure_tree_depth(&self) -> u8 {
6 trace!("Computing skeleton depth using BFS/DFS approach with cycle detection.");
7
8 let root_id = match self.root_id() {
9 Some(rid) => rid,
10 None => {
11 trace!("No root_id found => depth=0");
12 return 0;
13 }
14 };
15
16 let root_node = match self.nodes().iter().find(|n| n.id() == *root_id) {
18 Some(r) => r,
19 None => {
20 trace!("root_id is invalid => depth=0");
21 return 0;
22 }
23 };
24
25 use std::collections::HashSet;
26 let mut visited = HashSet::new();
27
28 let mut stack = vec![(root_node.id(), 1u8)];
29 let mut max_depth = 1;
30
31 let index_of = |id: u16| -> Option<usize> {
32 self.nodes().iter().position(|n| n.id() == id)
33 };
34
35 while let Some((nid, lvl)) = stack.pop() {
36 if !visited.insert(nid) {
37 trace!("Node {} already visited => skipping", nid);
38 continue;
39 }
40 if lvl > max_depth {
41 max_depth = lvl;
42 }
43 let node_idx = match index_of(nid) {
44 Some(idx) => idx,
45 None => {
46 trace!("Node {} not found => skipping children", nid);
47 continue;
48 }
49 };
50 let node = &self.nodes()[node_idx];
51
52 for &child_id in node.child_ids() {
53 let next_level = match lvl.checked_add(1) {
54 Some(l) => l,
55 None => {
56 trace!("Overflow in level => capping at 255");
57 return 255;
58 }
59 };
60 stack.push((child_id, next_level));
61 }
62 }
63
64 max_depth
65 }
66}
67
68#[cfg(test)]
69mod skeleton_depth_measurer_assessment {
70 use super::*;
71
72 #[traced_test]
73 fn check_empty_skeleton_produces_depth_zero() {
74 trace!("Creating an empty Skeleton (no nodes)...");
75 let skel = SkeletonBuilder::default()
76 .build()
77 .expect("Should build empty Skeleton");
78
79 trace!("Measuring tree depth on the empty Skeleton...");
80 let depth = skel.measure_tree_depth();
81 info!("Measured depth: {}", depth);
82
83 assert_eq!(depth, 0, "Depth should be 0 for an empty Skeleton");
84 }
85
86 #[traced_test]
87 fn check_linear_chain_skeleton_produces_correct_depth() {
88 trace!("Constructing a simple linear chain: 0 -> 1 -> 2 => depth=3");
89
90 let n0 = SkeletonNodeBuilder::default()
91 .id(0_u16)
92 .child_ids(vec![1_u16])
93 .name("root")
94 .original_key("root")
95 .build(NodeKind::Dispatch)
96 .unwrap();
97 let n1 = SkeletonNodeBuilder::default()
98 .id(1_u16)
99 .child_ids(vec![2_u16])
100 .name("child")
101 .original_key("child")
102 .build(NodeKind::Dispatch)
103 .unwrap();
104 let n2 = SkeletonNodeBuilder::default()
105 .id(2_u16)
106 .name("grandchild")
107 .original_key("grandchild")
108 .build(NodeKind::LeafHolder)
109 .unwrap();
110
111 let skel = SkeletonBuilder::default()
112 .nodes(vec![n0, n1, n2])
113 .root_id(Some(0_u16))
114 .build()
115 .unwrap();
116
117 trace!("Measuring depth...");
118 let depth = skel.measure_tree_depth();
119 info!("Measured depth: {}", depth);
120
121 assert_eq!(depth, 3, "Expected depth=3 in a linear chain of three nodes");
122 }
123
124 #[traced_test]
125 fn test_compute_skeleton_depth() {
126 let root = SkeletonNodeBuilder::default()
128 .id(0_u16)
129 .child_ids(vec![1])
130 .name("root")
131 .original_key("root")
132 .build(NodeKind::Dispatch)
133 .unwrap();
134
135 let child = SkeletonNodeBuilder::default()
136 .id(1_u16)
137 .child_ids(vec![2])
138 .name("child")
139 .original_key("child")
140 .build(NodeKind::Dispatch)
141 .unwrap();
142
143 let grandchild = SkeletonNodeBuilder::default()
144 .id(2_u16)
145 .name("grandchild")
146 .original_key("grandchild")
147 .build(NodeKind::LeafHolder)
148 .unwrap();
149
150 let skeleton = SkeletonBuilder::default()
151 .nodes(vec![root, child, grandchild])
152 .root_id(Some(0))
153 .build()
154 .unwrap();
155
156 let depth = skeleton.measure_tree_depth();
157 assert_eq!(depth, 3, "Expect depth=3");
158 }
159
160 fn make_node(
163 id: u16,
164 parent_id: Option<u16>,
165 child_ids: &[u16],
166 leaf_count: u16,
167 name: &str
168 ) -> SkeletonNode {
169 let k = if child_ids.is_empty() {
171 NodeKind::LeafHolder
172 } else {
173 NodeKind::Dispatch
174 };
175 SkeletonNodeBuilder::default()
176 .id(id)
177 .parent_id(parent_id)
178 .child_ids(child_ids.to_vec())
179 .leaf_count(leaf_count)
180 .name(name.to_string())
181 .original_key(name.to_string())
182 .build(k)
183 .unwrap()
184 }
185
186 fn make_skeleton(nodes: Vec<SkeletonNode>, root_id: Option<u16>) -> Skeleton {
187 SkeletonBuilder::default()
188 .nodes(nodes)
189 .root_id(root_id)
190 .build()
191 .unwrap()
192 }
193
194 #[traced_test]
195 fn test_depth_no_nodes() {
196 let skeleton = make_skeleton(vec![], None);
197 let depth = skeleton.measure_tree_depth();
198 assert_eq!(depth, 0, "No nodes => depth=0");
199 }
200
201 #[traced_test]
202 fn test_depth_no_root_id() {
203 let n1 = make_node(1, None, &[], 0, "n1");
205 let skeleton = make_skeleton(vec![n1], None);
206 let depth = skeleton.measure_tree_depth();
207 assert_eq!(depth, 0, "Missing root_id => depth=0");
208 }
209
210 #[traced_test]
211 fn test_depth_invalid_root_id() {
212 let n0 = make_node(0, None, &[], 0, "RootButNotActuallyUsed");
213 let skeleton = make_skeleton(vec![n0], Some(999));
214 let depth = skeleton.measure_tree_depth();
215 assert_eq!(depth, 0, "Invalid root => depth=0");
216 }
217
218 #[traced_test]
219 fn test_depth_single_node() {
220 let root_node = make_node(10, None, &[], 0, "SingleNode");
221 let skeleton = make_skeleton(vec![root_node], Some(10));
222 let depth = skeleton.measure_tree_depth();
223 assert_eq!(depth, 1, "A single root node => depth=1");
224 }
225
226 #[traced_test]
227 fn test_depth_linear_chain_three() {
228 let root = make_node(0, None, &[1], 0, "root");
229 let child = make_node(1, Some(0), &[2], 0, "child");
230 let grandchild = make_node(2, Some(1), &[], 0, "grandchild");
231
232 let skeleton = make_skeleton(vec![root, child, grandchild], Some(0));
233 let depth = skeleton.measure_tree_depth();
234 assert_eq!(depth, 3, "Expect depth=3 for linear chain root->child->grandchild");
235 }
236
237 #[traced_test]
238 fn test_depth_multiple_branches() {
239 let n0 = make_node(0, None, &[1,2], 0, "root");
242 let n1 = make_node(1, Some(0), &[3], 0, "branchA");
243 let n2 = make_node(2, Some(0), &[4,5], 0, "branchB");
244 let n3 = make_node(3, Some(1), &[], 0, "leafA");
245 let n4 = make_node(4, Some(2), &[6], 0, "midNode");
246 let n5 = make_node(5, Some(2), &[], 0, "leafB");
247 let n6 = make_node(6, Some(4), &[], 0, "deepLeafC");
248
249 let skeleton = make_skeleton(vec![n0,n1,n2,n3,n4,n5,n6], Some(0));
250 let depth = skeleton.measure_tree_depth();
251 assert_eq!(depth, 4, "Deepest path is root->2->4->6 => 4 levels");
252 }
253
254 #[traced_test]
255 fn test_depth_with_cycle() {
256 let n0 = make_node(0, None, &[1], 0, "root");
258 let n1 = make_node(1, Some(0), &[0], 0, "childWithCycle");
259
260 let skeleton = make_skeleton(vec![n0, n1], Some(0));
261 let depth = skeleton.measure_tree_depth();
262 eprintln!("Depth with cycle => {}", depth);
263 assert!(depth > 0, "At least root => depth≥1 in cyc case if we break");
264 }
265
266 #[traced_test]
267 fn test_depth_with_invalid_child_id() {
268 let root = make_node(0, None, &[1,999], 0, "root");
269 let child = make_node(1, Some(0), &[], 0, "validChild");
270 let skeleton = make_skeleton(vec![root, child], Some(0));
271 let depth = skeleton.measure_tree_depth();
272 assert_eq!(depth, 2, "root->child => depth=2, ignoring child=999");
273 }
274
275 #[traced_test]
276 fn test_depth_with_leaf_count() {
277 let root = SkeletonNodeBuilder::default()
278 .id(0_u16)
279 .child_ids(vec![1])
280 .leaf_count(5_u16)
281 .name("root")
282 .original_key("root")
283 .build(NodeKind::Dispatch)
284 .unwrap();
285 let child = SkeletonNodeBuilder::default()
286 .id(1_u16)
287 .leaf_count(3_u16)
288 .name("child")
289 .original_key("child")
290 .build(NodeKind::LeafHolder)
291 .unwrap();
292
293 let skeleton = SkeletonBuilder::default()
294 .nodes(vec![root, child])
295 .root_id(Some(0))
296 .build()
297 .unwrap();
298
299 let depth = skeleton.measure_tree_depth();
300 assert_eq!(depth, 2, "leaf_count is irrelevant to structural BFS => depth=2");
301 }
302
303 #[traced_test]
304 fn test_depth_multi_root_scenario() {
305 let n0 = make_node(0, None, &[], 0, "primaryRoot");
306 let n10 = make_node(10, None, &[], 0, "secondaryRootIgnored");
307 let skeleton = make_skeleton(vec![n0, n10], Some(0));
308 let depth = skeleton.measure_tree_depth();
309 assert_eq!(depth, 1, "We only measure from root_id=0 => ignoring node(10) as root");
310 }
311
312 #[traced_test]
313 fn check_branching_skeleton_produces_correct_depth() {
314 let root_node = SkeletonNodeBuilder::default()
316 .id(0_u16)
317 .child_ids(vec![1, 2])
318 .name("root")
319 .original_key("root")
320 .build(NodeKind::Dispatch)
321 .unwrap();
322 let child_a = SkeletonNodeBuilder::default()
323 .id(1_u16)
324 .child_ids(vec![3])
325 .name("childA")
326 .original_key("childA")
327 .build(NodeKind::Dispatch)
328 .unwrap();
329 let child_b = SkeletonNodeBuilder::default()
330 .id(2_u16)
331 .name("childB")
332 .original_key("childB")
333 .build(NodeKind::LeafHolder)
334 .unwrap();
335 let grandchild = SkeletonNodeBuilder::default()
336 .id(3_u16)
337 .name("grandchild")
338 .original_key("grandchild")
339 .build(NodeKind::LeafHolder)
340 .unwrap();
341
342 let skel = SkeletonBuilder::default()
343 .nodes(vec![root_node, child_a, child_b, grandchild])
344 .root_id(Some(0))
345 .build()
346 .unwrap();
347
348 let depth = skel.measure_tree_depth();
349 debug!("Measured depth: {}", depth);
350 assert_eq!(depth, 3, "root -> childA -> grandchild => 3 levels deep");
351 }
352}