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