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