selectors/
selectors.rs

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