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