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