1use anyhow::{bail, format_err, Error};
11use diagnostics_hierarchy::{
12 ArrayContent, ArrayFormat, ExponentialHistogram, ExponentialHistogramParams, LinearHistogram,
13 LinearHistogramParams, Property, EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS,
14 LINEAR_HISTOGRAM_EXTRA_SLOTS,
15};
16use difference::{Changeset, Difference};
17use num_traits::One;
18use regex::Regex;
19use std::collections::BTreeSet;
20use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
21use std::ops::{Add, AddAssign, MulAssign};
22
23pub use diagnostics_hierarchy::{hierarchy, DiagnosticsHierarchy, DiagnosticsHierarchyGetter};
24
25pub trait JsonGetter<K: Clone + AsRef<str>>: DiagnosticsHierarchyGetter<K> {
26 fn get_pretty_json(&self) -> String {
27 let mut tree = self.get_diagnostics_hierarchy();
28 tree.to_mut().sort();
29 serde_json::to_string_pretty(&tree).expect("pretty json string")
30 }
31
32 fn get_json(&self) -> String {
33 let mut tree = self.get_diagnostics_hierarchy();
34 tree.to_mut().sort();
35 serde_json::to_string(&tree).expect("json string")
36 }
37}
38
39impl<K: Clone + AsRef<str>, T: DiagnosticsHierarchyGetter<K>> JsonGetter<K> for T {}
40
41#[macro_export]
70macro_rules! tree_assertion {
71 (@build $tree_assertion:expr,) => {};
72
73 (@build $tree_assertion:expr, var $key:ident: { $($sub:tt)* }) => {{
75 #[allow(unused_mut)]
76 let mut child_tree_assertion = TreeAssertion::new($key, true);
77 $crate::tree_assertion!(@build child_tree_assertion, $($sub)*);
78 $tree_assertion.add_child_assertion(child_tree_assertion);
79 }};
80 (@build $tree_assertion:expr, var $key:ident: { $($sub:tt)* }, $($rest:tt)*) => {{
81 $crate::tree_assertion!(@build $tree_assertion, var $key: { $($sub)* });
82 $crate::tree_assertion!(@build $tree_assertion, $($rest)*);
83 }};
84
85 (@build $tree_assertion:expr, var $key:ident: contains { $($sub:tt)* }) => {{
87 #[allow(unused_mut)]
88 let mut child_tree_assertion = TreeAssertion::new($key, false);
89 $crate::tree_assertion!(@build child_tree_assertion, $($sub)*);
90 $tree_assertion.add_child_assertion(child_tree_assertion);
91 }};
92 (@build $tree_assertion:expr, var $key:ident: contains { $($sub:tt)* }, $($rest:tt)*) => {{
93 $crate::tree_assertion!(@build $tree_assertion, var $key: contains { $($sub)* });
94 $crate::tree_assertion!(@build $tree_assertion, $($rest)*);
95 }};
96
97 (@build $tree_assertion:expr, var $key:ident: $assertion:expr) => {{
99 $tree_assertion.add_property_assertion($key, Box::new($assertion))
100 }};
101 (@build $tree_assertion:expr, var $key:ident: $assertion:expr, $($rest:tt)*) => {{
102 $crate::tree_assertion!(@build $tree_assertion, var $key: $assertion);
103 $crate::tree_assertion!(@build $tree_assertion, $($rest)*);
104 }};
105
106 (@build $tree_assertion:expr, $key:ident: $($rest:tt)+) => {{
109 let key = stringify!($key);
110 $crate::tree_assertion!(@build $tree_assertion, var key: $($rest)+);
111 }};
112 (@build $tree_assertion:expr, ref $key:path: $($rest:tt)+) => {{
118 let key: &str = $key.as_ref(); $crate::tree_assertion!(@build $tree_assertion, var key: $($rest)+);
120 }};
121 (@build $tree_assertion:expr, $key:tt: $($rest:tt)+) => {{
123 let key: &'static str = $key;
124 $crate::tree_assertion!(@build $tree_assertion, var key: $($rest)+);
125 }};
126 (@build $tree_assertion:expr, $key:expr => $($rest:tt)+) => {{
128 let key_string : String = $key;
129 let key = &key_string;
130 $crate::tree_assertion!(@build $tree_assertion, var key: $($rest)+);
131 }};
132 (@build $tree_assertion:expr, $child_assertion:expr, $($rest:tt)*) => {{
134 $tree_assertion.add_child_assertion($child_assertion);
135 $crate::tree_assertion!(@build $tree_assertion, $($rest)*);
136 }};
137
138 (var $key:ident: { $($sub:tt)* }) => {{
140 use $crate::TreeAssertion;
141 #[allow(unused_mut)]
142 let mut tree_assertion = TreeAssertion::new($key, true);
143 $crate::tree_assertion!(@build tree_assertion, $($sub)*);
144 tree_assertion
145 }};
146 (var $key:ident: contains { $($sub:tt)* }) => {{
147 use $crate::TreeAssertion;
148 #[allow(unused_mut)]
149 let mut tree_assertion = TreeAssertion::new($key, false);
150 $crate::tree_assertion!(@build tree_assertion, $($sub)*);
151 tree_assertion
152 }};
153 ($key:ident: $($rest:tt)+) => {{
154 let key = stringify!($key);
155 $crate::tree_assertion!(var key: $($rest)+)
156 }};
157 ($key:tt: $($rest:tt)+) => {{
158 let key: &'static str = $key;
159 $crate::tree_assertion!(var key: $($rest)+)
160 }};
161}
162
163#[macro_export]
250macro_rules! assert_data_tree {
251 ($diagnostics_hierarchy:expr, $($rest:tt)+) => {{
252 use $crate::DiagnosticsHierarchyGetter as _;
253 let tree_assertion = $crate::tree_assertion!($($rest)+);
254
255 if let Err(e) = tree_assertion.run($diagnostics_hierarchy.get_diagnostics_hierarchy().as_ref()) {
256 panic!("tree assertion fails: {}", e);
257 }
258 }};
259}
260
261#[macro_export]
266macro_rules! assert_json_diff {
267 ($diagnostics_hierarchy:expr, $($rest:tt)+) => {{
268 use $crate::JsonGetter as _;
269 let expected = $diagnostics_hierarchy.get_pretty_json();
270 let actual_hierarchy: $crate::DiagnosticsHierarchy = $crate::hierarchy!{$($rest)+};
271 let actual = actual_hierarchy.get_pretty_json();
272
273 if actual != expected {
274 panic!("{}", $crate::Diff::from_text(&expected, &actual));
275 }
276 }}
277}
278
279pub struct Diff(Changeset);
281
282impl Diff {
283 fn new(expected: &dyn Debug, actual: &dyn Debug) -> Self {
284 let expected = format!("{:#?}", expected);
285 let actual = format!("{:#?}", actual);
286 Self::from_text(&expected, &actual)
287 }
288
289 #[doc(hidden)]
290 pub fn from_text(expected: &str, actual: &str) -> Self {
291 Diff(Changeset::new(expected, actual, "\n"))
292 }
293}
294
295impl Display for Diff {
296 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
297 writeln!(f, "(-) Expected vs. (+) Actual:")?;
298 for diff in &self.0.diffs {
299 let (prefix, contents) = match diff {
300 Difference::Same(same) => (" ", same),
301 Difference::Add(added) => ("+ ", added),
302 Difference::Rem(removed) => ("- ", removed),
303 };
304 for line in contents.split("\n") {
305 writeln!(f, "{}{}", prefix, line)?;
306 }
307 }
308 Ok(())
309 }
310}
311
312macro_rules! eq_or_bail {
313 ($expected:expr, $actual:expr) => {{
314 if $expected != $actual {
315 let changes = Diff::new(&$expected, &$actual);
316 return Err(format_err!("\n {}", changes));
317 }
318 }};
319 ($expected:expr, $actual:expr, $($args:tt)+) => {{
320 if $expected != $actual {
321 let changes = Diff::new(&$expected, &$actual);
322 return Err(format_err!("{}:\n {}", format!($($args)+), changes));
323 }
324 }}
325}
326
327pub struct TreeAssertion<K = String> {
329 name: String,
331 path: String,
334 properties: Vec<(String, Box<dyn PropertyAssertion<K>>)>,
336 children: Vec<TreeAssertion<K>>,
338 exact_match: bool,
340}
341
342impl<K> TreeAssertion<K>
343where
344 K: AsRef<str>,
345{
346 pub fn new(name: &str, exact_match: bool) -> Self {
350 Self {
351 name: name.to_string(),
352 path: name.to_string(),
353 properties: vec![],
354 children: vec![],
355 exact_match,
356 }
357 }
358
359 pub fn add_property_assertion(&mut self, key: &str, assertion: Box<dyn PropertyAssertion<K>>) {
361 self.properties.push((key.to_owned(), assertion));
362 }
363
364 pub fn add_child_assertion(&mut self, mut assertion: TreeAssertion<K>) {
366 assertion.path = format!("{}.{}", self.path, assertion.name);
367 self.children.push(assertion);
368 }
369
370 pub fn run(&self, actual: &DiagnosticsHierarchy<K>) -> Result<(), Error> {
373 eq_or_bail!(self.name, actual.name, "node `{}` - expected node name != actual", self.path);
374
375 if self.exact_match {
376 let properties_names = self.properties.iter().map(|p| p.0.to_string());
377 let children_names = self.children.iter().map(|c| c.name.to_string());
378 let keys: BTreeSet<String> = properties_names.chain(children_names).collect();
379
380 let actual_props = actual.properties.iter().map(|p| p.name().to_string());
381 let actual_children = actual.children.iter().map(|c| c.name.to_string());
382 let actual_keys: BTreeSet<String> = actual_props.chain(actual_children).collect();
383 eq_or_bail!(keys, actual_keys, "node `{}` - expected keys != actual", self.path);
384 }
385
386 for (name, assertion) in self.properties.iter() {
387 let mut matched = actual.properties.iter().filter(|p| p.key().as_ref() == name);
388 let first_match = matched.next();
389 if let Some(_second_match) = matched.next() {
390 bail!("node `{}` - multiple properties found with name `{}`", self.path, name);
391 }
392 match first_match {
393 Some(property) => {
394 if let Err(e) = assertion.run(property) {
395 bail!(
396 "node `{}` - assertion fails for property `{}`. Reason: {}",
397 self.path,
398 name,
399 e
400 );
401 }
402 }
403 None => bail!("node `{}` - no property named `{}`", self.path, name),
404 }
405 }
406 for assertion in self.children.iter() {
407 let mut matched = actual.children.iter().filter(|c| c.name == assertion.name);
408 let first_match = matched.next();
409 if let Some(_second_match) = matched.next() {
410 bail!(
411 "node `{}` - multiple children found with name `{}`",
412 self.path,
413 assertion.name
414 );
415 }
416 match first_match {
417 Some(child) => assertion.run(child)?,
418 None => bail!("node `{}` - no child named `{}`", self.path, assertion.name),
419 }
420 }
421 Ok(())
422 }
423}
424
425pub trait PropertyAssertion<K = String> {
427 fn run(&self, actual: &Property<K>) -> Result<(), Error>;
430}
431
432macro_rules! impl_property_assertion {
433 ($prop_variant:ident, $($ty:ty),+) => {
434 $(
435 impl<K> PropertyAssertion<K> for $ty {
436 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
437 if let Property::$prop_variant(_key, value, ..) = actual {
438 eq_or_bail!(self, value);
439 } else {
440 return Err(format_err!("expected {}, found {}",
441 stringify!($prop_variant), actual.discriminant_name()));
442 }
443 Ok(())
444 }
445 }
446 )+
447 }
448}
449
450macro_rules! impl_array_properties_assertion {
451 ($prop_variant:ident, $($ty:ty),+) => {
452 $(
453 impl<K> PropertyAssertion<K> for Vec<$ty> {
455 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
456 if let Property::$prop_variant(_key, value, ..) = actual {
457 match &value {
458 ArrayContent::Values(values) => eq_or_bail!(self, values),
459 _ => {
460 return Err(format_err!(
461 "expected a plain {} array, got a {}",
462 stringify!($prop_variant),
463 actual.discriminant_name()
464 ));
465 }
466 }
467 } else {
468 return Err(format_err!("expected {}, found {}",
469 stringify!($prop_variant), actual.discriminant_name()));
470 }
471 Ok(())
472 }
473 }
474
475 impl<K> PropertyAssertion<K> for LinearHistogram<$ty> {
476 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
477 if let Property::$prop_variant(_key, value, ..) = actual {
478 match &value {
479 ArrayContent::LinearHistogram(histogram) => {
480 eq_or_bail!(self, histogram)
481 }
482 _ => {
483 return Err(format_err!(
484 "expected a linear {} histogram, got a {}",
485 stringify!($prop_variant),
486 actual.discriminant_name()
487 ));
488 }
489 }
490 } else {
491 return Err(format_err!("expected {}, found {}",
492 stringify!($prop_variant), actual.discriminant_name()));
493 }
494 Ok(())
495 }
496 }
497
498 impl<K> PropertyAssertion<K> for ExponentialHistogram<$ty> {
499 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
500 if let Property::$prop_variant(_key, value, ..) = actual {
501 match &value {
502 ArrayContent::ExponentialHistogram(histogram) => {
503 eq_or_bail!(self, histogram)
504 }
505 _ => {
506 return Err(format_err!(
507 "expected an exponential {} histogram, got a {}",
508 stringify!($prop_variant),
509 actual.discriminant_name()
510 ));
511 }
512 }
513 } else {
514 return Err(format_err!("expected {}, found {}",
515 stringify!($prop_variant), actual.discriminant_name()));
516 }
517 Ok(())
518 }
519 }
520
521 impl<K> PropertyAssertion<K> for HistogramAssertion<$ty> {
523 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
524 if let Property::$prop_variant(_key, value, ..) = actual {
525 let expected_content =
526 ArrayContent::new(self.values.clone(), self.format.clone()).map_err(
527 |e| {
528 format_err!(
529 "failed to load array content for expected assertion {}: {:?}",
530 stringify!($prop_variant),
531 e
532 )
533 },
534 )?;
535 eq_or_bail!(&expected_content, value);
536 } else {
537 return Err(format_err!(
538 "expected {}, found {}",
539 stringify!($prop_variant),
540 actual.discriminant_name(),
541 ));
542 }
543 Ok(())
544 }
545 }
546 )+
547 }
548}
549
550impl_property_assertion!(String, &str, String);
551impl_property_assertion!(Bytes, Vec<u8>);
552impl_property_assertion!(Uint, u64);
553impl_property_assertion!(Int, i64);
554impl_property_assertion!(Double, f64);
555impl_property_assertion!(Bool, bool);
556impl_array_properties_assertion!(DoubleArray, f64);
557impl_array_properties_assertion!(IntArray, i64);
558impl_array_properties_assertion!(UintArray, u64);
559
560pub struct AnyProperty;
562
563impl<K> PropertyAssertion<K> for AnyProperty {
564 fn run(&self, _actual: &Property<K>) -> Result<(), Error> {
565 Ok(())
566 }
567}
568
569pub struct AnyStringProperty;
571
572impl<K> PropertyAssertion<K> for AnyStringProperty {
573 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
574 match actual {
575 Property::String(..) => Ok(()),
576 _ => Err(format_err!("expected String, found {}", actual.discriminant_name())),
577 }
578 }
579}
580
581impl<K> PropertyAssertion<K> for Regex {
584 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
585 (&self).run(actual)
586 }
587}
588
589impl<K> PropertyAssertion<K> for &Regex {
590 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
591 if let Property::String(_, ref v) = actual {
592 if self.is_match(v) {
593 return Ok(());
594 } else {
595 return Err(format_err!(
596 "expected String matching \"{}\", found \"{}\"",
597 self.as_str(),
598 v
599 ));
600 }
601 }
602 Err(format_err!(
603 "expected String matching \"{}\", found {}",
604 self.as_str(),
605 actual.discriminant_name()
606 ))
607 }
608}
609
610pub struct AnyBytesProperty;
612
613impl<K> PropertyAssertion<K> for AnyBytesProperty {
614 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
615 match actual {
616 Property::Bytes(..) => Ok(()),
617 _ => Err(format_err!("expected bytes, found {}", actual.discriminant_name())),
618 }
619 }
620}
621
622pub struct AnyUintProperty;
624
625impl<K> PropertyAssertion<K> for AnyUintProperty {
626 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
627 match actual {
628 Property::Uint(..) => Ok(()),
629 _ => Err(format_err!("expected Uint, found {}", actual.discriminant_name())),
630 }
631 }
632}
633
634pub struct NonZeroUintProperty;
638
639impl<K> PropertyAssertion<K> for NonZeroUintProperty {
640 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
641 match actual {
642 Property::Uint(_, v) if *v != 0 => Ok(()),
643 Property::Uint(_, v) if *v == 0 => {
644 Err(format_err!("expected non-zero integer, found 0"))
645 }
646 _ => {
647 Err(format_err!("expected non-zero integer, found {}", actual.discriminant_name()))
648 }
649 }
650 }
651}
652
653pub struct NonZeroIntProperty;
657
658impl<K> PropertyAssertion<K> for NonZeroIntProperty {
659 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
660 match actual {
661 Property::Int(_, v) if *v != 0 => Ok(()),
662 Property::Int(_, v) if *v == 0 => {
663 Err(format_err!("expected non-zero signed integer, found 0"))
664 }
665 _ => Err(format_err!(
666 "expected non-zero signed integer, found {}",
667 actual.discriminant_name()
668 )),
669 }
670 }
671}
672
673pub struct AnyIntProperty;
675
676impl<K> PropertyAssertion<K> for AnyIntProperty {
677 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
678 match actual {
679 Property::Int(..) => Ok(()),
680 _ => Err(format_err!("expected Int, found {}", actual.discriminant_name())),
681 }
682 }
683}
684
685pub struct AnyDoubleProperty;
687
688impl<K> PropertyAssertion<K> for AnyDoubleProperty {
689 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
690 match actual {
691 Property::Double(..) => Ok(()),
692 _ => Err(format_err!("expected Double, found {}", actual.discriminant_name())),
693 }
694 }
695}
696
697pub struct AnyNumericProperty;
699
700impl<K> PropertyAssertion<K> for AnyNumericProperty {
701 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
702 match actual {
703 Property::Int(..) | Property::Uint(..) | Property::Double(..) => Ok(()),
704 _ => Err(format_err!(
705 "expected an Int, Uint or Double. found {}",
706 actual.discriminant_name()
707 )),
708 }
709 }
710}
711
712pub struct AnyBoolProperty;
714
715impl<K> PropertyAssertion<K> for AnyBoolProperty {
716 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
717 match actual {
718 Property::Bool(..) => Ok(()),
719 _ => Err(format_err!("expected Bool, found {}", actual.discriminant_name())),
720 }
721 }
722}
723
724impl<K> PropertyAssertion<K> for Vec<String> {
725 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
726 let this = self.iter().map(|s| s.as_ref()).collect::<Vec<&str>>();
727 this.run(actual)
728 }
729}
730
731impl<K> PropertyAssertion<K> for Vec<&str> {
732 fn run(&self, actual: &Property<K>) -> Result<(), Error> {
733 match actual {
734 Property::StringList(_key, value) => {
735 eq_or_bail!(self, value);
736 Ok(())
737 }
738 _ => Err(format_err!("expected StringList, found {}", actual.discriminant_name())),
739 }
740 }
741}
742
743#[derive(Clone)]
745pub struct HistogramAssertion<T> {
746 format: ArrayFormat,
747 values: Vec<T>,
748}
749
750impl<T: MulAssign + AddAssign + PartialOrd + Add<Output = T> + Copy + Default + One>
751 HistogramAssertion<T>
752{
753 pub fn linear(params: LinearHistogramParams<T>) -> Self {
755 let mut values = vec![T::default(); params.buckets + LINEAR_HISTOGRAM_EXTRA_SLOTS];
756 values[0] = params.floor;
757 values[1] = params.step_size;
758 Self { format: ArrayFormat::LinearHistogram, values }
759 }
760
761 pub fn exponential(params: ExponentialHistogramParams<T>) -> Self {
763 let mut values = vec![T::default(); params.buckets + EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS];
764 values[0] = params.floor;
765 values[1] = params.initial_step;
766 values[2] = params.step_multiplier;
767 Self { format: ArrayFormat::ExponentialHistogram, values }
768 }
769
770 pub fn insert_values(&mut self, values: impl IntoIterator<Item = T>) {
772 match self.format {
773 ArrayFormat::ExponentialHistogram => {
774 for value in values {
775 self.insert_exp(value);
776 }
777 }
778 ArrayFormat::LinearHistogram => {
779 for value in values {
780 self.insert_linear(value);
781 }
782 }
783 ArrayFormat::Default => {
784 unreachable!("can't construct a histogram assertion for arrays");
785 }
786 }
787 }
788
789 fn insert_linear(&mut self, value: T) {
790 let value_index = {
791 let mut current_floor = self.values[0];
792 let step_size = self.values[1];
793 let mut index = LINEAR_HISTOGRAM_EXTRA_SLOTS - 2;
795 while value >= current_floor && index < self.values.len() - 1 {
796 current_floor += step_size;
797 index += 1;
798 }
799 index
800 };
801 self.values[value_index] += T::one();
802 }
803
804 fn insert_exp(&mut self, value: T) {
805 let value_index = {
806 let floor = self.values[0];
807 let mut current_floor = self.values[0];
808 let mut offset = self.values[1];
809 let step_multiplier = self.values[2];
810 let mut index = EXPONENTIAL_HISTOGRAM_EXTRA_SLOTS - 2;
812 while value >= current_floor && index < self.values.len() - 1 {
813 current_floor = floor + offset;
814 offset *= step_multiplier;
815 index += 1;
816 }
817 index
818 };
819 self.values[value_index] += T::one();
820 }
821}
822
823#[cfg(test)]
824mod tests {
825 use super::*;
826 use crate::Difference::{Add, Rem, Same};
827 use diagnostics_hierarchy::testing::CondensableOnDemand;
828 use std::sync::LazyLock;
829
830 static TEST_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new("a").unwrap());
831
832 #[fuchsia::test]
833 fn test_assert_json_diff() {
834 assert_json_diff!(
835 simple_tree(),
836 key: {
837 sub: "sub_value",
838 sub2: "sub2_value",
839 }
840 );
841
842 let diagnostics_hierarchy = complex_tree();
843 assert_json_diff!(diagnostics_hierarchy, key: {
844 sub: "sub_value",
845 sub2: "sub2_value",
846 child1: {
847 child1_sub: 10i64,
848 },
849 child2: {
850 child2_sub: 20u64,
851 },
852 });
853 }
854
855 #[fuchsia::test]
856 #[should_panic]
857 fn test_panicking_assert_json_diff() {
858 assert_json_diff!(
859 simple_tree(),
860 key: {
861 sub: "sub_value",
862 sb2: "sub2_value",
863 }
864 );
865
866 let diagnostics_hierarchy = complex_tree();
867 assert_json_diff!(diagnostics_hierarchy, key: {
868 sb: "sub_value",
869 sub2: "sub2_value",
870 child: {
871 child1_sub: 10i64,
872 },
873 child3: {
874 child2_sub: 20u64,
875 },
876 });
877 }
878
879 #[fuchsia::test]
880 fn test_exact_match_simple() {
881 let diagnostics_hierarchy = simple_tree();
882 assert_data_tree!(diagnostics_hierarchy, key: {
883 sub: "sub_value",
884 sub2: "sub2_value",
885 });
886 }
887
888 #[fuchsia::test]
889 fn test_exact_match_complex() {
890 let diagnostics_hierarchy = complex_tree();
891 assert_data_tree!(diagnostics_hierarchy, key: {
892 sub: "sub_value",
893 sub2: "sub2_value",
894 child1: {
895 child1_sub: 10i64,
896 },
897 child2: {
898 child2_sub: 20u64,
899 },
900 });
901 }
902
903 #[fuchsia::test]
904 #[should_panic]
905 fn test_exact_match_mismatched_property_name() {
906 let diagnostics_hierarchy = simple_tree();
907 assert_data_tree!(diagnostics_hierarchy, key: {
908 sub: "sub_value",
909 sub3: "sub2_value",
910 });
911 }
912
913 #[fuchsia::test]
914 #[should_panic]
915 fn test_exact_match_mismatched_child_name() {
916 let diagnostics_hierarchy = complex_tree();
917 assert_data_tree!(diagnostics_hierarchy, key: {
918 sub: "sub_value",
919 sub2: "sub2_value",
920 child1: {
921 child1_sub: 10i64,
922 },
923 child3: {
924 child2_sub: 20u64,
925 },
926 });
927 }
928
929 #[fuchsia::test]
930 #[should_panic]
931 fn test_exact_match_mismatched_property_name_in_child() {
932 let diagnostics_hierarchy = complex_tree();
933 assert_data_tree!(diagnostics_hierarchy, key: {
934 sub: "sub_value",
935 sub2: "sub2_value",
936 child1: {
937 child2_sub: 10i64,
938 },
939 child2: {
940 child2_sub: 20u64,
941 },
942 });
943 }
944
945 #[fuchsia::test]
946 #[should_panic]
947 fn test_exact_match_mismatched_property_value() {
948 let diagnostics_hierarchy = simple_tree();
949 assert_data_tree!(diagnostics_hierarchy, key: {
950 sub: "sub2_value",
951 sub2: "sub2_value",
952 });
953 }
954
955 #[fuchsia::test]
956 #[should_panic]
957 fn test_exact_match_missing_property() {
958 let diagnostics_hierarchy = simple_tree();
959 assert_data_tree!(diagnostics_hierarchy, key: {
960 sub: "sub_value",
961 });
962 }
963
964 #[fuchsia::test]
965 #[should_panic]
966 fn test_exact_match_missing_child() {
967 let diagnostics_hierarchy = complex_tree();
968 assert_data_tree!(diagnostics_hierarchy, key: {
969 sub: "sub_value",
970 sub2: "sub2_value",
971 child1: {
972 child1_sub: 10i64,
973 },
974 });
975 }
976
977 #[fuchsia::test]
978 fn test_partial_match_success() {
979 let diagnostics_hierarchy = complex_tree();
980
981 assert_data_tree!(diagnostics_hierarchy, key: contains {});
983
984 assert_data_tree!(diagnostics_hierarchy, key: contains {
986 sub: "sub_value",
987 child1: contains {},
988 });
989 }
990
991 #[fuchsia::test]
992 #[should_panic]
993 fn test_partial_match_nonexistent_property() {
994 let diagnostics_hierarchy = simple_tree();
995 assert_data_tree!(diagnostics_hierarchy, key: contains {
996 sub3: AnyProperty,
997 });
998 }
999
1000 #[fuchsia::test]
1001 fn test_ignore_property_value() {
1002 let diagnostics_hierarchy = simple_tree();
1003 assert_data_tree!(diagnostics_hierarchy, key: {
1004 sub: AnyProperty,
1005 sub2: "sub2_value",
1006 });
1007 }
1008
1009 #[fuchsia::test]
1010 #[should_panic]
1011 fn test_ignore_property_value_property_name_is_still_checked() {
1012 let diagnostics_hierarchy = simple_tree();
1013 assert_data_tree!(diagnostics_hierarchy, key: {
1014 sub1: AnyProperty,
1015 sub2: "sub2_value",
1016 })
1017 }
1018
1019 #[fuchsia::test]
1020 fn test_expr_key_syntax() {
1021 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1022 "key",
1023 vec![Property::String("@time".to_string(), "1.000".to_string())],
1024 vec![],
1025 );
1026 assert_data_tree!(diagnostics_hierarchy, key: {
1027 "@time": "1.000"
1028 });
1029 }
1030
1031 #[fuchsia::test]
1032 fn test_var_key_syntax() {
1033 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1034 "key",
1035 vec![Property::String("@time".to_string(), "1.000".to_string())],
1036 vec![],
1037 );
1038 let time_key = "@time";
1039 assert_data_tree!(diagnostics_hierarchy, key: {
1040 var time_key: "1.000"
1041 });
1042 }
1043
1044 const KEY_AS_STR: &str = "@time";
1045
1046 #[fuchsia::test]
1048 fn test_path_key_syntax() {
1049 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1050 "key",
1051 vec![Property::String("@time".to_string(), "1.000".to_string())],
1052 vec![],
1053 );
1054 assert_data_tree!(diagnostics_hierarchy, key: {
1055 ref crate::tests::KEY_AS_STR: "1.000"
1057 });
1058 }
1059
1060 #[fuchsia::test]
1061 fn test_arrays() {
1062 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1063 "key",
1064 vec![
1065 Property::UintArray("@uints".to_string(), ArrayContent::Values(vec![1, 2, 3])),
1066 Property::IntArray("@ints".to_string(), ArrayContent::Values(vec![-2, -4, 0])),
1067 Property::DoubleArray(
1068 "@doubles".to_string(),
1069 ArrayContent::Values(vec![1.3, 2.5, -3.6]),
1070 ),
1071 ],
1072 vec![],
1073 );
1074 assert_data_tree!(diagnostics_hierarchy, key: {
1075 "@uints": vec![1u64, 2, 3],
1076 "@ints": vec![-2i64, -4, 0],
1077 "@doubles": vec![1.3, 2.5, -3.6]
1078 });
1079 }
1080
1081 #[fuchsia::test]
1082 fn test_histograms() {
1083 let mut condensed_int_histogram =
1084 ArrayContent::new(vec![6, 7, 0, 9, 0], ArrayFormat::LinearHistogram).unwrap();
1085 condensed_int_histogram.condense_histogram();
1086 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1087 "key",
1088 vec![
1089 Property::UintArray(
1090 "@linear-uints".to_string(),
1091 ArrayContent::new(vec![1, 2, 3, 4, 5], ArrayFormat::LinearHistogram).unwrap(),
1092 ),
1093 Property::IntArray(
1094 "@linear-ints".to_string(),
1095 ArrayContent::new(vec![6, 7, 8, 9, 10], ArrayFormat::LinearHistogram).unwrap(),
1096 ),
1097 Property::IntArray("@linear-sparse-ints".to_string(), condensed_int_histogram),
1098 Property::DoubleArray(
1099 "@linear-doubles".to_string(),
1100 ArrayContent::new(vec![1.0, 2.0, 4.0, 5.0, 6.0], ArrayFormat::LinearHistogram)
1101 .unwrap(),
1102 ),
1103 Property::UintArray(
1104 "@exp-uints".to_string(),
1105 ArrayContent::new(vec![2, 4, 6, 8, 10, 12], ArrayFormat::ExponentialHistogram)
1106 .unwrap(),
1107 ),
1108 Property::IntArray(
1109 "@exp-ints".to_string(),
1110 ArrayContent::new(vec![1, 3, 5, 7, 9, 11], ArrayFormat::ExponentialHistogram)
1111 .unwrap(),
1112 ),
1113 Property::DoubleArray(
1114 "@exp-doubles".to_string(),
1115 ArrayContent::new(
1116 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
1117 ArrayFormat::ExponentialHistogram,
1118 )
1119 .unwrap(),
1120 ),
1121 ],
1122 vec![],
1123 );
1124 let mut linear_uint_assertion = HistogramAssertion::linear(LinearHistogramParams {
1125 floor: 1u64,
1126 step_size: 2,
1127 buckets: 1,
1128 });
1129 linear_uint_assertion.insert_values(vec![0, 0, 0, 2, 2, 2, 2, 4, 4, 4, 4, 4]);
1130 let mut exponential_double_assertion =
1131 HistogramAssertion::exponential(ExponentialHistogramParams {
1132 floor: 1.0,
1133 initial_step: 2.0,
1134 step_multiplier: 3.0,
1135 buckets: 1,
1136 });
1137 exponential_double_assertion.insert_values(vec![
1138 -3.1, -2.2, -1.3, 0.0, 1.1, 1.2, 2.5, 2.8, 2.0, 3.1, 4.2, 5.3, 6.4, 7.5, 8.6,
1139 ]);
1140 assert_data_tree!(diagnostics_hierarchy, key: {
1141 "@linear-uints": linear_uint_assertion,
1142 "@linear-ints": LinearHistogram {
1143 floor: 6i64,
1144 step: 7,
1145 counts: vec![8, 9, 10],
1146 indexes: None,
1147 size: 3
1148 },
1149 "@linear-sparse-ints": LinearHistogram {
1150 floor: 6i64,
1151 step: 7,
1152 counts: vec![9],
1153 indexes: Some(vec![1]),
1154 size: 3
1155 },
1156 "@linear-doubles": LinearHistogram {
1157 floor: 1.0,
1158 step: 2.0,
1159 counts: vec![4.0, 5.0, 6.0],
1160 indexes: None,
1161 size: 3
1162 },
1163 "@exp-uints": ExponentialHistogram {
1164 floor: 2u64,
1165 initial_step: 4,
1166 step_multiplier: 6,
1167 counts: vec![8, 10, 12],
1168 indexes: None,
1169 size: 3
1170 },
1171 "@exp-ints": ExponentialHistogram {
1172 floor: 1i64,
1173 initial_step: 3,
1174 step_multiplier: 5,
1175 counts: vec![7,9,11],
1176 indexes: None,
1177 size: 3
1178 },
1179 "@exp-doubles": exponential_double_assertion,
1180 });
1181 }
1182
1183 #[fuchsia::test]
1184 fn test_matching_tree_assertion_expression() {
1185 let diagnostics_hierarchy = complex_tree();
1186 let child1 = tree_assertion!(
1187 child1: {
1188 child1_sub: 10i64,
1189 }
1190 );
1191 assert_data_tree!(diagnostics_hierarchy, key: {
1192 sub: "sub_value",
1193 sub2: "sub2_value",
1194 child1,
1195 tree_assertion!(
1196 child2: {
1197 child2_sub: 20u64,
1198 }
1199 ),
1200 });
1201 }
1202
1203 #[fuchsia::test]
1204 #[should_panic]
1205 fn test_matching_non_unique_property_fails() {
1206 let diagnostics_hierarchy = non_unique_prop_tree();
1207 assert_data_tree!(diagnostics_hierarchy, key: { prop: "prop_value#0" });
1208 }
1209
1210 #[fuchsia::test]
1211 #[should_panic]
1212 fn test_matching_non_unique_property_fails_2() {
1213 let diagnostics_hierarchy = non_unique_prop_tree();
1214 assert_data_tree!(diagnostics_hierarchy, key: { prop: "prop_value#1" });
1215 }
1216
1217 #[fuchsia::test]
1218 #[should_panic]
1219 fn test_matching_non_unique_property_fails_3() {
1220 let diagnostics_hierarchy = non_unique_prop_tree();
1221 assert_data_tree!(diagnostics_hierarchy, key: {
1222 prop: "prop_value#0",
1223 prop: "prop_value#1",
1224 });
1225 }
1226
1227 #[fuchsia::test]
1228 #[should_panic]
1229 fn test_matching_non_unique_child_fails() {
1230 let diagnostics_hierarchy = non_unique_child_tree();
1231 assert_data_tree!(diagnostics_hierarchy, key: {
1232 child: {
1233 prop: 10i64
1234 }
1235 });
1236 }
1237
1238 #[fuchsia::test]
1239 #[should_panic]
1240 fn test_matching_non_unique_child_fails_2() {
1241 let diagnostics_hierarchy = non_unique_child_tree();
1242 assert_data_tree!(diagnostics_hierarchy, key: {
1243 child: {
1244 prop: 20i64
1245 }
1246 });
1247 }
1248
1249 #[fuchsia::test]
1250 #[should_panic]
1251 fn test_matching_non_unique_child_fails_3() {
1252 let diagnostics_hierarchy = non_unique_child_tree();
1253 assert_data_tree!(diagnostics_hierarchy, key: {
1254 child: {
1255 prop: 10i64,
1256 },
1257 child: {
1258 prop: 20i64,
1259 },
1260 });
1261 }
1262
1263 #[fuchsia::test]
1264 fn test_any_string_property_passes() {
1265 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1266 "key",
1267 vec![
1268 Property::String("value1".to_string(), "a".to_string()),
1269 Property::String("value2".to_string(), "b".to_string()),
1270 ],
1271 vec![],
1272 );
1273 assert_data_tree!(diagnostics_hierarchy, key: {
1274 value1: AnyStringProperty,
1275 value2: AnyStringProperty,
1276 });
1277 }
1278
1279 #[fuchsia::test]
1280 #[should_panic]
1281 fn test_any_string_property_fails() {
1282 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1283 "key",
1284 vec![Property::Int("value1".to_string(), 10i64)],
1285 vec![],
1286 );
1287 assert_data_tree!(diagnostics_hierarchy, key: {
1288 value1: AnyStringProperty,
1289 });
1290 }
1291
1292 #[fuchsia::test]
1293 fn test_string_property_regex_passes() {
1294 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1295 "key",
1296 vec![Property::String("value1".to_string(), "aaaabbbb".to_string())],
1297 vec![],
1298 );
1299 assert_data_tree!(diagnostics_hierarchy, key: {
1300 value1: &*TEST_REGEX,
1301 });
1302 assert_data_tree!(diagnostics_hierarchy, key: {
1303 value1: Regex::new("a{4}b{4}").unwrap(),
1304 });
1305 assert_data_tree!(diagnostics_hierarchy, key: {
1306 value1: Regex::new("a{4}").unwrap(),
1307 });
1308 assert_data_tree!(diagnostics_hierarchy, key: {
1309 value1: Regex::new("a{2}b{2}").unwrap(),
1310 });
1311 assert_data_tree!(diagnostics_hierarchy, key: {
1312 value1: Regex::new("b{4}").unwrap(),
1313 });
1314 }
1315
1316 #[fuchsia::test]
1317 #[should_panic]
1318 fn test_string_property_regex_no_match() {
1319 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1320 "key",
1321 vec![Property::String("value1".to_string(), "bbbbcccc".to_string())],
1322 vec![],
1323 );
1324 assert_data_tree!(diagnostics_hierarchy, key: {
1325 value: Regex::new("b{2}d{2}").unwrap(),
1326 });
1327 }
1328
1329 #[fuchsia::test]
1330 #[should_panic]
1331 fn test_string_property_regex_wrong_type() {
1332 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1333 "key",
1334 vec![Property::Int("value1".to_string(), 10i64)],
1335 vec![],
1336 );
1337 assert_data_tree!(diagnostics_hierarchy, key: {
1338 value1: Regex::new("a{4}").unwrap(),
1339 });
1340 }
1341
1342 #[fuchsia::test]
1343 fn test_any_bytes_property_passes() {
1344 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1345 "key",
1346 vec![
1347 Property::Bytes("value1".to_string(), vec![1, 2, 3]),
1348 Property::Bytes("value2".to_string(), vec![4, 5, 6]),
1349 ],
1350 vec![],
1351 );
1352 assert_data_tree!(diagnostics_hierarchy, key: {
1353 value1: AnyBytesProperty,
1354 value2: AnyBytesProperty,
1355 });
1356 }
1357
1358 #[fuchsia::test]
1359 #[should_panic]
1360 fn test_any_bytes_property_fails() {
1361 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1362 "key",
1363 vec![Property::Int("value1".to_string(), 10i64)],
1364 vec![],
1365 );
1366 assert_data_tree!(diagnostics_hierarchy, key: {
1367 value1: AnyBytesProperty,
1368 });
1369 }
1370
1371 #[fuchsia::test]
1372 fn test_nonzero_uint_property_passes() {
1373 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1374 "key",
1375 vec![
1376 Property::Uint("value1".to_string(), 10u64),
1377 Property::Uint("value2".to_string(), 20u64),
1378 ],
1379 vec![],
1380 );
1381 assert_data_tree!(diagnostics_hierarchy, key: {
1382 value1: NonZeroUintProperty,
1383 value2: NonZeroUintProperty,
1384 });
1385 }
1386
1387 #[fuchsia::test]
1388 #[should_panic]
1389 fn test_nonzero_uint_property_fails_on_zero() {
1390 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1391 "key",
1392 vec![Property::Uint("value1".to_string(), 0u64)],
1393 vec![],
1394 );
1395 assert_data_tree!(diagnostics_hierarchy, key: {
1396 value1: NonZeroUintProperty,
1397 });
1398 }
1399
1400 #[fuchsia::test]
1401 #[should_panic]
1402 fn test_nonzero_uint_property_fails() {
1403 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1404 "key",
1405 vec![Property::Int("value1".to_string(), 10i64)],
1406 vec![],
1407 );
1408 assert_data_tree!(diagnostics_hierarchy, key: {
1409 value1: NonZeroUintProperty,
1410 });
1411 }
1412
1413 #[fuchsia::test]
1414 fn test_nonzero_int_property_passes() {
1415 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1416 "key",
1417 vec![Property::Int("value1".to_string(), 10), Property::Int("value2".to_string(), 20)],
1418 vec![],
1419 );
1420 assert_data_tree!(diagnostics_hierarchy, key: {
1421 value1: NonZeroIntProperty,
1422 value2: NonZeroIntProperty,
1423 });
1424 }
1425
1426 #[fuchsia::test]
1427 #[should_panic]
1428 fn test_nonzero_int_property_fails_on_zero() {
1429 let diagnostics_hierarchy =
1430 DiagnosticsHierarchy::new("key", vec![Property::Int("value1".to_string(), 0)], vec![]);
1431 assert_data_tree!(diagnostics_hierarchy, key: {
1432 value1: NonZeroIntProperty,
1433 });
1434 }
1435
1436 #[fuchsia::test]
1437 #[should_panic]
1438 fn test_nonzero_int_property_fails() {
1439 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1440 "key",
1441 vec![Property::Uint("value1".to_string(), 10u64)],
1442 vec![],
1443 );
1444 assert_data_tree!(diagnostics_hierarchy, key: {
1445 value1: NonZeroIntProperty,
1446 });
1447 }
1448
1449 #[fuchsia::test]
1450 fn test_uint_property_passes() {
1451 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1452 "key",
1453 vec![
1454 Property::Uint("value1".to_string(), 10u64),
1455 Property::Uint("value2".to_string(), 20u64),
1456 ],
1457 vec![],
1458 );
1459 assert_data_tree!(diagnostics_hierarchy, key: {
1460 value1: AnyUintProperty,
1461 value2: AnyUintProperty,
1462 });
1463 }
1464
1465 #[fuchsia::test]
1466 #[should_panic]
1467 fn test_uint_property_fails() {
1468 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1469 "key",
1470 vec![Property::Int("value1".to_string(), 10i64)],
1471 vec![],
1472 );
1473 assert_data_tree!(diagnostics_hierarchy, key: {
1474 value1: AnyUintProperty,
1475 });
1476 }
1477
1478 #[fuchsia::test]
1479 fn test_int_property_passes() {
1480 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1481 "key",
1482 vec![
1483 Property::Int("value1".to_string(), 10i64),
1484 Property::Int("value2".to_string(), 20i64),
1485 ],
1486 vec![],
1487 );
1488 assert_data_tree!(diagnostics_hierarchy, key: {
1489 value1: AnyIntProperty,
1490 value2: AnyIntProperty,
1491 });
1492 }
1493
1494 #[fuchsia::test]
1495 #[should_panic]
1496 fn test_int_property_fails() {
1497 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1498 "key",
1499 vec![Property::Uint("value1".to_string(), 0u64)],
1500 vec![],
1501 );
1502 assert_data_tree!(diagnostics_hierarchy, key: {
1503 value1: AnyIntProperty,
1504 });
1505 }
1506
1507 #[fuchsia::test]
1508 fn test_double_property_passes() {
1509 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1510 "key",
1511 vec![
1512 Property::Double("value1".to_string(), std::f64::consts::PI),
1513 Property::Double("value2".to_string(), std::f64::consts::E),
1514 ],
1515 vec![],
1516 );
1517 assert_data_tree!(diagnostics_hierarchy, key: {
1518 value1: AnyDoubleProperty,
1519 value2: AnyDoubleProperty,
1520 });
1521 }
1522
1523 #[fuchsia::test]
1524 #[should_panic]
1525 fn test_double_property_fails() {
1526 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1527 "key",
1528 vec![Property::Uint("value1".to_string(), 0u64)],
1529 vec![],
1530 );
1531 assert_data_tree!(diagnostics_hierarchy, key: {
1532 value1: AnyDoubleProperty,
1533 });
1534 }
1535
1536 #[fuchsia::test]
1537 fn test_numeric_property_passes() {
1538 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1539 "key",
1540 vec![
1541 Property::Int("value1".to_string(), 10i64),
1542 Property::Uint("value2".to_string(), 20u64),
1543 Property::Double("value3".to_string(), std::f64::consts::PI),
1544 ],
1545 vec![],
1546 );
1547 assert_data_tree!(diagnostics_hierarchy, key: {
1548 value1: AnyNumericProperty,
1549 value2: AnyNumericProperty,
1550 value3: AnyNumericProperty,
1551 });
1552 }
1553
1554 #[fuchsia::test]
1555 #[should_panic]
1556 fn test_numeric_property_fails() {
1557 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1558 "key",
1559 vec![Property::String("value1".to_string(), "a".to_string())],
1560 vec![],
1561 );
1562 assert_data_tree!(diagnostics_hierarchy, key: {
1563 value1: AnyNumericProperty,
1564 });
1565 }
1566
1567 #[fuchsia::test]
1568 fn test_bool_property_passes() {
1569 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1570 "key",
1571 vec![
1572 Property::Bool("value1".to_string(), true),
1573 Property::Bool("value2".to_string(), false),
1574 ],
1575 vec![],
1576 );
1577 assert_data_tree!(diagnostics_hierarchy, key: {
1578 value1: AnyBoolProperty,
1579 value2: AnyBoolProperty,
1580 });
1581 }
1582
1583 #[fuchsia::test]
1584 #[should_panic]
1585 fn test_bool_property_fails() {
1586 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1587 "key",
1588 vec![Property::Uint("value1".to_string(), 0u64)],
1589 vec![],
1590 );
1591 assert_data_tree!(diagnostics_hierarchy, key: {
1592 value1: AnyBoolProperty,
1593 });
1594 }
1595
1596 #[fuchsia::test]
1597 fn test_string_list() {
1598 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1599 "key",
1600 vec![
1601 Property::StringList("value1".to_string(), vec!["a".to_string(), "b".to_string()]),
1602 Property::StringList("value2".to_string(), vec!["c".to_string(), "d".to_string()]),
1603 ],
1604 vec![],
1605 );
1606 assert_data_tree!(diagnostics_hierarchy, key: {
1607 value1: vec!["a", "b"],
1608 value2: vec!["c".to_string(), "d".to_string()],
1609 });
1610 }
1611
1612 #[fuchsia::test]
1613 #[should_panic]
1614 fn test_string_list_failure() {
1615 let diagnostics_hierarchy = DiagnosticsHierarchy::new(
1616 "key",
1617 vec![Property::StringList(
1618 "value1".to_string(),
1619 vec!["a".to_string(), "b".to_string()],
1620 )],
1621 vec![],
1622 );
1623 assert_data_tree!(diagnostics_hierarchy, key: {
1624 value1: vec![1i64, 2],
1625 });
1626 }
1627
1628 #[test]
1629 fn test_diff_from_text() {
1630 let original = "foo\nbar\nbaz";
1631 let update = "foo\nbaz\nqux";
1632
1633 let changeset = Diff::from_text(original, update);
1634 assert_eq!(
1635 changeset.0.diffs,
1636 vec![
1637 Same("foo".to_string()),
1638 Rem("bar".to_string()),
1639 Same("baz".to_string()),
1640 Add("qux".to_string())
1641 ]
1642 )
1643 }
1644
1645 fn simple_tree() -> DiagnosticsHierarchy {
1646 DiagnosticsHierarchy::new(
1647 "key",
1648 vec![
1649 Property::String("sub".to_string(), "sub_value".to_string()),
1650 Property::String("sub2".to_string(), "sub2_value".to_string()),
1651 ],
1652 vec![],
1653 )
1654 }
1655
1656 fn complex_tree() -> DiagnosticsHierarchy {
1657 DiagnosticsHierarchy::new(
1658 "key",
1659 vec![
1660 Property::String("sub".to_string(), "sub_value".to_string()),
1661 Property::String("sub2".to_string(), "sub2_value".to_string()),
1662 ],
1663 vec![
1664 DiagnosticsHierarchy::new(
1665 "child1",
1666 vec![Property::Int("child1_sub".to_string(), 10i64)],
1667 vec![],
1668 ),
1669 DiagnosticsHierarchy::new(
1670 "child2",
1671 vec![Property::Uint("child2_sub".to_string(), 20u64)],
1672 vec![],
1673 ),
1674 ],
1675 )
1676 }
1677
1678 fn non_unique_prop_tree() -> DiagnosticsHierarchy {
1679 DiagnosticsHierarchy::new(
1680 "key",
1681 vec![
1682 Property::String("prop".to_string(), "prop_value#0".to_string()),
1683 Property::String("prop".to_string(), "prop_value#1".to_string()),
1684 ],
1685 vec![],
1686 )
1687 }
1688
1689 fn non_unique_child_tree() -> DiagnosticsHierarchy {
1690 DiagnosticsHierarchy::new(
1691 "key",
1692 vec![],
1693 vec![
1694 DiagnosticsHierarchy::new(
1695 "child",
1696 vec![Property::Int("prop".to_string(), 10i64)],
1697 vec![],
1698 ),
1699 DiagnosticsHierarchy::new(
1700 "child",
1701 vec![Property::Int("prop".to_string(), 20i64)],
1702 vec![],
1703 ),
1704 ],
1705 )
1706 }
1707}