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