selectors/
selectors.rs

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