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