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    Ok(moniker_segments.next().is_none())
310}
311
312/// Checks whether or not a given selector matches a given moniker and if the given `tree_name` is
313/// present in the selector's tree-name-filter list.
314///
315/// Accounts for semantics like unspecified tree-name-filter lists.
316///
317/// Returns an error if the selector is invalid.
318fn match_component_and_tree_name<T>(
319    moniker: impl AsRef<[T]>,
320    tree_name: &str,
321    selector: &Selector,
322) -> Result<bool, anyhow::Error>
323where
324    T: AsRef<str>,
325{
326    Ok(match_component_moniker_against_selector(moniker, selector)?
327        && match_tree_name_against_selector(tree_name, selector))
328}
329
330/// Checks whether or not a given `tree_name` is present in the selector's
331/// tree-name-filter list.
332///
333/// Accounts for semantics like unspecified tree-name-filter lists.
334pub fn match_tree_name_against_selector(tree_name: &str, selector: &Selector) -> bool {
335    match selector.tree_names.as_ref() {
336        Some(TreeNames::All(_)) => true,
337
338        Some(TreeNames::Some(filters)) => filters.iter().any(|f| f == tree_name),
339
340        None => tree_name == DEFAULT_TREE_NAME,
341
342        Some(TreeNames::__SourceBreaking { .. }) => false,
343    }
344}
345
346/// Evaluates a component moniker against a single selector, returning
347/// True if the selector matches the component, else false.
348///
349/// Requires: hierarchy_path is not empty.
350///           selectors contains valid Selectors.
351fn match_component_moniker_against_selector<T>(
352    moniker: impl AsRef<[T]>,
353    selector: &Selector,
354) -> Result<bool, anyhow::Error>
355where
356    T: AsRef<str>,
357{
358    selector.validate()?;
359
360    if moniker.as_ref().is_empty() {
361        return Err(format_err!(
362            "Cannot have empty monikers, at least the component name is required."
363        ));
364    }
365
366    // Unwrap is safe because the validator ensures there is a component selector.
367    let component_selector = selector.component_selector.as_ref().unwrap();
368
369    match_moniker_against_component_selector(moniker.as_ref().iter(), component_selector)
370}
371
372/// Evaluates a component moniker against a list of selectors, returning
373/// all of the selectors which are matches for that moniker.
374///
375/// Requires: hierarchy_path is not empty.
376///           selectors contains valid Selectors.
377fn match_component_moniker_against_selectors<'a>(
378    moniker: Vec<String>,
379    selectors: impl IntoIterator<Item = &'a Selector>,
380) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
381    selectors
382        .into_iter()
383        .map(|selector| {
384            selector.validate()?;
385            Ok(selector)
386        })
387        .filter_map(move |selector| -> Option<Result<&'a Selector, anyhow::Error>> {
388            let Ok(selector) = selector else {
389                return Some(selector);
390            };
391            match_component_moniker_against_selector(moniker.as_slice(), selector)
392                .map(|is_match| if is_match { Some(selector) } else { None })
393                .transpose()
394        })
395}
396
397/// Evaluates a component moniker against a list of component selectors, returning
398/// all of the component selectors which are matches for that moniker.
399///
400/// Requires: moniker is not empty.
401///           component_selectors contains valid ComponentSelectors.
402fn match_moniker_against_component_selectors<'a, S, T>(
403    moniker: &[T],
404    selectors: &'a [S],
405) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
406where
407    S: Borrow<ComponentSelector> + 'a,
408    T: AsRef<str> + std::string::ToString,
409{
410    if moniker.is_empty() {
411        return Err(format_err!(
412            "Cannot have empty monikers, at least the component name is required."
413        ));
414    }
415
416    let component_selectors = selectors
417        .iter()
418        .map(|selector| {
419            let component_selector = selector.borrow();
420            component_selector.validate()?;
421            Ok(component_selector)
422        })
423        .collect::<Result<Vec<&ComponentSelector>, anyhow::Error>>();
424
425    component_selectors?
426        .iter()
427        .filter_map(|selector| {
428            match_moniker_against_component_selector(moniker.iter(), selector)
429                .map(|is_match| if is_match { Some(*selector) } else { None })
430                .transpose()
431        })
432        .collect::<Result<Vec<&ComponentSelector>, anyhow::Error>>()
433}
434
435/// Returns true if `moniker` matches one of `selectors`.
436///
437/// # Panics
438///
439/// This can panic if any selector in `selectors` is invalid; it assumes `selectors` is valid.
440pub fn matches_selectors(moniker: &ExtendedMoniker, selectors: &[ComponentSelector]) -> bool {
441    match moniker {
442        ExtendedMoniker::ComponentManager => selectors.iter().any(|s| {
443            match_moniker_against_component_selector(
444                once(EXTENDED_MONIKER_COMPONENT_MANAGER_STR),
445                s,
446            )
447            .unwrap()
448        }),
449        ExtendedMoniker::ComponentInstance(moniker) => {
450            if moniker.is_root() {
451                selectors.iter().any(|s| {
452                    match_moniker_against_component_selector(once(ROOT_SEGMENT), s).unwrap()
453                })
454            } else {
455                selectors.iter().any(|s| {
456                    match_moniker_against_component_selector(moniker.into_iter(), s).unwrap()
457                })
458            }
459        }
460    }
461}
462
463/// Settings for how to construct a displayable string from a
464/// `fidl_fuchsia_diagnostics::Selector`.
465pub struct SelectorDisplayOptions {
466    allow_wrapper_quotes: bool,
467}
468
469impl std::default::Default for SelectorDisplayOptions {
470    fn default() -> Self {
471        Self { allow_wrapper_quotes: true }
472    }
473}
474
475impl SelectorDisplayOptions {
476    /// Causes a selector to never be wrapped in exterior quotes.
477    pub fn never_wrap_in_quotes() -> Self {
478        Self { allow_wrapper_quotes: false }
479    }
480}
481
482/// Format a |Selector| as a string.
483///
484/// Returns the formatted |Selector|, or an error if the |Selector| is invalid.
485///
486/// Note that the output will always include both a component and tree selector. If your input is
487/// simply "moniker" you will likely see "moniker:root" as many clients implicitly append "root" if
488/// it is not present (e.g. iquery).
489///
490/// Name filter lists will only be shown if they have non-default tree names.
491pub fn selector_to_string(
492    selector: &Selector,
493    opts: SelectorDisplayOptions,
494) -> Result<String, anyhow::Error> {
495    fn contains_chars_requiring_wrapper_quotes(segment: &str) -> bool {
496        segment.contains('/') || segment.contains('*')
497    }
498
499    selector.validate()?;
500
501    let component_selector = selector
502        .component_selector
503        .as_ref()
504        .ok_or_else(|| format_err!("component selector missing"))?;
505    let (node_path, maybe_property_selector) = match selector
506        .tree_selector
507        .as_ref()
508        .ok_or_else(|| format_err!("tree selector missing"))?
509    {
510        TreeSelector::SubtreeSelector(SubtreeSelector { node_path, .. }) => (node_path, None),
511        TreeSelector::PropertySelector(PropertySelector {
512            node_path, target_properties, ..
513        }) => (node_path, Some(target_properties)),
514        _ => return Err(format_err!("unknown tree selector type")),
515    };
516
517    let mut needs_to_be_quoted = false;
518    let result = component_selector
519        .moniker_segments
520        .as_ref()
521        .ok_or_else(|| format_err!("moniker segments missing in component selector"))?
522        .iter()
523        .map(|segment| match segment {
524            StringSelector::StringPattern(p) => {
525                needs_to_be_quoted = true;
526                Ok(p)
527            }
528            StringSelector::ExactMatch(s) => {
529                needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
530                Ok(s)
531            }
532            fdiagnostics::StringSelectorUnknown!() => {
533                Err(format_err!("uknown StringSelector variant"))
534            }
535        })
536        .collect::<Result<Vec<_>, _>>()?
537        .into_iter()
538        .join("/");
539
540    let mut result = sanitize_moniker_for_selectors(&result);
541
542    let mut tree_selector_str = node_path
543        .iter()
544        .map(|segment| {
545            Ok(match segment {
546                StringSelector::StringPattern(p) => {
547                    needs_to_be_quoted = true;
548                    p.to_string()
549                }
550                StringSelector::ExactMatch(s) => {
551                    needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
552                    sanitize_string_for_selectors(s).to_string()
553                }
554                fdiagnostics::StringSelectorUnknown!() => {
555                    return Err(format_err!("uknown StringSelector variant"));
556                }
557            })
558        })
559        .collect::<Result<Vec<String>, _>>()?
560        .into_iter()
561        .join("/");
562
563    if let Some(target_property) = maybe_property_selector {
564        tree_selector_str.push(':');
565        tree_selector_str.push_str(&match target_property {
566            StringSelector::StringPattern(p) => {
567                needs_to_be_quoted = true;
568                p.to_string()
569            }
570            StringSelector::ExactMatch(s) => {
571                needs_to_be_quoted |= contains_chars_requiring_wrapper_quotes(s);
572                sanitize_string_for_selectors(s).to_string()
573            }
574            fdiagnostics::StringSelectorUnknown!() => {
575                return Err(format_err!("uknown StringSelector variant"));
576            }
577        });
578    }
579
580    tree_selector_str = match &selector.tree_names {
581        None => tree_selector_str,
582        Some(names) => match names {
583            TreeNames::Some(names) => {
584                let list = names
585                    .iter()
586                    .filter_map(|name| {
587                        if name == DEFAULT_TREE_NAME {
588                            return None;
589                        }
590
591                        for c in name.chars() {
592                            if !(c.is_alphanumeric() || c == '-' || c == '_') {
593                                return Some(format!(r#"name="{name}""#));
594                            }
595                        }
596
597                        Some(format!("name={name}"))
598                    })
599                    .join(",");
600
601                if list.is_empty() {
602                    tree_selector_str
603                } else {
604                    needs_to_be_quoted = true;
605                    format!("[{list}]{tree_selector_str}")
606                }
607            }
608            TreeNames::All(_) => {
609                needs_to_be_quoted = true;
610                format!("[...]{tree_selector_str}")
611            }
612            fdiagnostics::TreeNamesUnknown!() => {
613                return Err(format_err!("unknown TreeNames variant"));
614            }
615        },
616    };
617
618    result.push_str(&format!(":{tree_selector_str}"));
619
620    if needs_to_be_quoted && opts.allow_wrapper_quotes {
621        Ok(format!(r#""{result}""#))
622    } else {
623        Ok(result)
624    }
625}
626
627/// Match a selector against a target string.
628pub fn match_string(selector: &StringSelector, target: impl AsRef<str>) -> bool {
629    match selector {
630        StringSelector::ExactMatch(s) => s == target.as_ref(),
631        StringSelector::StringPattern(pattern) => match_pattern(pattern, target.as_ref()),
632        _ => false,
633    }
634}
635
636fn match_pattern(pattern: &str, target: &str) -> bool {
637    // Tokenize the string. From: "a*bc*d" to "a, bc, d".
638    let mut pattern_tokens = vec![];
639    let mut token = TokenBuilder::new(pattern);
640    let mut chars = pattern.char_indices();
641
642    while let Some((index, curr_char)) = chars.next() {
643        token.maybe_init(index);
644
645        // If we find a backslash then push the next character directly to our new string.
646        match curr_char {
647            '\\' => {
648                match chars.next() {
649                    Some((i, c)) => {
650                        token.turn_into_string();
651                        token.push(c, i);
652                    }
653                    // We found a backslash without a character to its right. Return false as this
654                    // isn't valid.
655                    None => return false,
656                }
657            }
658            '*' => {
659                if !token.is_empty() {
660                    pattern_tokens.push(token.take());
661                }
662                token = TokenBuilder::new(pattern);
663            }
664            c => {
665                token.push(c, index);
666            }
667        }
668    }
669
670    // Push the remaining token if there's any.
671    if !token.is_empty() {
672        pattern_tokens.push(token.take());
673    }
674
675    // Exit early. We only have *'s.
676    if pattern_tokens.is_empty() && !pattern.is_empty() {
677        return true;
678    }
679
680    // If the pattern doesn't begin with a * and the target string doesn't start with the first
681    // pattern token, we can exit.
682    if !pattern.starts_with('*') && !target.starts_with(pattern_tokens[0].as_ref()) {
683        return false;
684    }
685
686    // If the last character of the pattern is not an unescaped * and the target string doesn't end
687    // with the last token in the pattern, then we can exit.
688    if !pattern.ends_with('*')
689        && pattern.chars().rev().nth(1) != Some('\\')
690        && !target.ends_with(pattern_tokens[pattern_tokens.len() - 1].as_ref())
691    {
692        return false;
693    }
694
695    // We must find all pattern tokens in the target string in order. If we don't find one then we
696    // fail.
697    let mut cur_string = target;
698    for pattern in pattern_tokens.iter() {
699        match cur_string.find(pattern.as_ref()) {
700            Some(i) => {
701                cur_string = &cur_string[i + pattern.len()..];
702            }
703            None => {
704                return false;
705            }
706        }
707    }
708
709    true
710}
711
712// Utility to allow matching the string cloning only when necessary, this is when we run into a
713// escaped character.
714#[derive(Debug)]
715enum TokenBuilder<'a> {
716    Init(&'a str),
717    Slice { string: &'a str, start: usize, end: usize },
718    String(String),
719}
720
721impl<'a> TokenBuilder<'a> {
722    fn new(string: &'a str) -> Self {
723        Self::Init(string)
724    }
725
726    fn maybe_init(&mut self, start_index: usize) {
727        let Self::Init(s) = self else {
728            return;
729        };
730        *self = Self::Slice { string: s, start: start_index, end: start_index };
731    }
732
733    fn turn_into_string(&mut self) {
734        if let Self::Slice { string, start, end } = self {
735            *self = Self::String(string[*start..*end].to_string());
736        }
737    }
738
739    fn push(&mut self, c: char, index: usize) {
740        match self {
741            Self::Slice { end, .. } => {
742                *end = index + c.len_utf8();
743            }
744            Self::String(s) => s.push(c),
745            Self::Init(_) => unreachable!(),
746        }
747    }
748
749    fn take(self) -> Cow<'a, str> {
750        match self {
751            Self::Slice { string, start, end } => Cow::Borrowed(&string[start..end]),
752            Self::String(s) => Cow::Owned(s),
753            Self::Init(_) => unreachable!(),
754        }
755    }
756
757    fn is_empty(&self) -> bool {
758        match self {
759            Self::Slice { start, end, .. } => start >= end,
760            Self::String(s) => s.is_empty(),
761            Self::Init(_) => true,
762        }
763    }
764}
765
766pub trait SelectorExt {
767    fn match_against_selectors<'a>(
768        &self,
769        selectors: impl IntoIterator<Item = &'a Selector>,
770    ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>>;
771
772    /// Invalid selectors are filtered out.
773    fn match_against_selectors_and_tree_name<'a>(
774        &self,
775        tree_name: &str,
776        selectors: impl IntoIterator<Item = &'a Selector>,
777    ) -> impl Iterator<Item = &'a Selector>;
778
779    fn match_against_component_selectors<'a, S>(
780        &self,
781        selectors: &'a [S],
782    ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
783    where
784        S: Borrow<ComponentSelector>;
785
786    fn into_component_selector(self) -> ComponentSelector;
787
788    fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error>;
789
790    fn matches_component_selector(
791        &self,
792        selector: &ComponentSelector,
793    ) -> Result<bool, anyhow::Error>;
794
795    fn sanitized(&self) -> String;
796}
797
798impl SelectorExt for ExtendedMoniker {
799    fn match_against_selectors<'a>(
800        &self,
801        selectors: impl IntoIterator<Item = &'a Selector>,
802    ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
803        let s = match self {
804            ExtendedMoniker::ComponentManager => {
805                vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string()]
806            }
807            ExtendedMoniker::ComponentInstance(moniker) => {
808                SegmentIterator::from(moniker).collect::<Vec<_>>()
809            }
810        };
811
812        match_component_moniker_against_selectors(s, selectors)
813    }
814
815    fn match_against_selectors_and_tree_name<'a>(
816        &self,
817        tree_name: &str,
818        selectors: impl IntoIterator<Item = &'a Selector>,
819    ) -> impl Iterator<Item = &'a Selector> {
820        let m = match self {
821            ExtendedMoniker::ComponentManager => {
822                vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string()]
823            }
824            ExtendedMoniker::ComponentInstance(moniker) => {
825                SegmentIterator::from(moniker).collect::<Vec<_>>()
826            }
827        };
828
829        selectors
830            .into_iter()
831            .filter(move |s| match_component_and_tree_name(&m, tree_name, s).unwrap_or(false))
832    }
833
834    fn match_against_component_selectors<'a, S>(
835        &self,
836        selectors: &'a [S],
837    ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
838    where
839        S: Borrow<ComponentSelector>,
840    {
841        match self {
842            ExtendedMoniker::ComponentManager => match_moniker_against_component_selectors(
843                &[EXTENDED_MONIKER_COMPONENT_MANAGER_STR],
844                selectors,
845            ),
846            ExtendedMoniker::ComponentInstance(moniker) => {
847                moniker.match_against_component_selectors(selectors)
848            }
849        }
850    }
851
852    fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error> {
853        match self {
854            ExtendedMoniker::ComponentManager => match_component_moniker_against_selector(
855                [EXTENDED_MONIKER_COMPONENT_MANAGER_STR],
856                selector,
857            ),
858            ExtendedMoniker::ComponentInstance(moniker) => moniker.matches_selector(selector),
859        }
860    }
861
862    fn matches_component_selector(
863        &self,
864        selector: &ComponentSelector,
865    ) -> Result<bool, anyhow::Error> {
866        match self {
867            ExtendedMoniker::ComponentManager => match_moniker_against_component_selector(
868                [EXTENDED_MONIKER_COMPONENT_MANAGER_STR].into_iter(),
869                selector,
870            ),
871            ExtendedMoniker::ComponentInstance(moniker) => {
872                moniker.matches_component_selector(selector)
873            }
874        }
875    }
876
877    fn sanitized(&self) -> String {
878        match self {
879            ExtendedMoniker::ComponentManager => EXTENDED_MONIKER_COMPONENT_MANAGER_STR.to_string(),
880            ExtendedMoniker::ComponentInstance(moniker) => moniker.sanitized(),
881        }
882    }
883
884    fn into_component_selector(self) -> ComponentSelector {
885        ComponentSelector {
886            moniker_segments: Some(
887                match self {
888                    ExtendedMoniker::ComponentManager => {
889                        vec![EXTENDED_MONIKER_COMPONENT_MANAGER_STR.into()]
890                    }
891                    ExtendedMoniker::ComponentInstance(moniker) => {
892                        moniker.path().iter().map(|value| value.to_string()).collect()
893                    }
894                }
895                .into_iter()
896                .map(StringSelector::ExactMatch)
897                .collect(),
898            ),
899            ..Default::default()
900        }
901    }
902}
903
904impl SelectorExt for Moniker {
905    fn match_against_selectors<'a>(
906        &self,
907        selectors: impl IntoIterator<Item = &'a Selector>,
908    ) -> impl Iterator<Item = Result<&'a Selector, anyhow::Error>> {
909        let s = SegmentIterator::from(self).collect::<Vec<_>>();
910        match_component_moniker_against_selectors(s, selectors)
911    }
912
913    fn match_against_selectors_and_tree_name<'a>(
914        &self,
915        tree_name: &str,
916        selectors: impl IntoIterator<Item = &'a Selector>,
917    ) -> impl Iterator<Item = &'a Selector> {
918        let m = SegmentIterator::from(self).collect::<Vec<_>>();
919
920        selectors
921            .into_iter()
922            .filter(move |s| match_component_and_tree_name(&m, tree_name, s).unwrap_or(false))
923    }
924
925    fn match_against_component_selectors<'a, S>(
926        &self,
927        selectors: &'a [S],
928    ) -> Result<Vec<&'a ComponentSelector>, anyhow::Error>
929    where
930        S: Borrow<ComponentSelector>,
931    {
932        let s = SegmentIterator::from(self).collect::<Vec<_>>();
933        match_moniker_against_component_selectors(&s, selectors)
934    }
935
936    fn matches_selector(&self, selector: &Selector) -> Result<bool, anyhow::Error> {
937        let s = SegmentIterator::from(self).collect::<Vec<_>>();
938        match_component_moniker_against_selector(&s, selector)
939    }
940
941    fn matches_component_selector(
942        &self,
943        selector: &ComponentSelector,
944    ) -> Result<bool, anyhow::Error> {
945        match_moniker_against_component_selector(SegmentIterator::from(self), selector)
946    }
947
948    fn sanitized(&self) -> String {
949        SegmentIterator::from(self)
950            .map(|s| sanitize_string_for_selectors(&s).into_owned())
951            .collect::<Vec<String>>()
952            .join("/")
953    }
954
955    fn into_component_selector(self) -> ComponentSelector {
956        ComponentSelector {
957            moniker_segments: Some(
958                self.path()
959                    .iter()
960                    .map(|value| StringSelector::ExactMatch(value.to_string()))
961                    .collect(),
962            ),
963            ..Default::default()
964        }
965    }
966}
967
968enum SegmentIterator<'a> {
969    Iter { path: Arc<[&'a BorrowedChildName]>, current_index: usize },
970    Root(bool),
971}
972
973impl<'a> From<&'a Moniker> for SegmentIterator<'a> {
974    fn from(moniker: &'a Moniker) -> Self {
975        if moniker.is_root() {
976            return SegmentIterator::Root(false);
977        }
978        SegmentIterator::Iter { path: moniker.path().into(), current_index: 0 }
979    }
980}
981
982impl Iterator for SegmentIterator<'_> {
983    type Item = String;
984    fn next(&mut self) -> Option<Self::Item> {
985        match self {
986            Self::Iter { path, current_index } => {
987                let segment = path.get(*current_index)?;
988                let result = segment.to_string();
989                *self = Self::Iter { path: path.clone(), current_index: *current_index + 1 };
990                Some(result)
991            }
992            Self::Root(true) => None,
993            Self::Root(done) => {
994                *done = true;
995                Some(ROOT_SEGMENT.to_string())
996            }
997        }
998    }
999}
1000
1001#[cfg(test)]
1002mod tests {
1003    use super::*;
1004    use std::fs::File;
1005    use std::io::prelude::*;
1006    use std::path::PathBuf;
1007    use std::str::FromStr;
1008    use tempfile::TempDir;
1009    use test_case::test_case;
1010
1011    /// Loads all the selectors in the given directory.
1012    pub fn parse_selectors<E>(directory: &Path) -> Result<Vec<Selector>, Error>
1013    where
1014        E: for<'a> ParsingError<'a>,
1015    {
1016        let path: PathBuf = directory.to_path_buf();
1017        let mut selector_vec: Vec<Selector> = Vec::new();
1018        for entry in fs::read_dir(path)? {
1019            let entry = entry?;
1020            if entry.path().is_dir() {
1021                return Err(Error::NonFlatDirectory);
1022            } else {
1023                selector_vec.append(&mut parse_selector_file::<E>(&entry.path())?);
1024            }
1025        }
1026        Ok(selector_vec)
1027    }
1028
1029    #[fuchsia::test]
1030    fn successful_selector_parsing() {
1031        let tempdir = TempDir::new().expect("failed to create tmp dir");
1032        File::create(tempdir.path().join("a.txt"))
1033            .expect("create file")
1034            .write_all(
1035                b"a:b:c
1036
1037",
1038            )
1039            .expect("writing test file");
1040        File::create(tempdir.path().join("b.txt"))
1041            .expect("create file")
1042            .write_all(b"a*/b:c/d/*:*")
1043            .expect("writing test file");
1044
1045        File::create(tempdir.path().join("c.txt"))
1046            .expect("create file")
1047            .write_all(
1048                b"// this is a comment
1049a:b:c
1050",
1051            )
1052            .expect("writing test file");
1053        File::create(tempdir.path().join("d.txt"))
1054            .expect("create file")
1055            .write_all(
1056                b"foo:bar
1057// This is a multi line comment.
1058//
1059// The blank comment line above is allowed.
1060foo:baz
1061",
1062            )
1063            .expect("writing test file");
1064
1065        assert_matches::assert_matches!(parse_selectors::<VerboseError>(tempdir.path()), Ok(_));
1066    }
1067
1068    #[fuchsia::test]
1069    fn unsuccessful_selector_parsing_bad_selector() {
1070        let tempdir = TempDir::new().expect("failed to create tmp dir");
1071        File::create(tempdir.path().join("a.txt"))
1072            .expect("create file")
1073            .write_all(b"a:b:c")
1074            .expect("writing test file");
1075        File::create(tempdir.path().join("b.txt"))
1076            .expect("create file")
1077            .write_all(b"**:**:**")
1078            .expect("writing test file");
1079
1080        assert!(parse_selectors::<VerboseError>(tempdir.path()).is_err());
1081    }
1082
1083    #[fuchsia::test]
1084    fn unsuccessful_selector_parsing_nonflat_dir() {
1085        let tempdir = TempDir::new().expect("failed to create tmp dir");
1086        File::create(tempdir.path().join("a.txt"))
1087            .expect("create file")
1088            .write_all(b"a:b:c")
1089            .expect("writing test file");
1090        File::create(tempdir.path().join("b.txt"))
1091            .expect("create file")
1092            .write_all(b"**:**:**")
1093            .expect("writing test file");
1094
1095        std::fs::create_dir_all(tempdir.path().join("nested")).expect("make nested");
1096        File::create(tempdir.path().join("nested/c.txt"))
1097            .expect("create file")
1098            .write_all(b"**:**:**")
1099            .expect("writing test file");
1100        assert!(parse_selectors::<VerboseError>(tempdir.path()).is_err());
1101    }
1102
1103    #[fuchsia::test]
1104    fn component_selector_match_test() {
1105        // Note: We provide the full selector syntax but this test is only validating it
1106        // against the provided moniker
1107        let passing_test_cases = vec![
1108            (r#"echo:*:*"#, vec!["echo"]),
1109            (r#"*/echo:*:*"#, vec!["abc", "echo"]),
1110            (r#"ab*/echo:*:*"#, vec!["abc", "echo"]),
1111            (r#"ab*/echo:*:*"#, vec!["abcde", "echo"]),
1112            (r#"*/ab*/echo:*:*"#, vec!["123", "abcde", "echo"]),
1113            (r#"echo*:*:*"#, vec!["echo"]),
1114            (r#"a/echo*:*:*"#, vec!["a", "echo1"]),
1115            (r#"a/echo*:*:*"#, vec!["a", "echo"]),
1116            (r#"ab*/echo:*:*"#, vec!["ab", "echo"]),
1117            (r#"a/**:*:*"#, vec!["a", "echo"]),
1118            (r#"a/**:*:*"#, vec!["a", "b", "echo"]),
1119        ];
1120
1121        for (selector, moniker) in passing_test_cases {
1122            let parsed_selector = parse_selector::<VerboseError>(selector).unwrap();
1123            assert!(
1124                match_component_moniker_against_selector(&moniker, &parsed_selector).unwrap(),
1125                "Selector {selector:?} failed to match {moniker:?}"
1126            );
1127        }
1128
1129        // Note: We provide the full selector syntax but this test is only validating it
1130        // against the provided moniker
1131        let failing_test_cases = vec![
1132            (r#"*:*:*"#, vec!["a", "echo"]),
1133            (r#"*/echo:*:*"#, vec!["123", "abc", "echo"]),
1134            (r#"a/**:*:*"#, vec!["b", "echo"]),
1135            (r#"e/**:*:*"#, vec!["echo"]),
1136        ];
1137
1138        for (selector, moniker) in failing_test_cases {
1139            let parsed_selector = parse_selector::<VerboseError>(selector).unwrap();
1140            assert!(
1141                !match_component_moniker_against_selector(&moniker, &parsed_selector).unwrap(),
1142                "Selector {selector:?} matched {moniker:?}, but was expected to fail"
1143            );
1144        }
1145    }
1146
1147    #[fuchsia::test]
1148    fn multiple_component_selectors_match_test() {
1149        let selectors = vec![r#"*/echo"#, r#"ab*/echo"#, r#"abc/m*"#];
1150        let moniker = vec!["abc".to_string(), "echo".to_string()];
1151
1152        let component_selectors = selectors
1153            .into_iter()
1154            .map(|selector| parse_component_selector::<VerboseError>(selector).unwrap())
1155            .collect::<Vec<_>>();
1156
1157        let match_res =
1158            match_moniker_against_component_selectors(moniker.as_slice(), &component_selectors[..]);
1159        assert!(match_res.is_ok());
1160        assert_eq!(match_res.unwrap().len(), 2);
1161    }
1162
1163    #[test_case("a/b:c:d", "a/b:c:d" ; "no_wrap_with_basic_full_selector")]
1164    #[test_case("a/b:c", "a/b:c" ; "no_wrap_with_basic_partial_selector")]
1165    #[test_case(r"a/b:c/d\/e:f", r#"a/b:c/d\/e:f"# ; "no_wrap_with_escaped_forward_slash")]
1166    #[test_case(r"a/b:[name=root]c:d", "a/b:c:d" ; "no_wrap_with_default_name")]
1167    #[test_case(r"a/b:[name=cd-e]f:g", r#"a/b:[name=cd-e]f:g"# ; "no_wrap_with_non_default_name")]
1168    #[test_case(
1169        r#"a:[name="bc-d"]e:f"#,
1170        r"a:[name=bc-d]e:f"
1171        ; "no_wrap_with_unneeded_name_quotes"
1172    )]
1173    #[test_case(
1174        r#"a:[name="b[]c"]d:e"#,
1175        r#"a:[name="b[]c"]d:e"#
1176        ; "no_wrap_with_needed_name_quotes"
1177    )]
1178    #[test_case("a/b:[...]c:d", r#"a/b:[...]c:d"# ; "no_wrap_with_all_names")]
1179    #[test_case(
1180        r#"a/b:[name=c, name="d", name="f[]g"]h:i"#,
1181        r#"a/b:[name=c,name=d,name="f[]g"]h:i"#
1182        ; "no_wrap_with_name_list"
1183    )]
1184    #[test_case(r"a\:b/c:d:e", r"a\:b/c:d:e" ; "no_wrap_with_collection")]
1185    #[test_case(r"a/b/c*d:e:f", r#"a/b/c*d:e:f"# ; "no_wrap_with_wildcard_component")]
1186    #[test_case(r"a/b:c*/d:e", r#"a/b:c*/d:e"# ; "no_wrap_with_wildcard_tree")]
1187    #[test_case(r"a/b:c\*/d:e", r#"a/b:c\*/d:e"# ; "no_wrap_with_escaped_wildcard_tree")]
1188    #[test_case(r"a/b/c/d:e/f:g*", r#"a/b/c/d:e/f:g*"# ; "no_wrap_with_wildcard_property")]
1189    #[test_case(r"a/b/c/d:e/f:g*", r#"a/b/c/d:e/f:g*"# ; "no_wrap_with_escaped_wildcard_property")]
1190    #[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")]
1191    #[fuchsia::test]
1192    fn selector_to_string_test_never_wrap(input: &str, expected: &str) {
1193        let selector = parse_verbose(input).unwrap();
1194        assert_eq!(
1195            selector_to_string(&selector, SelectorDisplayOptions::never_wrap_in_quotes()).unwrap(),
1196            expected,
1197            "left: actual, right: expected"
1198        );
1199    }
1200
1201    #[test_case("a/b:c:d", "a/b:c:d" ; "with_basic_full_selector")]
1202    #[test_case("a/b:c", "a/b:c" ; "with_basic_partial_selector")]
1203    #[test_case(r"a/b:c/d\/e:f", r#""a/b:c/d\/e:f""# ; "with_escaped_forward_slash")]
1204    #[test_case(r"a/b:[name=root]c:d", "a/b:c:d" ; "with_default_name")]
1205    #[test_case(r"a/b:[name=cd-e]f:g", r#""a/b:[name=cd-e]f:g""# ; "with_non_default_name")]
1206    #[test_case(r#"a:[name="bc-d"]e:f"#, r#""a:[name=bc-d]e:f""# ; "with_unneeded_name_quotes")]
1207    #[test_case(r#"a:[name="b[]c"]d:e"#, r#""a:[name="b[]c"]d:e""# ; "with_needed_name_quotes")]
1208    #[test_case("a/b:[...]c:d", r#""a/b:[...]c:d""# ; "with_all_names")]
1209    #[test_case(
1210        r#"a/b:[name=c, name="d", name="f[]g"]h:i"#,
1211        r#""a/b:[name=c,name=d,name="f[]g"]h:i""#
1212        ; "with_name_list"
1213    )]
1214    #[test_case(r"a\:b/c:d:e", r"a\:b/c:d:e" ; "with_collection")]
1215    #[test_case(r"a/b/c*d:e:f", r#""a/b/c*d:e:f""# ; "with_wildcard_component")]
1216    #[test_case(r"a/b:c*/d:e", r#""a/b:c*/d:e""# ; "with_wildcard_tree")]
1217    #[test_case(r"a/b:c\*/d:e", r#""a/b:c\*/d:e""# ; "with_escaped_wildcard_tree")]
1218    #[test_case(r"a/b/c/d:e/f:g*", r#""a/b/c/d:e/f:g*""# ; "with_wildcard_property")]
1219    #[test_case(r"a/b/c/d:e/f:g*", r#""a/b/c/d:e/f:g*""# ; "with_escaped_wildcard_property")]
1220    #[test_case("a/b/c/d:e/f/g/h:k", "a/b/c/d:e/f/g/h:k" ; "with_deep_nesting")]
1221    #[fuchsia::test]
1222    fn selector_to_string_test_default(input: &str, expected: &str) {
1223        let selector = parse_verbose(input).unwrap();
1224        assert_eq!(
1225            selector_to_string(&selector, SelectorDisplayOptions::default()).unwrap(),
1226            expected,
1227            "left: actual, right: expected"
1228        );
1229    }
1230
1231    #[test_case("a*", r"a\*" ; "when_star_not_leading")]
1232    #[test_case("a:", r"a\:" ; "when_colon_not_leading")]
1233    #[test_case(":", r"\:" ; "when_colon_leading")]
1234    #[test_case("*", r"\*" ; "when_star_leading")]
1235    #[test_case(r"*:\abc", r"\*\:\\abc" ; "when_mixed_with_leading_special_chars")]
1236    #[fuchsia::test]
1237    fn sanitize_string_for_selectors_works(input: &str, expected: &str) {
1238        assert_eq!(sanitize_string_for_selectors(input), expected);
1239    }
1240
1241    #[fuchsia::test]
1242    fn sanitize_moniker_for_selectors_result_is_usable() {
1243        let selector = parse_selector::<VerboseError>(&format!(
1244            "{}:root",
1245            sanitize_moniker_for_selectors("foo/coll:bar/baz")
1246        ))
1247        .unwrap();
1248        let component_selector = selector.component_selector.as_ref().unwrap();
1249        let moniker = ["foo", "coll:bar", "baz"];
1250        assert!(
1251            match_moniker_against_component_selector(moniker.iter(), component_selector).unwrap()
1252        );
1253    }
1254
1255    #[fuchsia::test]
1256    fn escaped_spaces() {
1257        let selector_str = "foo:bar\\ baz/a*\\ b:quux";
1258        let selector = parse_selector::<VerboseError>(selector_str).unwrap();
1259        assert_eq!(
1260            selector,
1261            Selector {
1262                component_selector: Some(ComponentSelector {
1263                    moniker_segments: Some(vec![StringSelector::ExactMatch("foo".into()),]),
1264                    ..Default::default()
1265                }),
1266                tree_selector: Some(TreeSelector::PropertySelector(PropertySelector {
1267                    node_path: vec![
1268                        StringSelector::ExactMatch("bar baz".into()),
1269                        StringSelector::StringPattern("a* b".into()),
1270                    ],
1271                    target_properties: StringSelector::ExactMatch("quux".into())
1272                })),
1273                ..Default::default()
1274            }
1275        );
1276    }
1277
1278    #[fuchsia::test]
1279    fn match_string_test() {
1280        // Exact match.
1281        assert!(match_string(&StringSelector::ExactMatch("foo".into()), "foo"));
1282
1283        // Valid pattern matches.
1284        assert!(match_string(&StringSelector::StringPattern("*foo*".into()), "hellofoobye"));
1285        assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoo"));
1286        assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barfoo"));
1287        assert!(match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoo"));
1288        assert!(match_string(&StringSelector::StringPattern("foo*".into()), "foobar"));
1289        assert!(match_string(&StringSelector::StringPattern("*".into()), "foo"));
1290        assert!(match_string(&StringSelector::StringPattern("bar*baz*foo".into()), "barxzybazfoo"));
1291        assert!(match_string(&StringSelector::StringPattern("foo*bar*baz".into()), "foobazbarbaz"));
1292
1293        // Escaped char.
1294        assert!(match_string(&StringSelector::StringPattern("foo\\*".into()), "foo*"));
1295
1296        // Invalid cases.
1297        assert!(!match_string(&StringSelector::StringPattern("foo\\".into()), "foo\\"));
1298        assert!(!match_string(&StringSelector::StringPattern("bar*foo".into()), "barxfoox"));
1299        assert!(!match_string(&StringSelector::StringPattern("m*".into()), "echo.csx"));
1300        assert!(!match_string(&StringSelector::StringPattern("*foo*".into()), "xbary"));
1301        assert!(!match_string(
1302            &StringSelector::StringPattern("foo*bar*baz*qux".into()),
1303            "foobarbaazqux"
1304        ));
1305    }
1306
1307    #[fuchsia::test]
1308    fn test_log_interest_selector() {
1309        assert_eq!(
1310            parse_log_interest_selector("core/network#FATAL").unwrap(),
1311            LogInterestSelector {
1312                selector: parse_component_selector::<VerboseError>("core/network").unwrap(),
1313                interest: Interest { min_severity: Some(Severity::Fatal), ..Default::default() }
1314            }
1315        );
1316        assert_eq!(
1317            parse_log_interest_selector("any/component#INFO").unwrap(),
1318            LogInterestSelector {
1319                selector: parse_component_selector::<VerboseError>("any/component").unwrap(),
1320                interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1321            }
1322        );
1323        assert_eq!(
1324            parse_log_interest_selector("any/coll:instance/foo#INFO").unwrap(),
1325            LogInterestSelector {
1326                selector: parse_component_selector::<VerboseError>("any/coll\\:instance/foo")
1327                    .unwrap(),
1328                interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1329            }
1330        );
1331        assert_eq!(
1332            parse_log_interest_selector("any/coll:*/foo#INFO").unwrap(),
1333            LogInterestSelector {
1334                selector: parse_component_selector::<VerboseError>("any/coll\\:*/foo").unwrap(),
1335                interest: Interest { min_severity: Some(Severity::Info), ..Default::default() }
1336            }
1337        );
1338    }
1339    #[test]
1340    fn test_log_interest_selector_error() {
1341        assert!(parse_log_interest_selector("anything////#FATAL").is_err());
1342        assert!(parse_log_interest_selector("core/network").is_err());
1343        assert!(parse_log_interest_selector("core/network#FAKE").is_err());
1344        assert!(parse_log_interest_selector("core/network\\:foo#FAKE").is_err());
1345    }
1346
1347    #[test]
1348    fn test_moniker_to_selector() {
1349        assert_eq!(
1350            Moniker::from_str("a/b/c").unwrap().into_component_selector(),
1351            parse_component_selector::<VerboseError>("a/b/c").unwrap()
1352        );
1353        assert_eq!(
1354            ExtendedMoniker::ComponentManager.into_component_selector(),
1355            parse_component_selector::<VerboseError>("<component_manager>").unwrap()
1356        );
1357        assert_eq!(
1358            ExtendedMoniker::ComponentInstance(Moniker::from_str("a/b/c").unwrap())
1359                .into_component_selector(),
1360            parse_component_selector::<VerboseError>("a/b/c").unwrap()
1361        );
1362        assert_eq!(
1363            ExtendedMoniker::ComponentInstance(Moniker::from_str("a/coll:id/c").unwrap())
1364                .into_component_selector(),
1365            parse_component_selector::<VerboseError>("a/coll\\:id/c").unwrap()
1366        );
1367    }
1368
1369    #[test]
1370    fn test_parse_log_interest_or_severity() {
1371        for (severity_str, severity) in [
1372            ("TRACE", Severity::Trace),
1373            ("DEBUG", Severity::Debug),
1374            ("INFO", Severity::Info),
1375            ("WARN", Severity::Warn),
1376            ("ERROR", Severity::Error),
1377            ("FATAL", Severity::Fatal),
1378        ] {
1379            assert_eq!(
1380                parse_log_interest_selector_or_severity(severity_str).unwrap(),
1381                LogInterestSelector {
1382                    selector: parse_component_selector::<VerboseError>("**").unwrap(),
1383                    interest: Interest { min_severity: Some(severity), ..Default::default() }
1384                }
1385            );
1386        }
1387
1388        assert_eq!(
1389            parse_log_interest_selector_or_severity("foo/bar#DEBUG").unwrap(),
1390            LogInterestSelector {
1391                selector: parse_component_selector::<VerboseError>("foo/bar").unwrap(),
1392                interest: Interest { min_severity: Some(Severity::Debug), ..Default::default() }
1393            }
1394        );
1395
1396        assert!(parse_log_interest_selector_or_severity("RANDOM").is_err());
1397        assert!(parse_log_interest_selector_or_severity("core/foo#NO#YES").is_err());
1398    }
1399
1400    #[test]
1401    fn test_parse_tree_selector() {
1402        let selector = parse_tree_selector::<VerboseError>("root/node*/nested:prop").unwrap();
1403        assert_eq!(
1404            selector,
1405            TreeSelector::PropertySelector(PropertySelector {
1406                node_path: vec![
1407                    StringSelector::ExactMatch("root".into()),
1408                    StringSelector::StringPattern("node*".into()),
1409                    StringSelector::ExactMatch("nested".into()),
1410                ],
1411                target_properties: StringSelector::ExactMatch("prop".into())
1412            }),
1413        );
1414    }
1415
1416    #[test]
1417    fn test_monikers_against_selectors_and_tree_name() {
1418        let selectors = &[
1419            parse_selector::<VerboseError>("core/foo:root:prop").unwrap(),
1420            parse_selector::<VerboseError>("core/*:[name=root]root:prop").unwrap(),
1421            parse_selector::<VerboseError>("core/baz:[name=baz]root:prop").unwrap(),
1422            parse_selector::<VerboseError>("core/baz:[name=root]root:prop").unwrap(),
1423            parse_selector::<VerboseError>("core/*:[...]root:prop").unwrap(),
1424            parse_selector::<VerboseError>("<component_manager>:root:prop").unwrap(),
1425        ];
1426
1427        {
1428            let foo = ExtendedMoniker::try_from("core/foo").unwrap();
1429
1430            let actual = foo
1431                .match_against_selectors_and_tree_name("root", selectors.iter())
1432                .collect::<Vec<_>>();
1433            assert_eq!(actual, vec![&selectors[0], &selectors[1], &selectors[4]]);
1434
1435            let foo = Moniker::try_from("core/foo").unwrap();
1436
1437            let actual = foo
1438                .match_against_selectors_and_tree_name("root", selectors.iter())
1439                .collect::<Vec<_>>();
1440            assert_eq!(actual, vec![&selectors[0], &selectors[1], &selectors[4]]);
1441        }
1442
1443        {
1444            let baz = ExtendedMoniker::try_from("core/baz").unwrap();
1445
1446            let actual = baz
1447                .match_against_selectors_and_tree_name("root", selectors.iter())
1448                .collect::<Vec<_>>();
1449            assert_eq!(actual, vec![&selectors[1], &selectors[3], &selectors[4]]);
1450
1451            let baz = Moniker::try_from("core/baz").unwrap();
1452
1453            let actual = baz
1454                .match_against_selectors_and_tree_name("root", selectors.iter())
1455                .collect::<Vec<_>>();
1456            assert_eq!(actual, vec![&selectors[1], &selectors[3], &selectors[4]]);
1457        }
1458
1459        {
1460            let baz = ExtendedMoniker::try_from("core/baz").unwrap();
1461
1462            let actual = baz
1463                .match_against_selectors_and_tree_name("baz", selectors.iter())
1464                .collect::<Vec<_>>();
1465            assert_eq!(actual, vec![&selectors[2], &selectors[4]]);
1466
1467            let baz = Moniker::try_from("core/baz").unwrap();
1468
1469            let actual = baz
1470                .match_against_selectors_and_tree_name("baz", selectors.iter())
1471                .collect::<Vec<_>>();
1472            assert_eq!(actual, vec![&selectors[2], &selectors[4]]);
1473        }
1474
1475        {
1476            let qux = ExtendedMoniker::try_from("core/qux").unwrap();
1477
1478            let actual = qux
1479                .match_against_selectors_and_tree_name("qux", selectors.iter())
1480                .collect::<Vec<_>>();
1481            assert_eq!(actual, vec![&selectors[4]]);
1482
1483            let qux = Moniker::try_from("core/qux").unwrap();
1484
1485            let actual = qux
1486                .match_against_selectors_and_tree_name("qux", selectors.iter())
1487                .collect::<Vec<_>>();
1488            assert_eq!(actual, vec![&selectors[4]]);
1489        }
1490
1491        {
1492            let cm = ExtendedMoniker::try_from(EXTENDED_MONIKER_COMPONENT_MANAGER_STR).unwrap();
1493
1494            let actual = cm
1495                .match_against_selectors_and_tree_name("root", selectors.iter())
1496                .collect::<Vec<_>>();
1497            assert_eq!(actual, vec![&selectors[5]]);
1498        }
1499
1500        {
1501            let sanitized = sanitize_string_for_selectors("πŸ¦€:test");
1502            assert_eq!(sanitized, "πŸ¦€\\:test");
1503
1504            let sanitized_no_special = sanitize_string_for_selectors("πŸ¦€πŸ¦€πŸ¦€");
1505            assert_eq!(sanitized_no_special, "πŸ¦€πŸ¦€πŸ¦€");
1506
1507            assert!(match_pattern("πŸ¦€*", "πŸ¦€test"));
1508            assert!(!match_pattern("πŸ¦€*", "test"));
1509        }
1510    }
1511}