Skip to main content

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