selectors/
selectors.rs

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