diff --git a/src/diagnostic_status.rs b/src/diagnostic_status.rs index c87a32f..63e5112 100644 --- a/src/diagnostic_status.rs +++ b/src/diagnostic_status.rs @@ -38,9 +38,11 @@ impl DiagnosticStatus { hardware_id: String, values: BTreeMap, ) -> Self { + let cleaned_name = Self::clean_name(&name); + Self { level: level, - name: name, + name: cleaned_name, message: message, hardware_id: hardware_id, values: values, @@ -132,6 +134,15 @@ impl DiagnosticStatus { to_return.name = self.get_child_name(); return to_return; } + + fn clean_name(name: &str) -> String { + // Remove prefix "/" + let without_prefix = name.strip_prefix("/").unwrap_or(name); + // and suffix + let without_suffix = name.strip_suffix("/").unwrap_or(without_prefix); + + return without_suffix.to_owned(); + } } #[cfg(test)] @@ -180,4 +191,24 @@ mod tests { assert!(parent_names[1] == "b"); assert!(child_name == "c"); } + + #[test] + fn diagnostic_name_cleaning() { + let level = DiagnosticLevel::OK; + let name = "/a"; + let message = "I'm ok"; + let hardware_id = ""; + let values = BTreeMap::::new(); + + let diag_status = DiagnosticStatus::new( + level, + name.to_owned(), + message.to_owned(), + hardware_id.to_owned(), + values, + ); + + assert!(diag_status.name_is_basic()); + assert!(diag_status.name() == "a"); + } } diff --git a/src/lib.rs b/src/lib.rs index 6d9b1ad..898ab94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,22 @@ impl DiagnosticGraph { Ok(result) } + pub fn child_of_with_name( + &self, + parent: &limbo_graph::Key, + desired_child_name: &str, + ) -> anyhow::Result> { + let all_children = self.children_of(parent)?; + for child in all_children.iter() { + let child_name = self.value_of(&child)?.name(); + if child_name == desired_child_name { + return Ok(Some(child.clone())); + } + } + + return Ok(None); + } + pub fn add_status(&mut self, status: DiagnosticStatus) -> anyhow::Result<()> { // If I'm basic I just need to be added as a child of the root. if status.name_is_basic() { @@ -105,6 +121,8 @@ impl DiagnosticGraph { 'parent_loop: for parent_name in parent_names.iter() { let children = self.graph.children_of(&cur_key)?; + // There are no children of this parent, so we can add + // the parent and go to the next parent. if children.len() == 0 { let holder_for_parent = DiagnosticStatus::from_name(parent_name.clone()); cur_key = self @@ -112,11 +130,13 @@ impl DiagnosticGraph { .add(DiagnosticNode::DiagnosticStatus(holder_for_parent), cur_key)?; continue 'parent_loop; } - 'child_loop: for child in children { + // This parent does have children, look at them and + // update loop if appropriate. + for child in children { let child_node = self.graph.value_of(&child)?; if child_node.is_root() { - // child node can't be root, but we'll catch here anyway. - continue 'child_loop; + // A child node can't be root. + return Err(anyhow!("A child node can't be root!")); } if child_node.value().unwrap().name() == *parent_name { // The child node matched the parent we were looking for. @@ -133,11 +153,34 @@ impl DiagnosticGraph { .add(DiagnosticNode::DiagnosticStatus(holder_for_parent), cur_key)?; } // We've updated all the parents, so we can add ourselves now. - self.graph.add( - DiagnosticNode::DiagnosticStatus(status.copy_with_child_name()), - cur_key, - )?; + // Do we already exist as a child of parent? + let children_of_this_parent = self.graph.children_of(&cur_key)?; + let mut names_of_children_of_this_parent = children_of_this_parent.iter().map(|x| { + self.graph + .value_of(&x) + .expect("Given child not in graph.") + .value() + .expect("Given root node as child?") + .name() + }); + let child_in_children_of_this_parent = + names_of_children_of_this_parent.any(|x| x == status.get_child_name()); + if !child_in_children_of_this_parent { + // If we don't we can be added. + self.graph.add( + DiagnosticNode::DiagnosticStatus(status.copy_with_child_name()), + cur_key, + )?; + } + + Ok(()) + } + + pub fn add_status_vec(&mut self, statuses: &Vec) -> anyhow::Result<()> { + for status in statuses { + self.add_status(status.clone())?; + } Ok(()) } } @@ -145,25 +188,27 @@ impl DiagnosticGraph { #[cfg(test)] mod tests { use super::*; + use alloc::vec; - #[test] - fn add_one_to_graph() -> anyhow::Result<()> { + fn make_a_status_with_name(name: &str) -> DiagnosticStatus { let level = DiagnosticLevel::OK; - let name = "/a/b/c"; let message = "I'm ok"; let hardware_id = ""; let values = BTreeMap::::new(); - let diag_status = DiagnosticStatus::new( + DiagnosticStatus::new( level, name.to_owned(), message.to_owned(), hardware_id.to_owned(), values, - ); + ) + } + #[test] + fn add_one_to_graph() -> anyhow::Result<()> { let mut graph = DiagnosticGraph::new(); - graph.add_status(diag_status)?; + graph.add_status(make_a_status_with_name("/a/b/c"))?; let first_child_keys = graph.children_of(&graph.root())?; assert!(first_child_keys.len() == 1); @@ -186,4 +231,43 @@ mod tests { Ok(()) } + + #[test] + fn add_multiple_to_graph() -> anyhow::Result<()> { + let statuses = vec![ + make_a_status_with_name("/a"), + make_a_status_with_name("/a/b"), + make_a_status_with_name("/a/b/c"), + make_a_status_with_name("/a/d/e"), + make_a_status_with_name("/a/d/f"), + make_a_status_with_name("/a/d"), + ]; + + let mut graph = DiagnosticGraph::new(); + graph.add_status_vec(&statuses)?; + + let root_children = graph.children_of(&graph.root())?; + assert!(root_children.len() == 1); + assert!(graph.value_of(&root_children[0])?.name() == "a"); + + let children_of_a = graph.children_of(&root_children[0])?; + let mut children_of_a_names = children_of_a + .iter() + .map(|x| graph.value_of(&x).expect("Value of failed.").name()); + assert!(children_of_a.len() == 2); + assert!(children_of_a_names.any(|x| x == "b")); + assert!(children_of_a_names.any(|x| x == "d")); + + let b_key = graph.child_of_with_name(&root_children[0], "b")?; + assert!(b_key.is_some()); + let b_children = graph.children_of(&b_key.unwrap())?; + assert!(b_children.len() == 1); + + let d_key = graph.child_of_with_name(&root_children[0], "d")?; + assert!(d_key.is_some()); + let d_children = graph.children_of(&d_key.unwrap())?; + assert!(d_children.len() == 2); + + Ok(()) + } }