1use crate::error::*;
6use crate::parser::{self, ParsingError, RequireEscaped, VerboseError};
7use crate::validate::*;
8use anyhow::format_err;
9use fidl_fuchsia_diagnostics::{
10 self as fdiagnostics, ComponentSelector, Interest, LogInterestSelector, PropertySelector,
11 Selector, SelectorArgument, Severity, StringSelector, SubtreeSelector, TreeNames, TreeSelector,
12};
13use fidl_fuchsia_inspect::DEFAULT_TREE_NAME;
14use itertools::Itertools;
15use moniker::{ChildName, ExtendedMoniker, Moniker, EXTENDED_MONIKER_COMPONENT_MANAGER_STR};
16use std::borrow::{Borrow, Cow};
17use std::fs;
18use std::io::{BufRead, BufReader};
19use std::path::Path;
20
21pub const SELECTOR_DELIMITER: char = ':';
24
25const PATH_NODE_DELIMITER: char = '/';
27
28pub const ESCAPE_CHARACTER: char = '\\';
31
32const TAB_CHAR: char = '\t';
33const SPACE_CHAR: char = ' ';
34
35const WILDCARD_SYMBOL_CHAR: char = '*';
37
38const RECURSIVE_WILDCARD_SYMBOL_STR: &str = "**";
39
40pub fn contains_recursive_glob(component_selector: &ComponentSelector) -> bool {
43 let last_segment = component_selector.moniker_segments.as_ref().unwrap().last().unwrap();
45 string_selector_contains_recursive_glob(last_segment)
46}
47
48fn string_selector_contains_recursive_glob(selector: &StringSelector) -> bool {
49 matches!(
50 selector,
51 StringSelector::StringPattern(pattern) if pattern == RECURSIVE_WILDCARD_SYMBOL_STR
52 )
53}
54
55pub fn take_from_argument<E>(arg: SelectorArgument) -> Result<Selector, Error>
57where
58 E: for<'a> ParsingError<'a>,
59{
60 match arg {
61 SelectorArgument::StructuredSelector(s) => {
62 s.validate()?;
63 Ok(s)
64 }
65 SelectorArgument::RawSelector(r) => parse_selector::<VerboseError>(&r),
66 _ => Err(Error::InvalidSelectorArgument),
67 }
68}
69
70pub fn parse_tree_selector<'a, E>(
72 unparsed_tree_selector: &'a str,
73) -> Result<TreeSelector, ParseError>
74where
75 E: ParsingError<'a>,
76{
77 let result = parser::standalone_tree_selector::<E>(unparsed_tree_selector)?;
78 Ok(result.into())
79}
80
81pub fn parse_component_selector<'a, E>(
83 unparsed_component_selector: &'a str,
84) -> Result<ComponentSelector, ParseError>
85where
86 E: ParsingError<'a>,
87{
88 let result = parser::consuming_component_selector::<E>(
89 unparsed_component_selector,
90 RequireEscaped::COLONS,
91 )?;
92 Ok(result.into())
93}
94
95fn parse_component_selector_no_escaping<'a, E>(
96 unparsed_component_selector: &'a str,
97) -> Result<ComponentSelector, ParseError>
98where
99 E: ParsingError<'a>,
100{
101 let result = parser::consuming_component_selector::<E>(
102 unparsed_component_selector,
103 RequireEscaped::empty(),
104 )?;
105 Ok(result.into())
106}
107
108pub fn parse_log_interest_selector(selector: &str) -> Result<LogInterestSelector, anyhow::Error> {
111 let default_invalid_selector_err = format_err!(
112 "Invalid component interest selector: '{}'. Expecting: '/some/moniker/selector#<log-level>'.",
113 selector
114 );
115 let mut parts = selector.split('#');
116
117 let Some(component) = parts.next() else {
120 return Err(default_invalid_selector_err);
121 };
122 let Some(interest) = parts.next() else {
123 return Err(format_err!(
124 concat!(
125 "Missing <log-level> in selector. Expecting: '{}#<log-level>', ",
126 "such as #DEBUG or #INFO."
127 ),
128 selector
129 ));
130 };
131 if parts.next().is_some() {
132 return Err(default_invalid_selector_err);
133 }
134 let parsed_selector = match parse_component_selector_no_escaping::<VerboseError>(component) {
135 Ok(s) => s,
136 Err(e) => {
137 return Err(format_err!(
138 "Invalid component interest selector: '{}'. Error: {}",
139 selector,
140 e
141 ))
142 }
143 };
144 let Some(min_severity) = parse_severity(interest.to_uppercase().as_ref()) else {
145 return Err(format_err!(
146 concat!(
147 "Invalid <log-level> in selector '{}'. Expecting: a min log level ",
148 "such as #DEBUG or #INFO."
149 ),
150 selector
151 ));
152 };
153 Ok(LogInterestSelector {
154 selector: parsed_selector,
155 interest: Interest { min_severity: Some(min_severity), ..Default::default() },
156 })
157}
158
159pub fn parse_log_interest_selector_or_severity(
162 selector: &str,
163) -> Result<LogInterestSelector, anyhow::Error> {
164 if let Some(min_severity) = parse_severity(selector.to_uppercase().as_ref()) {
165 return Ok(LogInterestSelector {
166 selector: ComponentSelector {
167 moniker_segments: Some(vec![StringSelector::StringPattern("**".into())]),
168 ..Default::default()
169 },
170 interest: Interest { min_severity: Some(min_severity), ..Default::default() },
171 });
172 }
173 parse_log_interest_selector(selector)
174}
175
176fn parse_severity(severity: &str) -> Option<Severity> {
177 match severity {
178 "TRACE" => Some(Severity::Trace),
179 "DEBUG" => Some(Severity::Debug),
180 "INFO" => Some(Severity::Info),
181 "WARN" => Some(Severity::Warn),
182 "ERROR" => Some(Severity::Error),
183 "FATAL" => Some(Severity::Fatal),
184 _ => None,
185 }
186}
187
188pub fn parse_selector<E>(unparsed_selector: &str) -> Result<Selector, Error>
190where
191 for<'a> E: ParsingError<'a>,
192{
193 let result = parser::selector::<E>(unparsed_selector)?;
194 Ok(result.into())
195}
196
197pub fn parse_verbose(unparsed_selector: &str) -> Result<Selector, Error> {
198 parse_selector::<VerboseError>(unparsed_selector)
199}
200
201pub fn parse_selector_file<E>(selector_file: &Path) -> Result<Vec<Selector>, Error>
203where
204 E: for<'a> ParsingError<'a>,
205{
206 let selector_file = fs::File::open(selector_file)?;
207 let mut result = Vec::new();
208 let reader = BufReader::new(selector_file);
209 for line in reader.lines() {
210 let line = line?;
211 if line.is_empty() {
212 continue;
213 }
214 if let Some(selector) = parser::selector_or_comment::<E>(&line)? {
215 result.push(selector.into());
216 }
217 }
218 Ok(result)
219}
220
221fn is_special_character(character: char) -> bool {
225 character == ESCAPE_CHARACTER
226 || character == PATH_NODE_DELIMITER
227 || character == SELECTOR_DELIMITER
228 || character == WILDCARD_SYMBOL_CHAR
229 || character == SPACE_CHAR
230 || character == TAB_CHAR
231}
232
233pub fn sanitize_string_for_selectors(node: &str) -> Cow<'_, str> {
238 if node.is_empty() {
239 return Cow::Borrowed(node);
240 }
241
242 let mut token_builder = TokenBuilder::new(node);
243 for (index, node_char) in node.char_indices() {
244 token_builder.maybe_init(index);
245 if is_special_character(node_char) {
246 token_builder.turn_into_string();
247 token_builder.push(ESCAPE_CHARACTER, index);
248 }
249 token_builder.push(node_char, index);
250 }
251
252 token_builder.take()
253}
254
255pub fn sanitize_moniker_for_selectors(moniker: impl AsRef<str>) -> String {
260 moniker.as_ref().replace(":", "\\:")
261}
262
263fn match_moniker_against_component_selector<I, S>(
264 mut moniker_segments: I,
265 component_selector: &ComponentSelector,
266) -> Result<bool, anyhow::Error>
267where
268 I: Iterator<Item = S>,
269 S: AsRef<str>,
270{
271 let selector_segments = match &component_selector.moniker_segments {
272 Some(ref path_vec) => path_vec,
273 None => return Err(format_err!("Component selectors require moniker segments.")),
274 };
275
276 for (i, selector_segment) in selector_segments.iter().enumerate() {
277 let Some(moniker_segment) = moniker_segments.next() else {
279 return Ok(false);
280 };
281
282 if i == selector_segments.len() - 1
284 && string_selector_contains_recursive_glob(selector_segment)
285 {
286 return Ok(true);
287 }
288
289 if !match_string(selector_segment, moniker_segment.as_ref()) {
290 return Ok(false);
291 }
292 }
293
294 if moniker_segments.next().is_some() {
296 return Ok(false);
297 }
298
299 Ok(true)
300}
301
302fn match_component_and_tree_name<T>(
309 moniker: impl AsRef<[T]>,
310 tree_name: &str,
311 selector: &Selector,
312) -> Result<bool, anyhow::Error>
313where
314 T: AsRef<str>,
315{
316 Ok(match_component_moniker_against_selector(moniker, selector)?
317 && match_tree_name_against_selector(tree_name, selector))
318}
319
320pub fn match_tree_name_against_selector(tree_name: &str, selector: &Selector) -> bool {
325 match selector.tree_names.as_ref() {
326 Some(TreeNames::All(_)) => true,
327
328 Some(TreeNames::Some(filters)) => filters.iter().any(|f| f == tree_name),
329
330 None => tree_name == DEFAULT_TREE_NAME,
331
332 Some(TreeNames::__SourceBreaking { .. }) => false,
333 }
334}
335
336fn match_component_moniker_against_selector<T>(
342 moniker: impl AsRef<[T]>,
343 selector: &Selector,
344) -> Result<bool, anyhow::Error>
345where
346 T: AsRef<str>,
347{
348 selector.validate()?;
349
350 if moniker.as_ref().is_empty() {
351 return Err(format_err!(
352 "Cannot have empty monikers, at least the component name is required."
353 ));
354 }
355
356 let component_selector = selector.component_selector.as_ref().unwrap();
358
359 match_moniker_against_component_selector(moniker.as_ref().iter(), component_selector)
360}
361
362fn match_component_moniker_against_selectors<'a>(
368 moniker: Vec<String>,
369 selectors: impl IntoIterator<Item = &'a Selector>,
370) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
371 selectors
372 .into_iter()
373 .map(|selector| {
374 selector.validate()?;
375 Ok(selector)
376 })
377 .filter_map(move |selector| -> Option<Result<&'a Selector, anyhow::Error>> {
378 let Ok(selector) = selector else {
379 return Some(selector);
380 };
381 match_component_moniker_against_selector(moniker.as_slice(), selector)
382 .map(|is_match| if is_match { Some(selector) } else { None })
383 .transpose()
384 })
385}
386
387fn match_moniker_against_component_selectors<'a, S, T>(
393 moniker: &[T],
394 selectors: &'a [S],
395) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
396where
397 S: Borrow<ComponentSelector> + 'a,
398 T: AsRef<str> + std::string::ToString,
399{
400 if moniker.is_empty() {
401 return Err(format_err!(
402 "Cannot have empty monikers, at least the component name is required."
403 ));
404 }
405
406 let component_selectors = selectors
407 .iter()
408 .map(|selector| {
409 let component_selector = selector.borrow();
410 component_selector.validate()?;
411 Ok(component_selector)
412 })
413 .collect::<Result<Vec<&ComponentSelector>, anyhow::Error>>();
414
415 component_selectors?
416 .iter()
417 .filter_map(|selector| {
418 match_moniker_against_component_selector(moniker.iter(), selector)
419 .map(|is_match| if is_match { Some(*selector) } else { None })
420 .transpose()
421 })
422 .collect::<Result<Vec<&ComponentSelector>, anyhow::Error>>()
423}
424
425pub struct SelectorDisplayOptions {
428 allow_wrapper_quotes: bool,
429}
430
431impl std::default::Default for SelectorDisplayOptions {
432 fn default() -> Self {
433 Self { allow_wrapper_quotes: true }
434 }
435}
436
437impl SelectorDisplayOptions {
438 pub fn never_wrap_in_quotes() -> Self {
440 Self { allow_wrapper_quotes: false }
441 }
442}
443
444pub fn selector_to_string(
454 selector: &Selector,
455 opts: SelectorDisplayOptions,
456) -> Result<String, anyhow::Error> {
457 fn contains_chars_requiring_wrapper_quotes(segment: &str) -> bool {
458 segment.contains('/') || segment.contains('*')
459 }
460
461 selector.validate()?;
462
463 let component_selector = selector
464 .component_selector
465 .as_ref()
466 .ok_or_else(|| format_err!("component selector missing"))?;
467 let (node_path, maybe_property_selector) = match selector
468 .tree_selector
469 .as_ref()
470 .ok_or_else(|| format_err!("tree selector missing"))?
471 {
472 TreeSelector::SubtreeSelector(SubtreeSelector { node_path, .. }) => (node_path, None),
473 TreeSelector::PropertySelector(PropertySelector {
474 node_path, target_properties, ..
475 }) => (node_path, Some(target_properties)),
476 _ => return Err(format_err!("unknown tree selector type")),
477 };
478
479 let mut needs_to_be_quoted = false;
480 let result = component_selector
481 .moniker_segments
482 .as_ref()
483 .ok_or_else(|| format_err!("moniker segments missing in component selector"))?
484 .iter()
485 .map(|segment| match segment {
486 StringSelector::StringPattern(p) => {
487 needs_to_be_quoted = true;
488 Ok(p)
489 }
490 StringSelector::ExactMatch(s) => {
491 needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
492 Ok(s)
493 }
494 fdiagnostics::StringSelectorUnknown!() => {
495 Err(format_err!("uknown StringSelector variant"))
496 }
497 })
498 .collect::<Result<Vec<_>, _>>()?
499 .into_iter()
500 .join("/");
501
502 let mut result = sanitize_moniker_for_selectors(&result);
503
504 let mut tree_selector_str = node_path
505 .iter()
506 .map(|segment| {
507 Ok(match segment {
508 StringSelector::StringPattern(p) => {
509 needs_to_be_quoted = true;
510 p.to_string()
511 }
512 StringSelector::ExactMatch(s) => {
513 needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
514 sanitize_string_for_selectors(s).to_string()
515 }
516 fdiagnostics::StringSelectorUnknown!() => {
517 return Err(format_err!("uknown StringSelector variant"))
518 }
519 })
520 })
521 .collect::<Result<Vec<String>, _>>()?
522 .into_iter()
523 .join("/");
524
525 if let Some(target_property) = maybe_property_selector {
526 tree_selector_str.push(':');
527 tree_selector_str.push_str(&match target_property {
528 StringSelector::StringPattern(p) => {
529 needs_to_be_quoted = true;
530 p.to_string()
531 }
532 StringSelector::ExactMatch(s) => {
533 needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
534 sanitize_string_for_selectors(s).to_string()
535 }
536 fdiagnostics::StringSelectorUnknown!() => {
537 return Err(format_err!("uknown StringSelector variant"))
538 }
539 });
540 }
541
542 tree_selector_str = match &selector.tree_names {
543 None => tree_selector_str,
544 Some(names) => match names {
545 TreeNames::Some(names) => {
546 let list = names
547 .iter()
548 .filter_map(|name| {
549 if name == DEFAULT_TREE_NAME {
550 return None;
551 }
552
553 for c in name.chars() {
554 if !(c.is_alphanumeric() || c == '-' || c == '_') {
555 return Some(format!(r#"name="{name}""#));
556 }
557 }
558
559 Some(format!("name={name}"))
560 })
561 .join(",");
562
563 if list.is_empty() {
564 tree_selector_str
565 } else {
566 needs_to_be_quoted = true;
567 format!("[{list}]{tree_selector_str}")
568 }
569 }
570 TreeNames::All(_) => {
571 needs_to_be_quoted = true;
572 format!("[...]{tree_selector_str}")
573 }
574 fdiagnostics::TreeNamesUnknown!() => {
575 return Err(format_err!("unknown TreeNames variant"));
576 }
577 },
578 };
579
580 result.push_str(&format!(":{tree_selector_str}"));
581
582 if needs_to_be_quoted && opts.allow_wrapper_quotes {
583 Ok(format!(r#""{result}""#))
584 } else {
585 Ok(result)
586 }
587}
588
589pub fn match_string(selector: &StringSelector, target: impl AsRef<str>) -> bool {
591 match selector {
592 StringSelector::ExactMatch(s) => s == target.as_ref(),
593 StringSelector::StringPattern(pattern) => match_pattern(pattern, target.as_ref()),
594 _ => false,
595 }
596}
597
598fn match_pattern(pattern: &str, target: &str) -> bool {
599 let mut pattern_tokens = vec![];
601 let mut token = TokenBuilder::new(pattern);
602 let mut chars = pattern.char_indices();
603
604 while let Some((index, curr_char)) = chars.next() {
605 token.maybe_init(index);
606
607 match curr_char {
609 '\\' => {
610 match chars.next() {
611 Some((i, c)) => {
612 token.turn_into_string();
613 token.push(c, i);
614 }
615 None => return false,
618 }
619 }
620 '*' => {
621 if !token.is_empty() {
622 pattern_tokens.push(token.take());
623 }
624 token = TokenBuilder::new(pattern);
625 }
626 c => {
627 token.push(c, index);
628 }
629 }
630 }
631
632 if !token.is_empty() {
634 pattern_tokens.push(token.take());
635 }
636
637 if pattern_tokens.is_empty() && !pattern.is_empty() {
639 return true;
640 }
641
642 if !pattern.starts_with('*') && !target.starts_with(pattern_tokens[0].as_ref()) {
645 return false;
646 }
647
648 if !pattern.ends_with('*')
651 && pattern.chars().rev().nth(1) != Some('\\')
652 && !target.ends_with(pattern_tokens[pattern_tokens.len() - 1].as_ref())
653 {
654 return false;
655 }
656
657 let mut cur_string = target;
660 for pattern in pattern_tokens.iter() {
661 match cur_string.find(pattern.as_ref()) {
662 Some(i) => {
663 cur_string = &cur_string[i + pattern.len()..];
664 }
665 None => {
666 return false;
667 }
668 }
669 }
670
671 true
672}
673
674#[derive(Debug)]
677enum TokenBuilder<'a> {
678 Init(&'a str),
679 Slice { string: &'a str, start: usize, end: Option<usize> },
680 String(String),
681}
682
683impl<'a> TokenBuilder<'a> {
684 fn new(string: &'a str) -> Self {
685 Self::Init(string)
686 }
687
688 fn maybe_init(&mut self, start_index: usize) {
689 let Self::Init(s) = self else {
690 return;
691 };
692 *self = Self::Slice { string: s, start: start_index, end: None };
693 }
694
695 fn turn_into_string(&mut self) {
696 if let Self::Slice { string, start, end } = self {
697 if let Some(end) = end {
698 *self = Self::String(string[*start..=*end].to_string());
699 } else {
700 *self = Self::String(String::new());
703 }
704 }
705 }
706
707 fn push(&mut self, c: char, index: usize) {
708 match self {
709 Self::Slice { end, .. } => {
710 *end = Some(index);
711 }
712 Self::String(s) => s.push(c),
713 Self::Init(_) => unreachable!(),
714 }
715 }
716
717 fn take(self) -> Cow<'a, str> {
718 match self {
719 Self::Slice { string, start, end: Some(end) } => Cow::Borrowed(&string[start..=end]),
720 Self::Slice { string, start, end: None } => Cow::Borrowed(&string[start..start]),
721 Self::String(s) => Cow::Owned(s),
722 Self::Init(_) => unreachable!(),
723 }
724 }
725
726 fn is_empty(&self) -> bool {
727 match self {
728 Self::Slice { start, end: Some(end), .. } => start > end,
729 Self::Slice { end: None, .. } => true,
730 Self::String(s) => s.is_empty(),
731 Self::Init(_) => true,
732 }
733 }
734}
735
736pub trait SelectorExt {
737 fn match_against_selectors<'a>(
738 &self,
739 selectors: impl IntoIterator<Item = &'a Selector>,
740 ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>>;
741
742 fn match_against_selectors_and_tree_name<'a>(
744 &self,
745 tree_name: &str,
746 selectors: impl IntoIterator<Item = &'a Selector>,
747 ) -> impl Iterator<Item = &'a Selector>;
748
749 fn match_against_component_selectors<'a, S>(
750 &self,
751 selectors: &'a [S],
752 ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
753 where
754 S: Borrow<ComponentSelector>;
755
756 fn into_component_selector(self) -> ComponentSelector;
757
758 fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error>;
759
760 fn matches_component_selector(
761 &self,
762 selector: &ComponentSelector,
763 ) -> Result<bool, anyhow::Error>;
764
765 fn sanitized(&self) -> String;
766}
767
768impl SelectorExt for ExtendedMoniker {
769 fn match_against_selectors<'a>(
770 &self,
771 selectors: impl IntoIterator<Item = &'a Selector>,
772 ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
773 let s = match self {
774 ExtendedMoniker::ComponentManager => {
775 vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string()]
776 }
777 ExtendedMoniker::ComponentInstance(moniker) => {
778 SegmentIterator::from(moniker).collect::<Vec<_>>()
779 }
780 };
781
782 match_component_moniker_against_selectors(s, selectors)
783 }
784
785 fn match_against_selectors_and_tree_name<'a>(
786 &self,
787 tree_name: &str,
788 selectors: impl IntoIterator<Item = &'a Selector>,
789 ) -> impl Iterator<Item = &'a Selector> {
790 let m = match self {
791 ExtendedMoniker::ComponentManager => {
792 vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string()]
793 }
794 ExtendedMoniker::ComponentInstance(moniker) => {
795 SegmentIterator::from(moniker).collect::<Vec<_>>()
796 }
797 };
798
799 selectors
800 .into_iter()
801 .filter(move |s| match_component_and_tree_name(&m, tree_name, s).unwrap_or(false))
802 }
803
804 fn match_against_component_selectors<'a, S>(
805 &self,
806 selectors: &'a [S],
807 ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
808 where
809 S: Borrow<ComponentSelector>,
810 {
811 match self {
812 ExtendedMoniker::ComponentManager => match_moniker_against_component_selectors(
813 &[EXTENDED_MONIKER_COMPONENT_MANAGER_STR],
814 selectors,
815 ),
816 ExtendedMoniker::ComponentInstance(moniker) => {
817 moniker.match_against_component_selectors(selectors)
818 }
819 }
820 }
821
822 fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error> {
823 match self {
824 ExtendedMoniker::ComponentManager => match_component_moniker_against_selector(
825 [EXTENDED_MONIKER_COMPONENT_MANAGER_STR],
826 selector,
827 ),
828 ExtendedMoniker::ComponentInstance(moniker) => moniker.matches_selector(selector),
829 }
830 }
831
832 fn matches_component_selector(
833 &self,
834 selector: &ComponentSelector,
835 ) -> Result<bool, anyhow::Error> {
836 match self {
837 ExtendedMoniker::ComponentManager => match_moniker_against_component_selector(
838 [EXTENDED_MONIKER_COMPONENT_MANAGER_STR].into_iter(),
839 selector,
840 ),
841 ExtendedMoniker::ComponentInstance(moniker) => {
842 moniker.matches_component_selector(selector)
843 }
844 }
845 }
846
847 fn sanitized(&self) -> String {
848 match self {
849 ExtendedMoniker::ComponentManager => EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string(),
850 ExtendedMoniker::ComponentInstance(moniker) => moniker.sanitized(),
851 }
852 }
853
854 fn into_component_selector(self) -> ComponentSelector {
855 ComponentSelector {
856 moniker_segments: Some(
857 match self {
858 ExtendedMoniker::ComponentManager => {
859 vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.into()]
860 }
861 ExtendedMoniker::ComponentInstance(moniker) => {
862 moniker.path().iter().map(|value| value.to_string()).collect()
863 }
864 }
865 .into_iter()
866 .map(StringSelector::ExactMatch)
867 .collect(),
868 ),
869 ..Default::default()
870 }
871 }
872}
873
874impl SelectorExt for Moniker {
875 fn match_against_selectors<'a>(
876 &self,
877 selectors: impl IntoIterator<Item = &'a Selector>,
878 ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
879 let s = SegmentIterator::from(self).collect::<Vec<_>>();
880 match_component_moniker_against_selectors(s, selectors)
881 }
882
883 fn match_against_selectors_and_tree_name<'a>(
884 &self,
885 tree_name: &str,
886 selectors: impl IntoIterator<Item = &'a Selector>,
887 ) -> impl Iterator<Item = &'a Selector> {
888 let m = SegmentIterator::from(self).collect::<Vec<_>>();
889
890 selectors
891 .into_iter()
892 .filter(move |s| match_component_and_tree_name(&m, tree_name, s).unwrap_or(false))
893 }
894
895 fn match_against_component_selectors<'a, S>(
896 &self,
897 selectors: &'a [S],
898 ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
899 where
900 S: Borrow<ComponentSelector>,
901 {
902 let s = SegmentIterator::from(self).collect::<Vec<_>>();
903 match_moniker_against_component_selectors(&s, selectors)
904 }
905
906 fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error> {
907 let s = SegmentIterator::from(self).collect::<Vec<_>>();
908 match_component_moniker_against_selector(&s, selector)
909 }
910
911 fn matches_component_selector(
912 &self,
913 selector: &ComponentSelector,
914 ) -> Result<bool, anyhow::Error> {
915 match_moniker_against_component_selector(SegmentIterator::from(self), selector)
916 }
917
918 fn sanitized(&self) -> String {
919 SegmentIterator::from(self)
920 .map(|s| sanitize_string_for_selectors(&s).into_owned())
921 .collect::<Vec<String>>()
922 .join("/")
923 }
924
925 fn into_component_selector(self) -> ComponentSelector {
926 ComponentSelector {
927 moniker_segments: Some(
928 self.path()
929 .iter()
930 .map(|value| StringSelector::ExactMatch(value.to_string()))
931 .collect(),
932 ),
933 ..Default::default()
934 }
935 }
936}
937
938enum SegmentIterator<'a> {
939 Iter { path: &'a [ChildName], current_index: usize },
940 Root(bool),
941}
942
943impl<'a> From<&'a Moniker> for SegmentIterator<'a> {
944 fn from(moniker: &'a Moniker) -> Self {
945 let path = moniker.path();
946 if path.is_empty() {
947 return SegmentIterator::Root(false);
948 }
949 SegmentIterator::Iter { path: path.as_slice(), current_index: 0 }
950 }
951}
952
953impl Iterator for SegmentIterator<'_> {
954 type Item = String;
955 fn next(&mut self) -> Option<Self::Item> {
956 match self {
957 Self::Iter { path, current_index } => {
958 let segment = path.get(*current_index)?;
959 let result = segment.to_string();
960 *self = Self::Iter { path, current_index: *current_index + 1 };
961 Some(result)
962 }
963 Self::Root(true) => None,
964 Self::Root(done) => {
965 *done = true;
966 Some("<root>".to_string())
967 }
968 }
969 }
970}
971
972#[cfg(test)]
973mod tests {
974 use super::*;
975 use std::fs::File;
976 use std::io::prelude::*;
977 use std::path::PathBuf;
978 use std::str::FromStr;
979 use tempfile::TempDir;
980 use test_case::test_case;
981
982 pub fn parse_selectors<E>(directory: &Path) -> Result<Vec<Selector>, Error>
984 where
985 E: for<'a> ParsingError<'a>,
986 {
987 let path: PathBuf = directory.to_path_buf();
988 let mut selector_vec: Vec<Selector> = Vec::new();
989 for entry in fs::read_dir(path)? {
990 let entry = entry?;
991 if entry.path().is_dir() {
992 return Err(Error::NonFlatDirectory);
993 } else {
994 selector_vec.append(&mut parse_selector_file::<E>(&entry.path())?);
995 }
996 }
997 Ok(selector_vec)
998 }
999
1000 #[fuchsia::test]
1001 fn successful_selector_parsing() {
1002 let tempdir = TempDir::new().expect("failed to create tmp dir");
1003 File::create(tempdir.path().join("a.txt"))
1004 .expect("create file")
1005 .write_all(
1006 b"a:b:c
1007
1008",
1009 )
1010 .expect("writing test file");
1011 File::create(tempdir.path().join("b.txt"))
1012 .expect("create file")
1013 .write_all(b"a*/b:c/d/*:*")
1014 .expect("writing test file");
1015
1016 File::create(tempdir.path().join("c.txt"))
1017 .expect("create file")
1018 .write_all(
1019 b"// this is a comment
1020a:b:c
1021",
1022 )
1023 .expect("writing test file");
1024
1025 assert!(parse_selectors::<VerboseError>(tempdir.path()).is_ok());
1026 }
1027
1028 #[fuchsia::test]
1029 fn unsuccessful_selector_parsing_bad_selector() {
1030 let tempdir = TempDir::new().expect("failed to create tmp dir");
1031 File::create(tempdir.path().join("a.txt"))
1032 .expect("create file")
1033 .write_all(b"a:b:c")
1034 .expect("writing test file");
1035 File::create(tempdir.path().join("b.txt"))
1036 .expect("create file")
1037 .write_all(b"**:**:**")
1038 .expect("writing test file");
1039
1040 assert!(parse_selectors::<VerboseError>(tempdir.path()).is_err());
1041 }
1042
1043 #[fuchsia::test]
1044 fn unsuccessful_selector_parsing_nonflat_dir() {
1045 let tempdir = TempDir::new().expect("failed to create tmp dir");
1046 File::create(tempdir.path().join("a.txt"))
1047 .expect("create file")
1048 .write_all(b"a:b:c")
1049 .expect("writing test file");
1050 File::create(tempdir.path().join("b.txt"))
1051 .expect("create file")
1052 .write_all(b"**:**:**")
1053 .expect("writing test file");
1054
1055 std::fs::create_dir_all(tempdir.path().join("nested")).expect("make nested");
1056 File::create(tempdir.path().join("nested/c.txt"))
1057 .expect("create file")
1058 .write_all(b"**:**:**")
1059 .expect("writing test file");
1060 assert!(parse_selectors::<VerboseError>(tempdir.path()).is_err());
1061 }
1062
1063 #[fuchsia::test]
1064 fn component_selector_match_test() {
1065 let passing_test_cases = vec![
1068 (r#"echo:*:*"#, vec!["echo"]),
1069 (r#"*/echo:*:*"#, vec!["abc", "echo"]),
1070 (r#"ab*/echo:*:*"#, vec!["abc", "echo"]),
1071 (r#"ab*/echo:*:*"#, vec!["abcde", "echo"]),
1072 (r#"*/ab*/echo:*:*"#, vec!["123", "abcde", "echo"]),
1073 (r#"echo*:*:*"#, vec!["echo"]),
1074 (r#"a/echo*:*:*"#, vec!["a", "echo1"]),
1075 (r#"a/echo*:*:*"#, vec!["a", "echo"]),
1076 (r#"ab*/echo:*:*"#, vec!["ab", "echo"]),
1077 (r#"a/**:*:*"#, vec!["a", "echo"]),
1078 (r#"a/**:*:*"#, vec!["a", "b", "echo"]),
1079 ];
1080
1081 for (selector, moniker) in passing_test_cases {
1082 let parsed_selector = parse_selector::<VerboseError>(selector).unwrap();
1083 assert!(
1084 match_component_moniker_against_selector(&moniker, &parsed_selector).unwrap(),
1085 "Selector {:?} failed to match {:?}",
1086 selector,
1087 moniker
1088 );
1089 }
1090
1091 let failing_test_cases = vec![
1094 (r#"*:*:*"#, vec!["a", "echo"]),
1095 (r#"*/echo:*:*"#, vec!["123", "abc", "echo"]),
1096 (r#"a/**:*:*"#, vec!["b", "echo"]),
1097 (r#"e/**:*:*"#, vec!["echo"]),
1098 ];
1099
1100 for (selector, moniker) in failing_test_cases {
1101 let parsed_selector = parse_selector::<VerboseError>(selector).unwrap();
1102 assert!(
1103 !match_component_moniker_against_selector(&moniker, &parsed_selector).unwrap(),
1104 "Selector {:?} matched {:?}, but was expected to fail",
1105 selector,
1106 moniker
1107 );
1108 }
1109 }
1110
1111 #[fuchsia::test]
1112 fn multiple_component_selectors_match_test() {
1113 let selectors = vec![r#"*/echo"#, r#"ab*/echo"#, r#"abc/m*"#];
1114 let moniker = vec!["abc".to_string(), "echo".to_string()];
1115
1116 let component_selectors = selectors
1117 .into_iter()
1118 .map(|selector| parse_component_selector::<VerboseError>(selector).unwrap())
1119 .collect::<Vec<_>>();
1120
1121 let match_res =
1122 match_moniker_against_component_selectors(moniker.as_slice(), &component_selectors[..]);
1123 assert!(match_res.is_ok());
1124 assert_eq!(match_res.unwrap().len(), 2);
1125 }
1126
1127 #[test_case("a/b:c:d", "a/b:c:d" ; "no_wrap_with_basic_full_selector")]
1128 #[test_case("a/b:c", "a/b:c" ; "no_wrap_with_basic_partial_selector")]
1129 #[test_case(r"a/b:c/d\/e:f", r#"a/b:c/d\/e:f"# ; "no_wrap_with_escaped_forward_slash")]
1130 #[test_case(r"a/b:[name=root]c:d", "a/b:c:d" ; "no_wrap_with_default_name")]
1131 #[test_case(r"a/b:[name=cd-e]f:g", r#"a/b:[name=cd-e]f:g"# ; "no_wrap_with_non_default_name")]
1132 #[test_case(
1133 r#"a:[name="bc-d"]e:f"#,
1134 r"a:[name=bc-d]e:f"
1135 ; "no_wrap_with_unneeded_name_quotes"
1136 )]
1137 #[test_case(
1138 r#"a:[name="b[]c"]d:e"#,
1139 r#"a:[name="b[]c"]d:e"#
1140 ; "no_wrap_with_needed_name_quotes"
1141 )]
1142 #[test_case("a/b:[...]c:d", r#"a/b:[...]c:d"# ; "no_wrap_with_all_names")]
1143 #[test_case(
1144 r#"a/b:[name=c, name="d", name="f[]g"]h:i"#,
1145 r#"a/b:[name=c,name=d,name="f[]g"]h:i"#
1146 ; "no_wrap_with_name_list"
1147 )]
1148 #[test_case(r"a\:b/c:d:e", r"a\:b/c:d:e" ; "no_wrap_with_collection")]
1149 #[test_case(r"a/b/c*d:e:f", r#"a/b/c*d:e:f"# ; "no_wrap_with_wildcard_component")]
1150 #[test_case(r"a/b:c*/d:e", r#"a/b:c*/d:e"# ; "no_wrap_with_wildcard_tree")]
1151 #[test_case(r"a/b:c\*/d:e", r#"a/b:c\*/d:e"# ; "no_wrap_with_escaped_wildcard_tree")]
1152 #[test_case(r"a/b/c/d:e/f:g*", r#"a/b/c/d:e/f:g*"# ; "no_wrap_with_wildcard_property")]
1153 #[test_case(r"a/b/c/d:e/f:g*", r#"a/b/c/d:e/f:g*"# ; "no_wrap_with_escaped_wildcard_property")]
1154 #[test_case("a/b/c/d:e/f/g/h:k", "a/b/c/d:e/f/g/h:k" ; "no_wrap_with_deep_nesting")]
1155 #[fuchsia::test]
1156 fn selector_to_string_test_never_wrap(input: &str, expected: &str) {
1157 let selector = parse_verbose(input).unwrap();
1158 assert_eq!(
1159 selector_to_string(&selector, SelectorDisplayOptions::never_wrap_in_quotes()).unwrap(),
1160 expected,
1161 "left: actual, right: expected"
1162 );
1163 }
1164
1165 #[test_case("a/b:c:d", "a/b:c:d" ; "with_basic_full_selector")]
1166 #[test_case("a/b:c", "a/b:c" ; "with_basic_partial_selector")]
1167 #[test_case(r"a/b:c/d\/e:f", r#""a/b:c/d\/e:f""# ; "with_escaped_forward_slash")]
1168 #[test_case(r"a/b:[name=root]c:d", "a/b:c:d" ; "with_default_name")]
1169 #[test_case(r"a/b:[name=cd-e]f:g", r#""a/b:[name=cd-e]f:g""# ; "with_non_default_name")]
1170 #[test_case(r#"a:[name="bc-d"]e:f"#, r#""a:[name=bc-d]e:f""# ; "with_unneeded_name_quotes")]
1171 #[test_case(r#"a:[name="b[]c"]d:e"#, r#""a:[name="b[]c"]d:e""# ; "with_needed_name_quotes")]
1172 #[test_case("a/b:[...]c:d", r#""a/b:[...]c:d""# ; "with_all_names")]
1173 #[test_case(
1174 r#"a/b:[name=c, name="d", name="f[]g"]h:i"#,
1175 r#""a/b:[name=c,name=d,name="f[]g"]h:i""#
1176 ; "with_name_list"
1177 )]
1178 #[test_case(r"a\:b/c:d:e", r"a\:b/c:d:e" ; "with_collection")]
1179 #[test_case(r"a/b/c*d:e:f", r#""a/b/c*d:e:f""# ; "with_wildcard_component")]
1180 #[test_case(r"a/b:c*/d:e", r#""a/b:c*/d:e""# ; "with_wildcard_tree")]
1181 #[test_case(r"a/b:c\*/d:e", r#""a/b:c\*/d:e""# ; "with_escaped_wildcard_tree")]
1182 #[test_case(r"a/b/c/d:e/f:g*", r#""a/b/c/d:e/f:g*""# ; "with_wildcard_property")]
1183 #[test_case(r"a/b/c/d:e/f:g*", r#""a/b/c/d:e/f:g*""# ; "with_escaped_wildcard_property")]
1184 #[test_case("a/b/c/d:e/f/g/h:k", "a/b/c/d:e/f/g/h:k" ; "with_deep_nesting")]
1185 #[fuchsia::test]
1186 fn selector_to_string_test_default(input: &str, expected: &str) {
1187 let selector = parse_verbose(input).unwrap();
1188 assert_eq!(
1189 selector_to_string(&selector, SelectorDisplayOptions::default()).unwrap(),
1190 expected,
1191 "left: actual, right: expected"
1192 );
1193 }
1194
1195 #[test_case("a*", r"a\*" ; "when_star_not_leading")]
1196 #[test_case("a:", r"a\:" ; "when_colon_not_leading")]
1197 #[test_case(":", r"\:" ; "when_colon_leading")]
1198 #[test_case("*", r"\*" ; "when_star_leading")]
1199 #[test_case(r"*:\abc", r"\*\:\\abc" ; "when_mixed_with_leading_special_chars")]
1200 #[fuchsia::test]
1201 fn sanitize_string_for_selectors_works(input: &str, expected: &str) {
1202 assert_eq!(sanitize_string_for_selectors(input), expected);
1203 }
1204
1205 #[fuchsia::test]
1206 fn sanitize_moniker_for_selectors_result_is_usable() {
1207 let selector = parse_selector::<VerboseError>(&format!(
1208 "{}:root",
1209 sanitize_moniker_for_selectors("foo/coll:bar/baz")
1210 ))
1211 .unwrap();
1212 let component_selector = selector.component_selector.as_ref().unwrap();
1213 let moniker = ["foo", "coll:bar", "baz"];
1214 assert!(
1215 match_moniker_against_component_selector(moniker.iter(), component_selector).unwrap()
1216 );
1217 }
1218
1219 #[fuchsia::test]
1220 fn escaped_spaces() {
1221 let selector_str = "foo:bar\\ baz/a*\\ b:quux";
1222 let selector = parse_selector::<VerboseError>(selector_str).unwrap();
1223 assert_eq!(
1224 selector,
1225 Selector {
1226 component_selector: Some(ComponentSelector {
1227 moniker_segments: Some(vec![StringSelector::ExactMatch("foo".into()),]),
1228 ..Default::default()
1229 }),
1230 tree_selector: Some(TreeSelector::PropertySelector(PropertySelector {
1231 node_path: vec![
1232 StringSelector::ExactMatch("bar baz".into()),
1233 StringSelector::StringPattern("a* b".into()),
1234 ],
1235 target_properties: StringSelector::ExactMatch("quux".into())
1236 })),
1237 ..Default::default()
1238 }
1239 );
1240 }
1241
1242 #[fuchsia::test]
1243 fn match_string_test() {
1244 assert!(match_string(&StringSelector::ExactMatch("foo".into()), "foo"));
1246
1247 assert!(match_string(&StringSelector::StringPattern("*foo*".into()), "hellofoobye"));
1249 assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoo"));
1250 assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barfoo"));
1251 assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoo"));
1252 assert!(match_string(&StringSelector::StringPattern("foo*".into()), "foobar"));
1253 assert!(match_string(&StringSelector::StringPattern("*".into()), "foo"));
1254 assert!(match_string(&StringSelector::StringPattern("bar*baz*foo".into()), "barxzybazfoo"));
1255 assert!(match_string(&StringSelector::StringPattern("foo*bar*baz".into()), "foobazbarbaz"));
1256
1257 assert!(match_string(&StringSelector::StringPattern("foo\\*".into()), "foo*"));
1259
1260 assert!(!match_string(&StringSelector::StringPattern("foo\\".into()), "foo\\"));
1262 assert!(!match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoox"));
1263 assert!(!match_string(&StringSelector::StringPattern("m*".into()), "echo.csx"));
1264 assert!(!match_string(&StringSelector::StringPattern("*foo*".into()), "xbary"));
1265 assert!(!match_string(
1266 &StringSelector::StringPattern("foo*bar*baz*qux".into()),
1267 "foobarbaazqux"
1268 ));
1269 }
1270
1271 #[fuchsia::test]
1272 fn test_log_interest_selector() {
1273 assert_eq!(
1274 parse_log_interest_selector("core/network#FATAL").unwrap(),
1275 LogInterestSelector {
1276 selector: parse_component_selector::<VerboseError>("core/network").unwrap(),
1277 interest: Interest { min_severity: Some(Severity::Fatal), ..Default::default() }
1278 }
1279 );
1280 assert_eq!(
1281 parse_log_interest_selector("any/component#INFO").unwrap(),
1282 LogInterestSelector {
1283 selector: parse_component_selector::<VerboseError>("any/component").unwrap(),
1284 interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1285 }
1286 );
1287 assert_eq!(
1288 parse_log_interest_selector("any/coll:instance/foo#INFO").unwrap(),
1289 LogInterestSelector {
1290 selector: parse_component_selector::<VerboseError>("any/coll\\:instance/foo")
1291 .unwrap(),
1292 interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1293 }
1294 );
1295 assert_eq!(
1296 parse_log_interest_selector("any/coll:*/foo#INFO").unwrap(),
1297 LogInterestSelector {
1298 selector: parse_component_selector::<VerboseError>("any/coll\\:*/foo").unwrap(),
1299 interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1300 }
1301 );
1302 }
1303 #[test]
1304 fn test_log_interest_selector_error() {
1305 assert!(parse_log_interest_selector("anything////#FATAL").is_err());
1306 assert!(parse_log_interest_selector("core/network").is_err());
1307 assert!(parse_log_interest_selector("core/network#FAKE").is_err());
1308 assert!(parse_log_interest_selector("core/network\\:foo#FAKE").is_err());
1309 }
1310
1311 #[test]
1312 fn test_moniker_to_selector() {
1313 assert_eq!(
1314 Moniker::from_str("a/b/c").unwrap().into_component_selector(),
1315 parse_component_selector::<VerboseError>("a/b/c").unwrap()
1316 );
1317 assert_eq!(
1318 ExtendedMoniker::ComponentManager.into_component_selector(),
1319 parse_component_selector::<VerboseError>("<component_manager>").unwrap()
1320 );
1321 assert_eq!(
1322 ExtendedMoniker::ComponentInstance(Moniker::from_str("a/b/c").unwrap())
1323 .into_component_selector(),
1324 parse_component_selector::<VerboseError>("a/b/c").unwrap()
1325 );
1326 assert_eq!(
1327 ExtendedMoniker::ComponentInstance(Moniker::from_str("a/coll:id/c").unwrap())
1328 .into_component_selector(),
1329 parse_component_selector::<VerboseError>("a/coll\\:id/c").unwrap()
1330 );
1331 }
1332
1333 #[test]
1334 fn test_parse_log_interest_or_severity() {
1335 for (severity_str, severity) in [
1336 ("TRACE", Severity::Trace),
1337 ("DEBUG", Severity::Debug),
1338 ("INFO", Severity::Info),
1339 ("WARN", Severity::Warn),
1340 ("ERROR", Severity::Error),
1341 ("FATAL", Severity::Fatal),
1342 ] {
1343 assert_eq!(
1344 parse_log_interest_selector_or_severity(severity_str).unwrap(),
1345 LogInterestSelector {
1346 selector: parse_component_selector::<VerboseError>("**").unwrap(),
1347 interest: Interest { min_severity: Some(severity), ..Default::default() }
1348 }
1349 );
1350 }
1351
1352 assert_eq!(
1353 parse_log_interest_selector_or_severity("foo/bar#DEBUG").unwrap(),
1354 LogInterestSelector {
1355 selector: parse_component_selector::<VerboseError>("foo/bar").unwrap(),
1356 interest: Interest { min_severity: Some(Severity::Debug), ..Default::default() }
1357 }
1358 );
1359
1360 assert!(parse_log_interest_selector_or_severity("RANDOM").is_err());
1361 assert!(parse_log_interest_selector_or_severity("core/foo#NO#YES").is_err());
1362 }
1363
1364 #[test]
1365 fn test_parse_tree_selector() {
1366 let selector = parse_tree_selector::<VerboseError>("root/node*/nested:prop").unwrap();
1367 assert_eq!(
1368 selector,
1369 TreeSelector::PropertySelector(PropertySelector {
1370 node_path: vec![
1371 StringSelector::ExactMatch("root".into()),
1372 StringSelector::StringPattern("node*".into()),
1373 StringSelector::ExactMatch("nested".into()),
1374 ],
1375 target_properties: StringSelector::ExactMatch("prop".into())
1376 }),
1377 );
1378 }
1379
1380 #[test]
1381 fn test_monikers_against_selectors_and_tree_name() {
1382 let selectors = &[
1383 parse_selector::<VerboseError>("core/foo:root:prop").unwrap(),
1384 parse_selector::<VerboseError>("core/*:[name=root]root:prop").unwrap(),
1385 parse_selector::<VerboseError>("core/baz:[name=baz]root:prop").unwrap(),
1386 parse_selector::<VerboseError>("core/baz:[name=root]root:prop").unwrap(),
1387 parse_selector::<VerboseError>("core/*:[...]root:prop").unwrap(),
1388 parse_selector::<VerboseError>("<component_manager>:root:prop").unwrap(),
1389 ];
1390
1391 {
1392 let foo = ExtendedMoniker::try_from("core/foo").unwrap();
1393
1394 let actual = foo
1395 .match_against_selectors_and_tree_name("root", selectors.iter())
1396 .collect::<Vec<_>>();
1397 assert_eq!(actual, vec![&selectors[0], &selectors[1], &selectors[4]]);
1398
1399 let foo = Moniker::try_from("core/foo").unwrap();
1400
1401 let actual = foo
1402 .match_against_selectors_and_tree_name("root", selectors.iter())
1403 .collect::<Vec<_>>();
1404 assert_eq!(actual, vec![&selectors[0], &selectors[1], &selectors[4]]);
1405 }
1406
1407 {
1408 let baz = ExtendedMoniker::try_from("core/baz").unwrap();
1409
1410 let actual = baz
1411 .match_against_selectors_and_tree_name("root", selectors.iter())
1412 .collect::<Vec<_>>();
1413 assert_eq!(actual, vec![&selectors[1], &selectors[3], &selectors[4]]);
1414
1415 let baz = Moniker::try_from("core/baz").unwrap();
1416
1417 let actual = baz
1418 .match_against_selectors_and_tree_name("root", selectors.iter())
1419 .collect::<Vec<_>>();
1420 assert_eq!(actual, vec![&selectors[1], &selectors[3], &selectors[4]]);
1421 }
1422
1423 {
1424 let baz = ExtendedMoniker::try_from("core/baz").unwrap();
1425
1426 let actual = baz
1427 .match_against_selectors_and_tree_name("baz", selectors.iter())
1428 .collect::<Vec<_>>();
1429 assert_eq!(actual, vec![&selectors[2], &selectors[4]]);
1430
1431 let baz = Moniker::try_from("core/baz").unwrap();
1432
1433 let actual = baz
1434 .match_against_selectors_and_tree_name("baz", selectors.iter())
1435 .collect::<Vec<_>>();
1436 assert_eq!(actual, vec![&selectors[2], &selectors[4]]);
1437 }
1438
1439 {
1440 let qux = ExtendedMoniker::try_from("core/qux").unwrap();
1441
1442 let actual = qux
1443 .match_against_selectors_and_tree_name("qux", selectors.iter())
1444 .collect::<Vec<_>>();
1445 assert_eq!(actual, vec![&selectors[4]]);
1446
1447 let qux = Moniker::try_from("core/qux").unwrap();
1448
1449 let actual = qux
1450 .match_against_selectors_and_tree_name("qux", selectors.iter())
1451 .collect::<Vec<_>>();
1452 assert_eq!(actual, vec![&selectors[4]]);
1453 }
1454
1455 {
1456 let cm = ExtendedMoniker::try_from(EXTENDED_MONIKER_COMPONENT_MANAGER_STR).unwrap();
1457
1458 let actual = cm
1459 .match_against_selectors_and_tree_name("root", selectors.iter())
1460 .collect::<Vec<_>>();
1461 assert_eq!(actual, vec![&selectors[5]]);
1462 }
1463 }
1464}