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