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