selectors/
selectors.rs

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