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