Skip to main content

relay_pattern/
lib.rs

1//! A glob like pattern used throught Relay and its APIs.
2//!
3//! # Behaviour
4//!
5//! A pattern is similar to a glob but without support for brace expansions and without any support
6//! for filesystem specific behaviour like platform dependent separators and file extension
7//! matching.
8//!
9//! By default a [`Pattern`] does not support any separator characters.
10//! For example `*` usually only matches up to the next path separator (often platform dependent),
11//! in a [`Pattern`] `*` matches all characters. Optional support for a single separator character
12//! is available.
13//!
14//! The empty glob `""` never matches.
15//!
16//! # Syntax
17//!
18//! Basic glob like syntax is supported with Unix style negations.
19//!
20//! * `?` matches any single character.
21//! * `*` matches any number of any characters, including none.
22//! * `[abc]` matches one character in the given bracket.
23//! * `[!abc]` matches one character that is not in the given bracket.
24//! * `[a-z]` matches one character in the given range.
25//! * `[!a-z]` matches one character that is not in the given range.
26//! * `{a,b}` matches any pattern within the alternation group.
27//! * `\` escapes any of the above special characters and treats it as a literal.
28//!
29//! # Complexity
30//!
31//! Patterns can be limited to a maximum complexity using [`PatternBuilder::max_complexity`].
32//! Complexity of a pattern is calculated by the amount of possible combinations created with
33//! alternations.
34//!
35//! For example, the pattern `{foo,bar}` has a complexity of 2, the pattern `{foo,bar}/{*.html,*.js,*.css}`
36//! has a complexity of `2 * 3`.
37//!
38//! For untrusted user input it is highly recommended to limit the maximum complexity.
39
40use std::fmt::{self, Write};
41use std::num::NonZeroUsize;
42
43mod typed;
44mod wildmatch;
45
46pub use typed::*;
47
48/// Pattern parsing error.
49#[derive(Debug)]
50pub struct Error {
51    pattern: String,
52    kind: ErrorKind,
53}
54
55#[derive(Debug)]
56enum ErrorKind {
57    /// The specified range is invalid. The `end` character is lexicographically
58    /// after the `start` character.
59    InvalidRange(char, char),
60    /// Unbalanced character class. The pattern contains unbalanced `[`, `]` characters.
61    UnbalancedCharacterClass,
62    /// Character class is invalid and cannot be parsed.
63    InvalidCharacterClass,
64    /// Nested alternates are not valid.
65    NestedAlternates,
66    /// Unbalanced alternates. The pattern contains unbalanced `{`, `}` characters.
67    UnbalancedAlternates,
68    /// Dangling escape character.
69    DanglingEscape,
70    /// The pattern's complexity exceeds the maximum allowed complexity.
71    Complexity {
72        complexity: u64,
73        max_complexity: u64,
74    },
75}
76
77impl std::error::Error for Error {}
78
79impl fmt::Display for Error {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        write!(f, "Error parsing pattern '{}': ", self.pattern)?;
82        match &self.kind {
83            ErrorKind::InvalidRange(start, end) => {
84                write!(f, "Invalid character range `{start}-{end}`")
85            }
86            ErrorKind::UnbalancedCharacterClass => write!(f, "Unbalanced character class"),
87            ErrorKind::InvalidCharacterClass => write!(f, "Invalid character class"),
88            ErrorKind::NestedAlternates => write!(f, "Nested alternates"),
89            ErrorKind::UnbalancedAlternates => write!(f, "Unbalanced alternates"),
90            ErrorKind::DanglingEscape => write!(f, "Dangling escape"),
91            ErrorKind::Complexity {
92                complexity,
93                max_complexity,
94            } => write!(
95                f,
96                "Pattern complexity ({complexity}) exceeds maximum allowed complexity ({max_complexity})"
97            ),
98        }
99    }
100}
101
102/// Error returned from [`Pattern::is_match`] when the matching runs out of gas.
103#[derive(Debug, PartialEq, Eq)]
104pub struct OutOfGas(u64);
105
106impl std::error::Error for OutOfGas {}
107
108impl fmt::Display for OutOfGas {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        write!(f, "Pattern could not be matched with {} ops", self.0)
111    }
112}
113
114/// `Pattern` represents a successfully parsed Relay pattern.
115///
116/// A pattern can be parsed/de-serialized from a string, serializing a pattern again may not produce
117/// the same original pattern but a normalized variant of the pattern.
118///
119/// ```
120/// # use relay_pattern::Pattern;
121/// let pattern = Pattern::builder("Foo**").case_insensitive(true).build().unwrap();
122/// assert_eq!(&pattern.to_string(), "foo*");
123/// ```
124///
125/// Patterns can be compared with other patterns, a pattern is considered equal with another pattern
126/// if its parsed and normalized forms and options are the same. Two patterns with the same options
127/// but built from different strings may compare equal if their normalized forms are the same.
128///
129/// ```
130/// # use relay_pattern::Pattern;
131/// let pattern1 = Pattern::builder("Foo**").case_insensitive(true).build().unwrap();
132/// let pattern2 = Pattern::builder("foo*").case_insensitive(true).build().unwrap();
133/// assert_eq!(&pattern1, &pattern2);
134/// # assert_eq!(&pattern2, &pattern1);
135///
136/// let pattern1 = Pattern::builder("Foo**").case_insensitive(true).build().unwrap();
137/// let pattern2 = Pattern::builder("foo*").case_insensitive(false).build().unwrap();
138/// assert_ne!(&pattern1, &pattern2);
139/// # assert_ne!(&pattern2, &pattern1);
140/// ```
141#[derive(Clone, PartialEq, Eq)]
142pub struct Pattern {
143    case_sensitive: CaseSensitive,
144    strategy: MatchStrategy,
145}
146
147impl Pattern {
148    /// Create a new [`Pattern`] from a string with the default settings.
149    pub fn new(pattern: &str) -> Result<Self, Error> {
150        Self::builder(pattern).build()
151    }
152
153    /// Create a new [`PatternBuilder`]. The builder can be used to adjust the
154    /// pattern settings.
155    pub fn builder(pattern: &str) -> PatternBuilder<'_> {
156        PatternBuilder {
157            pattern,
158            case_sensitive: CaseSensitive(true),
159            max_complexity: u64::MAX,
160        }
161    }
162
163    /// Returns `true` if the pattern matches the passed string.
164    pub fn is_match(&self, haystack: &str, gas: Gas) -> Result<bool, OutOfGas> {
165        let opts = MatchOptions {
166            case_sensitive: self.case_sensitive,
167            gas: &mut gas.clone(),
168        };
169        self.strategy
170            .is_match(haystack, opts)
171            .map_err(|_| OutOfGas(gas.0))
172    }
173}
174
175impl fmt::Debug for Pattern {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        f.debug_struct("Pattern")
178            .field("<pattern>", &self.to_string())
179            .field("case_sensitive", &self.case_sensitive)
180            .field("strategy", &self.strategy)
181            .finish()
182    }
183}
184
185impl fmt::Display for Pattern {
186    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187        self.strategy.fmt(f)
188    }
189}
190
191#[cfg(feature = "serde")]
192impl serde::Serialize for Pattern {
193    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194    where
195        S: serde::Serializer,
196    {
197        serializer.collect_str(&self)
198    }
199}
200
201#[cfg(feature = "serde")]
202impl<'de> serde::Deserialize<'de> for Pattern {
203    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204    where
205        D: serde::Deserializer<'de>,
206    {
207        let pattern = String::deserialize(deserializer)?;
208        Pattern::new(&pattern).map_err(serde::de::Error::custom)
209    }
210}
211
212/// A collection of [`Pattern`]s sharing the same configuration.
213#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct Patterns {
215    strategies: Box<[MatchStrategy]>,
216    case_sensitive: CaseSensitive,
217}
218
219impl Patterns {
220    /// Creates an empty [`Patterns`] instance which never matches anything.
221    ///
222    /// ```
223    /// # use relay_pattern::{Patterns, Gas};
224    /// let patterns = Patterns::empty();
225    ///
226    /// assert_eq!(patterns.is_match("", Gas::MAX), Ok(false));
227    /// assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(false));
228    /// ```
229    pub fn empty() -> Self {
230        Self {
231            strategies: Default::default(),
232            case_sensitive: CaseSensitive(true),
233        }
234    }
235
236    /// Returns a [`PatternsBuilder`].
237    pub fn builder() -> PatternsBuilder {
238        PatternsBuilder {
239            case_sensitive: CaseSensitive(true),
240        }
241    }
242
243    /// Returns `true` if any of the contained patterns matches the passed string.
244    pub fn is_match(&self, haystack: &str, gas: Gas) -> Result<bool, OutOfGas> {
245        let remaining_gas = &mut gas.clone();
246        for strategy in &self.strategies {
247            let opts = MatchOptions {
248                case_sensitive: self.case_sensitive,
249                gas: remaining_gas,
250            };
251            if strategy
252                .is_match(haystack, opts)
253                .map_err(|_| OutOfGas(gas.0))?
254            {
255                return Ok(true);
256            }
257        }
258        Ok(false)
259    }
260
261    /// Returns `true` if this instance contains no patterns.
262    ///
263    /// An empty [`Patterns`] never matches any input.
264    pub fn is_empty(&self) -> bool {
265        self.strategies.is_empty()
266    }
267}
268
269#[cfg(feature = "serde")]
270impl serde::Serialize for Patterns {
271    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272    where
273        S: serde::Serializer,
274    {
275        struct AsDisplay<'a>(&'a MatchStrategy);
276        impl serde::Serialize for AsDisplay<'_> {
277            fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
278                serializer.collect_str(self.0)
279            }
280        }
281
282        serializer.collect_seq(self.strategies.iter().map(AsDisplay))
283    }
284}
285
286#[cfg(feature = "serde")]
287impl<'de> serde::Deserialize<'de> for Patterns {
288    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289    where
290        D: serde::Deserializer<'de>,
291    {
292        struct Visitor;
293
294        impl<'de> serde::de::Visitor<'de> for Visitor {
295            type Value = Patterns;
296
297            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
298                formatter.write_str("a sequence of patterns")
299            }
300
301            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
302            where
303                A: serde::de::SeqAccess<'de>,
304            {
305                let mut builder = Patterns::builder().patterns();
306                while let Some(pattern) = seq.next_element::<std::borrow::Cow<'_, str>>()? {
307                    builder.add(&pattern).map_err(serde::de::Error::custom)?;
308                }
309                Ok(builder.build())
310            }
311        }
312
313        deserializer.deserialize_seq(Visitor)
314    }
315}
316
317/// A builder for a [`Pattern`].
318#[derive(Debug)]
319pub struct PatternBuilder<'a> {
320    pattern: &'a str,
321    max_complexity: u64,
322    case_sensitive: CaseSensitive,
323}
324
325impl PatternBuilder<'_> {
326    /// If enabled matches the pattern case insensitive.
327    ///
328    /// This is disabled by default.
329    pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
330        self.case_sensitive = CaseSensitive(!enabled);
331        self
332    }
333
334    /// Sets the max complexity for this pattern.
335    ///
336    /// Attempting to build a pattern with a complexity higher
337    /// than the maximum specified here will fail.
338    ///
339    /// Complexity is a constraint enforced when building a pattern,
340    /// it does not change [`PartialEq`] and [`Eq`] comparisons.
341    ///
342    /// Defaults to `u64::MAX`.
343    pub fn max_complexity(&mut self, max_complexity: u64) -> &mut Self {
344        self.max_complexity = max_complexity;
345        self
346    }
347
348    /// Build a new [`Pattern`] from the passed pattern and configured options.
349    pub fn build(&self) -> Result<Pattern, Error> {
350        let mut parser = Parser::new(self.pattern, self.case_sensitive);
351        parser.parse().map_err(|kind| Error {
352            pattern: self.pattern.to_owned(),
353            kind,
354        })?;
355
356        if parser.complexity > self.max_complexity {
357            return Err(Error {
358                pattern: self.pattern.to_owned(),
359                kind: ErrorKind::Complexity {
360                    complexity: parser.complexity,
361                    max_complexity: self.max_complexity,
362                },
363            });
364        }
365
366        let strategy = MatchStrategy::from_tokens(parser.tokens).map_err(|kind| Error {
367            pattern: self.pattern.to_owned(),
368            kind,
369        })?;
370
371        Ok(Pattern {
372            case_sensitive: self.case_sensitive,
373            strategy,
374        })
375    }
376}
377
378/// A builder for a collection of [`Patterns`].
379#[derive(Debug)]
380pub struct PatternsBuilder {
381    case_sensitive: CaseSensitive,
382}
383
384impl PatternsBuilder {
385    /// If enabled matches the pattern case insensitive.
386    ///
387    /// This is disabled by default.
388    pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
389        self.case_sensitive = CaseSensitive(!enabled);
390        self
391    }
392
393    /// Returns a [`PatternsBuilderConfigured`] builder which allows adding patterns.
394    pub fn patterns(&mut self) -> PatternsBuilderConfigured {
395        PatternsBuilderConfigured {
396            strategies: Vec::new(),
397            case_sensitive: self.case_sensitive,
398        }
399    }
400
401    /// Adds a pattern to the builder and returns the resulting [`PatternsBuilderConfigured`].
402    pub fn add(&mut self, pattern: &str) -> Result<PatternsBuilderConfigured, Error> {
403        let mut builder = PatternsBuilderConfigured {
404            strategies: Vec::with_capacity(1),
405            case_sensitive: self.case_sensitive,
406        };
407        builder.add(pattern)?;
408        Ok(builder)
409    }
410}
411
412/// A [`PatternsBuilder`] with all options configured.
413///
414/// The second step after [`PatternsBuilder`].
415#[derive(Debug)]
416pub struct PatternsBuilderConfigured {
417    strategies: Vec<MatchStrategy>,
418    case_sensitive: CaseSensitive,
419}
420
421impl PatternsBuilderConfigured {
422    /// Adds a pattern to the builder.
423    pub fn add(&mut self, pattern: &str) -> Result<&mut Self, Error> {
424        let mut parser = Parser::new(pattern, self.case_sensitive);
425        parser.parse().map_err(|kind| Error {
426            pattern: pattern.to_owned(),
427            kind,
428        })?;
429
430        let strategy = MatchStrategy::from_tokens(parser.tokens).map_err(|kind| Error {
431            pattern: pattern.to_owned(),
432            kind,
433        })?;
434
435        self.strategies.push(strategy);
436
437        Ok(self)
438    }
439
440    /// Builds a [`Patterns`] from the contained patterns.
441    pub fn build(self) -> Patterns {
442        Patterns {
443            strategies: self.strategies.into_boxed_slice(),
444            case_sensitive: self.case_sensitive,
445        }
446    }
447
448    /// Returns [`Patterns`] containing all added patterns and removes them from the builder.
449    ///
450    /// The builder can still be used afterwards, it keeps the configuration.
451    pub fn take(&mut self) -> Patterns {
452        Patterns {
453            strategies: std::mem::take(&mut self.strategies).into_boxed_slice(),
454            case_sensitive: self.case_sensitive,
455        }
456    }
457}
458
459/// Whether the pattern is matching case sensitive.
460///
461/// Patterns match by default case sensitive.
462#[derive(Debug, Clone, Copy, PartialEq, Eq)]
463struct CaseSensitive(pub bool);
464
465/// A gas amount which can be consumed during matching.
466///
467/// Gas bounds the overall runtime of the matching.
468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
469pub struct Gas(u64);
470
471impl Gas {
472    /// Maximum available gas for basically unconstrained matching.
473    pub const MAX: Self = Gas(u64::MAX);
474
475    /// Amount of gas which allows for reasonable pattern matches but does not allow unconstrained matches.
476    ///
477    /// It is recommended to use this value when the pattern is user controlled.
478    pub const CONSTRAINED: Self = Gas(50_000);
479
480    /// Creates a new [`Gas`] budget.
481    pub const fn new(gas: u64) -> Self {
482        Self(gas)
483    }
484
485    /// Attempts to use one unit of gas.
486    ///
487    /// Returns `None` if all gas has been used up.
488    fn try_consume(&mut self) -> Result<(), OutOfGas> {
489        self.0 = self.0.checked_sub(1).ok_or(OutOfGas(0))?;
490        Ok(())
491    }
492}
493
494/// Options to influence [`Pattern`] compilation and matching behaviour.
495#[derive(Debug)]
496struct MatchOptions<'a> {
497    /// Whether the matching is case insensitive.
498    ///
499    /// This flag must match how the tokens were compiled as components like literals must be
500    /// normalized beforehand.
501    pub case_sensitive: CaseSensitive,
502    /// Amount of 'gas' which the matching is allowed to consume.
503    ///
504    /// Every matching 'op' takes up 1 gas, the matcher will consume gas until out.
505    pub gas: &'a mut Gas,
506}
507
508/// Matching strategy for a [`Pattern`].
509///
510/// Certain patterns can be matched more efficiently while the complex
511/// patterns fallback to [`wildmatch::is_match`].
512#[derive(Debug, Clone, PartialEq, Eq)]
513enum MatchStrategy {
514    /// The pattern is a single literal string.
515    ///
516    /// The stored string is converted to lowercase for case insensitive patterns.
517    ///
518    /// Example pattern: `foobar`.
519    Literal(Literal),
520    /// The pattern only has a single wildcard in the end and can be
521    /// matched with a simple prefix check.
522    ///
523    /// The stored string is converted to lowercase for case insensitive patterns.
524    ///
525    /// Example pattern: `foobar*`.
526    Prefix(Literal),
527    /// The pattern only has a single wildcard at the start and can be
528    /// matched with a simple suffix check.
529    ///
530    /// The stored string is converted to lowercase for case insensitive patterns.
531    ///
532    /// Example pattern: `*foobar`.
533    Suffix(Literal),
534    /// The pattern is surrounded with wildcards and contains a literal in the middle
535    /// and can be matched with a simple contains check.
536    ///
537    /// The stored string is converted to lowercase for case insensitive patterns.
538    ///
539    /// Example pattern: `*foobar*`.
540    Contains(Literal),
541    /// The pattern always evaluates to a static boolean.
542    ///
543    /// Example: `*`
544    Static(bool),
545    /// The pattern is complex and needs to be evaluated using [`wildmatch`].
546    Wildmatch(Tokens),
547    // Possible future optimizations for `Any` variations:
548    // Examples: `??`. `??suffix`, `prefix??` and `?contains?`.
549}
550
551impl MatchStrategy {
552    /// Create a [`MatchStrategy`] from [`Tokens`].
553    fn from_tokens(mut tokens: Tokens) -> Result<Self, ErrorKind> {
554        let s = match tokens.as_mut_slice() {
555            [] => Self::Static(false),
556            [Token::Wildcard] => Self::Static(true),
557            [Token::Literal(literal)] => Self::Literal(std::mem::take(literal)),
558            [Token::Literal(literal), Token::Wildcard] => Self::Prefix(std::mem::take(literal)),
559            [Token::Wildcard, Token::Literal(literal)] => Self::Suffix(std::mem::take(literal)),
560            [Token::Wildcard, Token::Literal(literal), Token::Wildcard] => {
561                Self::Contains(std::mem::take(literal))
562            }
563            _ => Self::Wildmatch(tokens),
564        };
565
566        Ok(s)
567    }
568
569    /// Returns `true` if the pattern matches the passed string.
570    pub fn is_match(&self, haystack: &str, options: MatchOptions) -> Result<bool, OutOfGas> {
571        match &self {
572            MatchStrategy::Literal(literal) => Ok(match_literal(literal, haystack, options)),
573            MatchStrategy::Prefix(prefix) => Ok(match_prefix(prefix, haystack, options)),
574            MatchStrategy::Suffix(suffix) => Ok(match_suffix(suffix, haystack, options)),
575            MatchStrategy::Contains(contains) => Ok(match_contains(contains, haystack, options)),
576            MatchStrategy::Static(matches) => Ok(*matches),
577            MatchStrategy::Wildmatch(tokens) => wildmatch::is_match(haystack, tokens, options),
578        }
579    }
580}
581
582impl fmt::Display for MatchStrategy {
583    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584        match self {
585            MatchStrategy::Literal(literal) => literal.fmt(f),
586            MatchStrategy::Prefix(literal) => {
587                literal.fmt(f)?;
588                f.write_char('*')
589            }
590            MatchStrategy::Suffix(literal) => {
591                f.write_char('*')?;
592                literal.fmt(f)
593            }
594            MatchStrategy::Contains(literal) => {
595                f.write_char('*')?;
596                literal.fmt(f)?;
597                f.write_char('*')
598            }
599            MatchStrategy::Static(true) => f.write_char('*'),
600            // This is the empty glob, which never matches.
601            MatchStrategy::Static(false) => Ok(()),
602            MatchStrategy::Wildmatch(tokens) => tokens.fmt(f),
603        }
604    }
605}
606
607#[inline(always)]
608fn match_literal(literal: &Literal, haystack: &str, options: MatchOptions) -> bool {
609    if options.case_sensitive == CaseSensitive(false) {
610        // Can't do an explicit len compare first here `literal.len() == haystack.len()`,
611        // the amount of characters can change when converting case.
612        //
613        // The literal matches if the prefix match consumes the entire haystack.
614        wildmatch::is_prefix_case_insensitive(haystack, literal)
615            .is_some_and(|len| len == haystack.len())
616    } else {
617        literal.as_case_converted_str() == haystack
618    }
619}
620
621#[inline(always)]
622fn match_prefix(prefix: &Literal, haystack: &str, options: MatchOptions) -> bool {
623    if options.case_sensitive == CaseSensitive(false) {
624        wildmatch::is_prefix_case_insensitive(haystack, prefix).is_some()
625    } else {
626        haystack.starts_with(prefix.as_case_converted_str())
627    }
628}
629
630#[inline(always)]
631fn match_suffix(suffix: &Literal, haystack: &str, options: MatchOptions) -> bool {
632    if options.case_sensitive == CaseSensitive(false) {
633        let mut suffix = suffix.as_case_converted_str().chars().rev();
634        let mut haystack = haystack.chars().flat_map(|c| c.to_lowercase()).rev();
635
636        loop {
637            match (suffix.next(), haystack.next()) {
638                // If the prefix is exhausted it matched.
639                (None, _) => break true,
640                // If the haystack is exhausted, but the pattern is not -> no match.
641                (Some(_), None) => break false,
642                (Some(s), Some(h)) if s != h => break false,
643                _ => {}
644            }
645        }
646    } else {
647        haystack.ends_with(suffix.as_case_converted_str())
648    }
649}
650
651#[inline(always)]
652fn match_contains(contains: &Literal, haystack: &str, options: MatchOptions) -> bool {
653    if options.case_sensitive == CaseSensitive(false) {
654        let haystack = haystack.to_lowercase();
655        memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
656    } else {
657        memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
658    }
659}
660
661struct Parser<'a> {
662    chars: std::iter::Peekable<std::str::Chars<'a>>,
663    tokens: Tokens,
664    alternates: Option<Vec<Tokens>>,
665    current_literal: Option<String>,
666    case_sensitive: CaseSensitive,
667    complexity: u64,
668}
669
670impl<'a> Parser<'a> {
671    fn new(pattern: &'a str, case_sensitive: CaseSensitive) -> Self {
672        Self {
673            chars: pattern.chars().peekable(),
674            tokens: Default::default(),
675            alternates: None,
676            current_literal: None,
677            case_sensitive,
678            complexity: 0,
679        }
680    }
681
682    fn parse(&mut self) -> Result<(), ErrorKind> {
683        while let Some(c) = self.advance() {
684            match c {
685                '?' => self.push_token(Token::Any(NonZeroUsize::MIN)),
686                '*' => self.push_token(Token::Wildcard),
687                '[' => self.parse_class()?,
688                ']' => return Err(ErrorKind::UnbalancedCharacterClass),
689                '{' => self.start_alternates()?,
690                '}' => self.end_alternates()?,
691                '\\' => match self.advance() {
692                    Some(c) => self.push_literal(c),
693                    None => return Err(ErrorKind::DanglingEscape),
694                },
695                ',' if self.alternates.is_some() => {
696                    self.finish_literal();
697                    // safe to unwrap, we just checked for `some`.
698                    let alternates = self.alternates.as_mut().unwrap();
699                    alternates.push(Tokens::default());
700                }
701                c => self.push_literal(c),
702            }
703        }
704
705        // Finish off the parsing with creating a token for any remaining literal buffered.
706        self.finish_literal();
707
708        Ok(())
709    }
710
711    fn start_alternates(&mut self) -> Result<(), ErrorKind> {
712        if self.alternates.is_some() {
713            return Err(ErrorKind::NestedAlternates);
714        }
715        self.finish_literal();
716        self.alternates = Some(vec![Tokens::default()]);
717        Ok(())
718    }
719
720    fn end_alternates(&mut self) -> Result<(), ErrorKind> {
721        self.finish_literal();
722        match self.alternates.take() {
723            None => return Err(ErrorKind::UnbalancedAlternates),
724            Some(alternates) => {
725                if !alternates.is_empty() {
726                    self.complexity = self
727                        .complexity
728                        .max(1)
729                        .saturating_mul(alternates.len() as u64);
730                    self.push_token(Token::Alternates(alternates));
731                }
732            }
733        }
734
735        Ok(())
736    }
737
738    fn parse_class(&mut self) -> Result<(), ErrorKind> {
739        let negated = self.advance_if(|c| c == '!');
740
741        let mut ranges = Ranges::default();
742
743        let mut first = true;
744        let mut in_range = false;
745        loop {
746            let Some(c) = self.advance() else {
747                return Err(ErrorKind::UnbalancedCharacterClass);
748            };
749
750            match c {
751                // Another opening bracket is invalid, literal `[` need to be escaped.
752                '[' => return Err(ErrorKind::InvalidCharacterClass),
753                ']' => break,
754                '-' => {
755                    if first {
756                        ranges.push(Range::single('-'));
757                    } else if in_range {
758                        // safe to unwrap, `in_range` is only true if there is already
759                        // a range pushed.
760                        ranges.last_mut().unwrap().set_end('-')?;
761                        in_range = false;
762                    } else {
763                        assert!(!ranges.is_empty());
764                        in_range = true;
765                    }
766                }
767                c => {
768                    let c = match c {
769                        '\\' => self.advance().ok_or(ErrorKind::DanglingEscape)?,
770                        c => c,
771                    };
772
773                    if in_range {
774                        // safe to unwrap, `in_range` is only true if there is already
775                        // a range pushed.
776                        ranges.last_mut().unwrap().set_end(c)?;
777                        in_range = false;
778                    } else {
779                        ranges.push(Range::single(c))
780                    }
781                }
782            }
783
784            first = false;
785        }
786
787        if in_range {
788            // A pattern which ends with a `-`.
789            ranges.push(Range::single('-'));
790        }
791
792        self.push_token(Token::Class { negated, ranges });
793
794        Ok(())
795    }
796
797    /// Pushes a new character into the currently active literal token.
798    ///
799    /// Starts a new literal token if there is none already.
800    fn push_literal(&mut self, c: char) {
801        self.current_literal.get_or_insert_with(String::new).push(c);
802    }
803
804    /// Finishes and pushes the currently in progress literal token.
805    fn finish_literal(&mut self) {
806        if let Some(literal) = self.current_literal.take() {
807            self.push_token(Token::Literal(Literal::new(literal, self.case_sensitive)));
808        }
809    }
810
811    /// Pushes the passed `token` and finishes the currently in progress literal token.
812    fn push_token(&mut self, token: Token) {
813        self.finish_literal();
814        match self.alternates.as_mut() {
815            Some(alternates) => match alternates.last_mut() {
816                Some(tokens) => tokens.push(token),
817                None => {
818                    let mut tokens = Tokens::default();
819                    tokens.push(token);
820                    alternates.push(tokens);
821                }
822            },
823            None => self.tokens.push(token),
824        }
825    }
826
827    fn advance(&mut self) -> Option<char> {
828        self.chars.next()
829    }
830
831    fn advance_if(&mut self, matcher: impl FnOnce(char) -> bool) -> bool {
832        if self.peek().is_some_and(matcher) {
833            let _ = self.advance();
834            true
835        } else {
836            false
837        }
838    }
839
840    fn peek(&mut self) -> Option<char> {
841        self.chars.peek().copied()
842    }
843}
844
845/// A container of tokens.
846///
847/// Automatically folds redundant tokens.
848///
849/// The contained tokens are guaranteed to uphold the following invariants:
850/// - A [`Token::Wildcard`] is never followed by [`Token::Wildcard`].
851/// - A [`Token::Any`] is never followed by [`Token::Any`].
852/// - A [`Token::Literal`] is never followed by [`Token::Literal`].
853/// - A [`Token::Class`] is never empty.
854#[derive(Clone, Debug, Default, PartialEq, Eq)]
855struct Tokens(Vec<Token>);
856
857impl Tokens {
858    fn push(&mut self, mut token: Token) {
859        // Normalize / clean the token.
860        if let Token::Alternates(mut alternates) = token {
861            let mut contains_empty = false;
862            let mut contains_wildcard = false;
863            alternates.retain_mut(|alternate| {
864                if alternate.0.is_empty() {
865                    contains_empty = true;
866                    return false;
867                }
868
869                if matches!(alternate.0.as_slice(), [Token::Wildcard]) {
870                    contains_wildcard = true;
871                }
872
873                true
874            });
875
876            // At this point `alternates` contains only the nonempty branches
877            // and we additionally know
878            // * if one of the branches was just a wildcard
879            // * if there were any empty branches.
880            //
881            // We can push different tokens based on this.
882            if contains_wildcard {
883                // Case: {foo,*,} -> reduces to *
884                token = Token::Wildcard;
885            } else if alternates.len() == 1 {
886                if contains_empty {
887                    // Case: {foo*bar,} -> Optional(foo*bar)
888                    token = Token::Optional(alternates.remove(0));
889                } else {
890                    // Case: {foo*bar} -> remove the alternation and
891                    // push foo*bar directly
892                    for t in alternates.remove(0).0 {
893                        self.push(t);
894                    }
895                    return;
896                }
897            } else if alternates.len() > 1 {
898                if contains_empty {
899                    // Case: {foo,bar,} -> Optional({foo,bar})
900                    token = Token::OptionalAlternates(alternates);
901                } else {
902                    // Case: {foo, bar} -> can stay as it is
903                    token = Token::Alternates(alternates);
904                }
905            } else {
906                // Case: {,,,} -> reduces to {}
907                return;
908            }
909        }
910
911        match (self.0.last_mut(), token) {
912            // Collapse Any's.
913            (Some(Token::Any(n)), Token::Any(n2)) => *n = n.saturating_add(n2.get()),
914            // Collapse multiple wildcards into a single one.
915            // TODO: separator special handling (?)
916            (Some(Token::Wildcard), Token::Wildcard) => {}
917            // Collapse wildcards with optionals.
918            (Some(Token::Wildcard), Token::Optional(_) | Token::OptionalAlternates(_)) => {}
919            (Some(Token::Optional(_) | Token::OptionalAlternates(_)), Token::Wildcard) => {
920                self.0.pop();
921                // We can now also remove all other preceding optionals.
922                while let Some(Token::Optional(_) | Token::OptionalAlternates(_)) = self.0.last() {
923                    self.0.pop();
924                }
925                self.0.push(Token::Wildcard);
926            }
927            // Collapse multiple literals into one.
928            (Some(Token::Literal(last)), Token::Literal(s)) => last.push(&s),
929            // Ignore empty class tokens.
930            (_, Token::Class { negated: _, ranges }) if ranges.is_empty() => {}
931            // Everything else is just another token.
932            (_, token) => self.0.push(token),
933        }
934    }
935
936    fn as_mut_slice(&mut self) -> &mut [Token] {
937        self.0.as_mut_slice()
938    }
939
940    fn as_slice(&self) -> &[Token] {
941        self.0.as_slice()
942    }
943}
944
945impl fmt::Display for Tokens {
946    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947        for token in &self.0 {
948            token.fmt(f)?;
949        }
950
951        Ok(())
952    }
953}
954
955/// Represents a token in a Relay pattern.
956#[derive(Clone, Debug, PartialEq, Eq)]
957enum Token {
958    /// A literal token.
959    Literal(Literal),
960    /// The any token `?` and how many `?` are seen in a row.
961    Any(NonZeroUsize),
962    /// The wildcard token `*`.
963    Wildcard,
964    /// A class token `[abc]` or its negated variant `[!abc]`.
965    Class { negated: bool, ranges: Ranges },
966    /// A list of nested alternate tokens `{a,b}`.
967    Alternates(Vec<Tokens>),
968    /// A list of nested alternate tokens, where none need to match.
969    ///
970    /// There is no dedicated syntax for this, it is parsed from an alternate
971    /// group with an empty alternate: `{a,b,}`.
972    OptionalAlternates(Vec<Tokens>),
973    /// A list of optional tokens.
974    ///
975    /// This has no syntax of its own, it's parsed from an alternate with two
976    /// alternations where one of them is empty: `{a,}`.
977    Optional(Tokens),
978}
979
980impl fmt::Display for Token {
981    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
982        match self {
983            Token::Literal(literal) => literal.fmt(f),
984            Token::Any(num) => {
985                for _ in 0..num.get() {
986                    f.write_char('?')?;
987                }
988                Ok(())
989            }
990            Token::Wildcard => f.write_char('*'),
991            Token::Class { negated, ranges } => {
992                f.write_char('[')?;
993                if *negated {
994                    f.write_char('!')?;
995                }
996                ranges.fmt(f)?;
997                f.write_char(']')
998            }
999            Token::Alternates(items) => {
1000                f.write_char('{')?;
1001                let mut is_first = true;
1002                for item in items {
1003                    if !is_first {
1004                        f.write_char(',')?;
1005                    } else {
1006                        is_first = false;
1007                    }
1008                    item.fmt(f)?;
1009                }
1010                f.write_char('}')
1011            }
1012            Token::OptionalAlternates(items) => {
1013                f.write_char('{')?;
1014                for item in items {
1015                    item.fmt(f)?;
1016                    // This will always produce an empty group as the last item in the alternate,
1017                    // which is exactly what this token is built from.
1018                    f.write_char(',')?;
1019                }
1020                f.write_char('}')
1021            }
1022            Token::Optional(tokens) => {
1023                f.write_char('{')?;
1024                tokens.fmt(f)?;
1025                f.write_char(',')?;
1026                f.write_char('}')
1027            }
1028        }
1029    }
1030}
1031
1032/// A string literal.
1033///
1034/// The contained literal is only available as a case converted string.
1035/// Depending on whether the pattern is case sensitive or case insensitive the literal is either
1036/// the original string or converted to lowercase.
1037#[derive(Clone, Debug, Default, PartialEq, Eq)]
1038struct Literal(String);
1039
1040impl Literal {
1041    /// Creates a new literal from `s` and `options`.
1042    fn new(s: String, case_sensitive: CaseSensitive) -> Self {
1043        match case_sensitive {
1044            CaseSensitive(true) => Self(s),
1045            CaseSensitive(false) => Self(s.to_lowercase()),
1046        }
1047    }
1048
1049    /// Adds a literal to this literal.
1050    ///
1051    /// This function does not validate case conversion, both literals must be for the same caseing.
1052    fn push(&mut self, Literal(other): &Literal) {
1053        self.0.push_str(other);
1054    }
1055
1056    /// Returns a reference to the case converted string.
1057    fn as_case_converted_str(&self) -> &str {
1058        &self.0
1059    }
1060
1061    /// Returns a reference to the case converted string as bytes.
1062    fn as_case_converted_bytes(&self) -> &[u8] {
1063        self.as_case_converted_str().as_bytes()
1064    }
1065}
1066
1067impl fmt::Display for Literal {
1068    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1069        fn print_escaped_char(c: char, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1070            // A comma must be escaped if the surrounding context is an alternation,
1071            // to not make the printing context dependent the comma is always escaped.
1072            if matches!(c, '*' | '?' | '[' | ']' | '{' | '}' | '\\' | ',') {
1073                f.write_char('\\')?;
1074            }
1075            f.write_char(c)
1076        }
1077
1078        for c in self.0.chars() {
1079            print_escaped_char(c, f)?;
1080        }
1081        Ok(())
1082    }
1083}
1084
1085/// A [`Range`] contains whatever is contained between `[` and `]` of
1086/// a glob pattern, except the negation.
1087///
1088/// For example the pattern `[a-z]` contains the range from `a` to `z`,
1089/// the pattern `[ax-zbf-h]` contains the ranges `x-z`, `f-h`, `a-a` and `b-b`.
1090#[derive(Clone, Debug, Default, PartialEq, Eq)]
1091enum Ranges {
1092    /// An empty, default range not containing any characters.
1093    ///
1094    /// The empty range matches nothing.
1095    #[default]
1096    Empty,
1097    /// The pattern only contains a single range.
1098    ///
1099    /// For example: `[a]` or `[a-z]`.
1100    Single(Range),
1101    /// The pattern contains more than one range.
1102    ///
1103    /// The `Empty` and `Single` states are just explicit and optimized
1104    /// cases for `Multiple` with a vector containing zero or just one range.
1105    Multiple(Vec<Range>),
1106}
1107
1108impl Ranges {
1109    /// Pushes another range into the current [`Range`].
1110    ///
1111    /// Returns [`Error`] if the range starts with a lexicographically larger character than it
1112    /// ends with.
1113    fn push(&mut self, range: Range) {
1114        match self {
1115            Self::Empty => *self = Self::Single(range),
1116            Self::Single(single) => *self = Self::Multiple(vec![*single, range]),
1117            Self::Multiple(v) => v.push(range),
1118        }
1119    }
1120
1121    /// Returns a mutable reference to the last range contained.
1122    fn last_mut(&mut self) -> Option<&mut Range> {
1123        match self {
1124            Ranges::Empty => None,
1125            Ranges::Single(range) => Some(range),
1126            Ranges::Multiple(ranges) => ranges.last_mut(),
1127        }
1128    }
1129
1130    /// Returns `true` if there is no contained range.
1131    fn is_empty(&self) -> bool {
1132        match self {
1133            Ranges::Empty => true,
1134            Ranges::Single(_) => false,
1135            Ranges::Multiple(ranges) => {
1136                // While not technically wrong, the invariant should uphold.
1137                debug_assert!(!ranges.is_empty());
1138                ranges.is_empty()
1139            }
1140        }
1141    }
1142
1143    /// Returns `true` if the character `c` is contained matches any contained range.
1144    #[inline(always)]
1145    fn contains(&self, c: char) -> bool {
1146        // TODO: optimize this into a `starts_with` which gets a `&str`, this can be optimized to
1147        // byte matches
1148        match self {
1149            Self::Empty => false,
1150            Self::Single(range) => range.contains(c),
1151            Self::Multiple(ranges) => ranges.iter().any(|range| range.contains(c)),
1152        }
1153    }
1154}
1155
1156impl fmt::Display for Ranges {
1157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1158        match self {
1159            Ranges::Empty => Ok(()),
1160            Ranges::Single(range) => range.fmt(f),
1161            Ranges::Multiple(ranges) => {
1162                for range in ranges {
1163                    range.fmt(f)?;
1164                }
1165                Ok(())
1166            }
1167        }
1168    }
1169}
1170
1171/// Represents a character range in a [`Token::Class`].
1172#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1173struct Range {
1174    start: char,
1175    end: char,
1176}
1177
1178impl Range {
1179    /// Create a new range which matches a single character.
1180    fn single(c: char) -> Self {
1181        Self { start: c, end: c }
1182    }
1183
1184    /// Changes the end of the range to a new character.
1185    ///
1186    /// Returns an error if the new end character is lexicographically before
1187    /// the start character.
1188    fn set_end(&mut self, end: char) -> Result<(), ErrorKind> {
1189        if self.start > end {
1190            return Err(ErrorKind::InvalidRange(self.start, end));
1191        }
1192        self.end = end;
1193        Ok(())
1194    }
1195
1196    /// Returns `true` if the character `c` is contained in the range.
1197    #[inline(always)]
1198    fn contains(&self, c: char) -> bool {
1199        self.start <= c && c <= self.end
1200    }
1201}
1202
1203impl fmt::Display for Range {
1204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205        fn print_escaped_char(c: char, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1206            // The `!` only needs to be escaped if the range is the first range in a class,
1207            // to not make the escaping context dependent it's always escaped. Similar reasoning
1208            // applies also to `-`.
1209            if matches!(c, '[' | ']' | '\\' | '!' | '-') {
1210                f.write_char('\\')?;
1211            }
1212            f.write_char(c)
1213        }
1214
1215        print_escaped_char(self.start, f)?;
1216        if self.start != self.end {
1217            f.write_char('-')?;
1218            print_escaped_char(self.end, f)?;
1219        }
1220        Ok(())
1221    }
1222}
1223
1224#[cfg(test)]
1225mod tests {
1226    use super::*;
1227
1228    #[track_caller]
1229    fn build_pattern(p: &str, options: &str) -> Pattern {
1230        let mut pattern = Pattern::builder(p);
1231        for opt in options.chars() {
1232            match opt {
1233                'i' => drop(pattern.case_insensitive(true)),
1234                _ => unimplemented!("{opt} not implemented"),
1235            }
1236        }
1237        pattern.build().unwrap()
1238    }
1239
1240    #[track_caller]
1241    fn build_patterns(patterns: &[&str], options: &str) -> Patterns {
1242        let mut builder = Patterns::builder();
1243        for opt in options.chars() {
1244            match opt {
1245                'i' => drop(builder.case_insensitive(true)),
1246                _ => unimplemented!("{opt} not implemented"),
1247            }
1248        }
1249        let mut builder = builder.patterns();
1250        for pattern in patterns {
1251            builder.add(pattern).unwrap();
1252        }
1253        builder.build()
1254    }
1255
1256    macro_rules! pattern {
1257        ($pattern:expr $(,$options:tt)?) => {
1258            build_pattern($pattern, stringify!($($options)?))
1259        };
1260    }
1261
1262    macro_rules! patterns {
1263        ($($pattern:expr),* $(,)?) => {
1264            build_patterns(&[$($pattern),*], "")
1265        };
1266        ($($pattern:expr,)* @ $options:tt) => {
1267            build_patterns(&[$($pattern),*], stringify!($options))
1268        };
1269    }
1270
1271    macro_rules! assert_pattern {
1272        ($pattern:expr, $s:expr $(,$options:tt)?) => {{
1273            let pattern = pattern!($pattern $(,$options)?);
1274            assert!(
1275                pattern.is_match($s, Gas::MAX).unwrap(),
1276                "expected pattern '{}' to match '{}' - {pattern:?}",
1277                $pattern,
1278                $s
1279            );
1280            let pattern = pattern!(&pattern.to_string() $(,$options)?);
1281            assert!(
1282                pattern.is_match($s, Gas::MAX).unwrap(),
1283                "expected round-tripped pattern '{}' to match '{}' - {pattern:?}",
1284                $pattern,
1285                $s
1286            );
1287        }};
1288        ($pattern:expr, NOT $s:expr $(,$options:tt)?) => {{
1289            let pattern = pattern!($pattern $(,$options)?);
1290            assert!(
1291                !pattern.is_match($s, Gas::MAX).unwrap(),
1292                "expected pattern '{}' to not match '{}' - {pattern:?}",
1293                $pattern,
1294                $s
1295            );
1296            let pattern = pattern!(&pattern.to_string() $(,$options)?);
1297            assert!(
1298                !pattern.is_match($s, Gas::MAX).unwrap(),
1299                "expected round-tripped pattern '{}' to not match '{}' - {pattern:?}",
1300                $pattern,
1301                $s
1302            );
1303        }};
1304    }
1305
1306    macro_rules! assert_strategy {
1307        ($pattern:expr, $expected:pat) => {{
1308            let pattern = Pattern::new($pattern).unwrap();
1309            let kind = match &pattern.strategy {
1310                MatchStrategy::Literal(_) => "Literal",
1311                MatchStrategy::Prefix(_) => "Prefix",
1312                MatchStrategy::Suffix(_) => "Suffix",
1313                MatchStrategy::Contains(_) => "Contains",
1314                MatchStrategy::Static(_) => "Static",
1315                MatchStrategy::Wildmatch(_) => "Wildmatch",
1316            };
1317            assert_eq!(
1318                kind,
1319                stringify!($expected),
1320                "expected pattern '{}' to have strategy '{}' - {pattern:?}",
1321                $pattern,
1322                stringify!($expected)
1323            );
1324        }};
1325    }
1326
1327    macro_rules! assert_invalid {
1328        ($pattern:expr) => {{
1329            if let Ok(pattern) = Pattern::new($pattern) {
1330                assert!(
1331                    false,
1332                    "expected pattern '{}' to not compile - {pattern:?}",
1333                    $pattern
1334                );
1335            }
1336        }};
1337    }
1338
1339    #[test]
1340    fn test_empty() {
1341        assert_pattern!("", NOT "");
1342        assert_pattern!("", NOT "foo");
1343    }
1344
1345    #[test]
1346    fn test_literal() {
1347        assert_pattern!("foo", "foo");
1348        assert_pattern!("foo", NOT "fOo");
1349        assert_pattern!("foo", NOT "FOO");
1350        assert_pattern!(r"f\{\}o", "f{}o");
1351        assert_pattern!(r"f\}o", "f}o");
1352        assert_pattern!(r"f\{o", "f{o");
1353        assert_pattern!(r"f\{b,a,r\}o", "f{b,a,r}o");
1354        assert_pattern!(r"f\\o", r"f\o");
1355        assert_pattern!("fඞo", "fඞo");
1356    }
1357
1358    #[test]
1359    fn test_literal_case_insensitive() {
1360        assert_pattern!("foo", "foo", i);
1361        assert_pattern!("foo", "fOo", i);
1362        assert_pattern!("fOo", "Foo", i);
1363        assert_pattern!("İ", "i\u{307}", i);
1364        assert_pattern!("İ", "i̇", i);
1365        assert_pattern!("İ", NOT "i", i);
1366        assert_pattern!("i", NOT "İ", i);
1367        assert_pattern!("kelvin", "\u{212A}elvin", i);
1368        assert_pattern!("\u{212A}elvin", "kelvin", i);
1369        assert_pattern!("ß", "ẞ", i);
1370        assert_pattern!("straße", "straẞe", i);
1371        assert_pattern!("strasse", NOT "straẞe", i);
1372        assert_pattern!("ΑΣ", NOT "ΑΣ", i);
1373        assert_pattern!("ΑΣ", "ας", i);
1374        assert_pattern!("ΑΣ", NOT "ασ", i);
1375        assert_pattern!("ασ", "ΑΣ", i);
1376    }
1377
1378    #[test]
1379    fn test_literal_strategy() {
1380        assert_strategy!("foo", Literal);
1381        assert_strategy!(r"f\{b,a,r\}o", Literal);
1382        assert_strategy!(r"f\\o", Literal);
1383        assert_strategy!("fඞo", Literal);
1384    }
1385
1386    #[test]
1387    fn test_prefix() {
1388        assert_pattern!("foo*", "foo___");
1389        assert_pattern!("foo*", "foo");
1390        assert_pattern!(r"foo\?*", "foo?___");
1391        assert_pattern!(r"foo\?*", NOT "foox___");
1392        assert_pattern!("foo**", "foo");
1393        assert_pattern!("foo*?*", NOT "foo");
1394        assert_pattern!("foo*?*", "foo_");
1395        assert_pattern!("foo*?*?", "foo_____");
1396        assert_pattern!("foo*?*?", NOT "foo");
1397        assert_pattern!("foo*?*?", "foo__");
1398        assert_pattern!("foo*?*?", "foo_____");
1399        assert_pattern!("foo**", "foo___");
1400        assert_pattern!("foo*?*", "foo___");
1401        assert_pattern!("foo*?*?", "foo___");
1402        assert_pattern!("foo*", "fooඞ");
1403        assert_pattern!("ඞ*", "ඞfoo");
1404        assert_pattern!("foo*", NOT "___");
1405        assert_pattern!("foo*", NOT "fo");
1406        assert_pattern!("foo*", NOT "fob");
1407        assert_pattern!("foo*", NOT "boo");
1408        assert_pattern!("foo*", NOT "Foo");
1409        assert_pattern!("foo*", NOT "FOO___");
1410
1411        // No special slash handling
1412        assert_pattern!("foo/bar*", "foo/bar___");
1413        assert_pattern!("foo*", "foo/bar___");
1414        assert_pattern!("foo*", NOT "/foo");
1415    }
1416
1417    #[test]
1418    fn test_prefix_case_insensitive() {
1419        assert_pattern!("foo*", "foo___", i);
1420        assert_pattern!("foo*", "fOo___", i);
1421        assert_pattern!("foo*", "FOO___", i);
1422        assert_pattern!("fOo*", "FOO___", i);
1423        assert_pattern!("fOo*", "Foo___", i);
1424
1425        assert_pattern!("İ*", "İ___", i);
1426        assert_pattern!("İ*", "İ", i);
1427        assert_pattern!("İ*", "i̇", i);
1428        assert_pattern!("İ*", "i\u{307}___", i);
1429        assert_pattern!("İ*", NOT "i____", i);
1430
1431        assert_pattern!("kelvin*", "\u{212A}elvin___", i);
1432        assert_pattern!("\u{212A}elvin*", "kelvin___", i);
1433        assert_pattern!("ΑΣ*", NOT "ΑΣ", i);
1434        assert_pattern!("ΑΣ*", "ας___", i);
1435        assert_pattern!("ΑΣ*", NOT "ασ___", i);
1436        assert_pattern!("ασ*", "ΑΣ___", i);
1437    }
1438
1439    #[test]
1440    fn test_prefix_strategy() {
1441        assert_strategy!("foo*", Prefix);
1442        assert_strategy!("foo**", Prefix);
1443        assert_strategy!("foo?*", Wildmatch);
1444    }
1445
1446    #[test]
1447    fn test_suffix() {
1448        assert_pattern!("*foo", "___foo");
1449        assert_pattern!("*foo", "foo");
1450        assert_pattern!(r"*\?foo", "___?foo");
1451        assert_pattern!(r"*\?foo", NOT "___xfoo");
1452        assert_pattern!("**foo", "foo");
1453        assert_pattern!("*?*foo", NOT "foo");
1454        assert_pattern!("*?*foo", "_foo");
1455        assert_pattern!("*?*foo", "_____foo");
1456        assert_pattern!("?*?*foo", NOT "foo");
1457        assert_pattern!("?*?*foo", NOT "_foo");
1458        assert_pattern!("?*?*foo", "__foo");
1459        assert_pattern!("?*?*foo", "_____foo");
1460        assert_pattern!("**foo", "___foo");
1461        assert_pattern!("*?*foo", "___foo");
1462        assert_pattern!("*?*?foo", "__foo");
1463        assert_pattern!("*foo", "ඞfoo");
1464        assert_pattern!("*ඞ", "fooඞ");
1465        assert_pattern!("*foo", NOT "bar");
1466        assert_pattern!("*foo", NOT "fo");
1467        assert_pattern!("*foo", NOT "fob");
1468        assert_pattern!("*foo", NOT "boo");
1469        assert_pattern!("*foo", NOT "Foo");
1470        assert_pattern!("*foo", NOT "___FOO");
1471
1472        // No special slash handling
1473        assert_pattern!("*foo/bar", "___foo/bar");
1474        assert_pattern!("*bar", "___foo/bar");
1475        assert_pattern!("*foo", NOT "foo/");
1476    }
1477
1478    #[test]
1479    fn test_suffix_case_insensitive() {
1480        assert_pattern!("foo*", "foo___", i);
1481        assert_pattern!("foo*", "fOo___", i);
1482        assert_pattern!("foo*", "FOO___", i);
1483        assert_pattern!("fOo*", "FOO___", i);
1484        assert_pattern!("fOo*", "Foo___", i);
1485
1486        assert_pattern!("*İ", "___İ", i);
1487        assert_pattern!("*İ", "İ", i);
1488        assert_pattern!("*İ", "i̇", i);
1489        assert_pattern!("*İ", "___i\u{307}", i);
1490        assert_pattern!("*İ", NOT "___i", i);
1491    }
1492
1493    #[test]
1494    fn test_suffix_strategy() {
1495        assert_strategy!("*foo", Suffix);
1496        assert_strategy!("**foo", Suffix);
1497        assert_strategy!("*?foo", Wildmatch);
1498    }
1499
1500    #[test]
1501    fn test_contains() {
1502        assert_pattern!("*foo*", "foo");
1503        assert_pattern!(r"*\?foo*", "___?foo___");
1504        assert_pattern!(r"*\?foo*", NOT "___xfoo___");
1505        assert_pattern!("*foo*", "foo___");
1506        assert_pattern!("*foo*", "___foo");
1507        assert_pattern!("*foo*", "___foo___");
1508        assert_pattern!("*foo*", NOT "___fo");
1509        assert_pattern!("*foo*", NOT "oo___");
1510        assert_pattern!("*foo*", NOT "___fo___");
1511        assert_pattern!("*foo*", NOT "fඞo");
1512        assert_pattern!("*foo*", NOT "___fOo___");
1513        assert_pattern!("*foo*", NOT "___FOO___");
1514
1515        // No special slash handling
1516        assert_pattern!("*foo*", "foo");
1517        assert_pattern!("*foo*", "foo_/_");
1518        assert_pattern!("*foo*", "_/_foo");
1519        assert_pattern!("*foo*", "_/_foo_/_");
1520        assert_pattern!("*f/o*", "_/_f/o_/_");
1521    }
1522
1523    #[test]
1524    fn test_contains_case_insensitive() {
1525        assert_pattern!("*foo*", "foo", i);
1526        assert_pattern!("*foo*", "fOo", i);
1527        assert_pattern!("*fOo*", "Foo", i);
1528        assert_pattern!("*foo*", "___foo___", i);
1529        assert_pattern!("*foo*", "___fOo___", i);
1530        assert_pattern!("*foo*", "___FOO___", i);
1531        assert_pattern!("*fOo*", "___FOO___", i);
1532        assert_pattern!("*fOo*", "___Foo___", i);
1533
1534        assert_pattern!("*İ*", "___İ___", i);
1535        assert_pattern!("*İ*", "İ", i);
1536        assert_pattern!("*İ*", "___İ", i);
1537        assert_pattern!("*İ*", "İ___", i);
1538        assert_pattern!("*İ*", "___İ___", i);
1539        assert_pattern!("*İ*", "i̇", i);
1540        assert_pattern!("*İ*", "___i̇", i);
1541        assert_pattern!("*İ*", "i̇___", i);
1542        assert_pattern!("*İ*", "___i̇___", i);
1543        assert_pattern!("*İ*", "___i\u{307}", i);
1544        assert_pattern!("*İ*", "i\u{307}___", i);
1545        assert_pattern!("*İ*", "___i\u{307}___", i);
1546        assert_pattern!("*İ*", NOT "i", i);
1547        assert_pattern!("*İ*", NOT "i___", i);
1548        assert_pattern!("*İ*", NOT "___i", i);
1549        assert_pattern!("*İ*", NOT "___i___", i);
1550    }
1551
1552    #[test]
1553    fn test_contains_strategy() {
1554        assert_strategy!("*foo*", Contains);
1555        assert_strategy!("**foo**", Contains);
1556        assert_strategy!("*?foo*", Wildmatch);
1557        assert_strategy!("*foo?*", Wildmatch);
1558        assert_strategy!("*foo*?", Wildmatch);
1559        assert_strategy!("?*foo*", Wildmatch);
1560    }
1561
1562    #[test]
1563    fn test_wildcard() {
1564        assert_pattern!("*", "");
1565        assert_pattern!("*", "a");
1566        assert_pattern!("*", "\n");
1567        assert_pattern!("*", "\n\n");
1568        assert_pattern!("*", "\na\n");
1569        assert_pattern!("*", "\na\nb\nc");
1570        assert_pattern!("*", "ඞfooඞfooඞ");
1571
1572        // No special slash handling
1573        assert_pattern!("*", "/");
1574        assert_pattern!("*", "_/");
1575        assert_pattern!("*", "/_");
1576        assert_pattern!("*", "_/_");
1577        assert_pattern!("*", "/?/?/");
1578    }
1579
1580    #[test]
1581    fn test_wildcard_strategy() {
1582        assert_strategy!("*", Static);
1583        assert_strategy!("{*}", Static);
1584        assert_strategy!("{*,}", Static);
1585        assert_strategy!("{foo,*}", Static);
1586        assert_strategy!("{foo,*}?{*,bar}", Wildmatch);
1587        assert_strategy!("{*,}?{*,}", Wildmatch);
1588    }
1589
1590    #[test]
1591    fn test_any() {
1592        assert_pattern!("?", NOT "");
1593        assert_pattern!("?", "ඞ");
1594        assert_pattern!("?", "?");
1595        assert_pattern!("?", "\n");
1596        assert_pattern!("?", "_");
1597        assert_pattern!("?", NOT "aa");
1598        assert_pattern!("?", NOT "aaaaaaaaaaaaaaaaaa");
1599        assert_pattern!("??", "aa");
1600        assert_pattern!("??", NOT "aaa");
1601        assert_pattern!("a?a?a", "aaaaa");
1602        assert_pattern!("a?a?a", "abaca");
1603        assert_pattern!("a?a?a", NOT "ab_ca");
1604        assert_pattern!("a?a?a", NOT "aaAaa");
1605        assert_pattern!("???????????x???????????", "???????????x???????????");
1606        assert_pattern!("???????????x???????????", "??______???x?????_?????");
1607        assert_pattern!("???????????x???????????", NOT "?______???x?????_?????");
1608        assert_pattern!("???????????x???????????", NOT "??______???_?????_?????");
1609        assert_pattern!(
1610            "??????????????????????????????????????????????????",
1611            "?????????????????????????????????????????????????!"
1612        );
1613        assert_pattern!("foo?bar", "foo?bar");
1614        assert_pattern!("foo?bar", "foo!bar");
1615        assert_pattern!("a??a", "aඞඞa");
1616
1617        // No special slash handling
1618        assert_pattern!("?", "/");
1619    }
1620
1621    #[test]
1622    fn test_any_wildcard() {
1623        assert_pattern!("??*", NOT "");
1624        assert_pattern!("??*", NOT "a");
1625        assert_pattern!("??*", "ab");
1626        assert_pattern!("??*", "abc");
1627        assert_pattern!("??*", "abcde");
1628
1629        assert_pattern!("*??", NOT "");
1630        assert_pattern!("*??", NOT "a");
1631        assert_pattern!("*??", "ab");
1632        assert_pattern!("*??", "abc");
1633        assert_pattern!("*??", "abcde");
1634
1635        assert_pattern!("*??*", NOT "");
1636        assert_pattern!("*??*", NOT "a");
1637        assert_pattern!("*??*", "ab");
1638        assert_pattern!("*??*", "abc");
1639        assert_pattern!("*??*", "abcde");
1640
1641        assert_pattern!("*?*?*", NOT "");
1642        assert_pattern!("*?*?*", NOT "a");
1643        assert_pattern!("*?*?*", "ab");
1644        assert_pattern!("*?*?*", "abc");
1645        assert_pattern!("*?*?*", "abcde");
1646    }
1647
1648    #[test]
1649    fn test_escapes() {
1650        assert_pattern!(r"f\\o", r"f\o");
1651        assert_pattern!(r"f\*o", r"f*o");
1652        assert_pattern!(r"f\*o", NOT r"f\*o");
1653        assert_pattern!(r"f\?o", "f?o");
1654        assert_pattern!(r"f\?o", NOT "fao");
1655        assert_pattern!(r"f\\*o", r"f\*o");
1656        assert_pattern!(r"f\\*o", r"f\o");
1657        assert_pattern!(r"f\\*o", r"f\___o");
1658        assert_pattern!(r"f\\\*o", r"f\*o");
1659        assert_pattern!(r"f\[\]o", r"f[]o");
1660        assert_pattern!(r"f\[?\]o", r"f[?]o");
1661        assert_pattern!(r"f\[a-z\]o", r"f[a-z]o");
1662        assert_pattern!(r"f\[o", r"f[o");
1663        assert_pattern!(r"f\]o", r"f]o");
1664        assert_pattern!(r"f\,o", "f,o");
1665        assert_pattern!(r"\[", r"[");
1666    }
1667
1668    #[test]
1669    fn test_invalid() {
1670        assert_invalid!(r"\");
1671        assert_invalid!(r"f\");
1672        assert_invalid!(r"*\");
1673        assert_invalid!("[");
1674        assert_invalid!("[a-z");
1675        assert_invalid!(r"[a-z\");
1676        assert_invalid!("[[]");
1677        assert_invalid!("[]]");
1678        assert_invalid!("]");
1679        assert_invalid!("[a-z");
1680        assert_invalid!("[b-a]");
1681        assert_invalid!("[a-A]");
1682        assert_invalid!("{a,b,{c,d}}");
1683    }
1684
1685    #[test]
1686    fn test_classes() {
1687        assert_pattern!("[]", NOT "");
1688        assert_pattern!("[]", NOT "_");
1689        assert_pattern!("[a]", "a");
1690        assert_pattern!("[a]", NOT "[a]");
1691        assert_pattern!("[a]", NOT "b");
1692        assert_pattern!("[a]", NOT "A");
1693        assert_pattern!("[ඞ]", "ඞ");
1694        assert_pattern!("[ඞ]", NOT "a");
1695        assert_pattern!("[ඞa]", "a");
1696        assert_pattern!("[aඞ]", "ඞ");
1697        assert_pattern!("[ඞa]", NOT "b");
1698        assert_pattern!("[ab]", "a");
1699        assert_pattern!("[ab]", "b");
1700        assert_pattern!("[ab]", NOT "c");
1701        assert_pattern!("x[ab]x", "xax");
1702        assert_pattern!("x[ab]x", "xbx");
1703        assert_pattern!("x[ab]x", NOT "xBx");
1704        assert_pattern!("x[ab]x", NOT "xcx");
1705        assert_pattern!("x[ab]x", NOT "aax");
1706        assert_pattern!("x[ab]x", NOT "xaa");
1707        assert_pattern!("x[ab]x", NOT "xaax");
1708        assert_pattern!("x[ab]x", NOT "xxax");
1709        assert_pattern!("x[ab]x", NOT "xaxx");
1710        assert_pattern!("[a-b]", "a");
1711        assert_pattern!("[a-b]", "b");
1712        assert_pattern!("[a-b]", NOT "c");
1713        assert_pattern!("[a-c]", "a");
1714        assert_pattern!("[a-c]", "b");
1715        assert_pattern!("[a-c]", "c");
1716        assert_pattern!("[a-c]", NOT "d");
1717        assert_pattern!("[a-c]", NOT "1");
1718        assert_pattern!("[a-c]", NOT "ඞ");
1719        assert_pattern!("[A-z]", "a");
1720        assert_pattern!("[A-z]", "z");
1721        assert_pattern!("[A-z]", "["); // `[` is actually inbetween here in the ascii table
1722        assert_pattern!("[A-z]", "A");
1723        assert_pattern!("[A-z]", "Z");
1724        assert_pattern!("[A-z]", NOT "0");
1725        assert_pattern!("[0-9]", "0");
1726        assert_pattern!("[0-9]", "1");
1727        assert_pattern!("[0-9]", "2");
1728        assert_pattern!("[0-9]", "3");
1729        assert_pattern!("[0-9]", "4");
1730        assert_pattern!("[0-9]", "5");
1731        assert_pattern!("[0-9]", "6");
1732        assert_pattern!("[0-9]", "7");
1733        assert_pattern!("[0-9]", "8");
1734        assert_pattern!("[0-9]", "9");
1735        assert_pattern!(
1736            "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1737            "3bYf"
1738        );
1739        assert_pattern!(
1740            "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1741            NOT "3cYf"
1742        );
1743        assert_pattern!(
1744            "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1745            NOT "3ඞYf"
1746        );
1747        assert_pattern!("[0-9]", NOT "a9");
1748        assert_pattern!("[0-9]", NOT "9a");
1749        assert_pattern!("[0-9]", NOT "a9a");
1750        assert_pattern!("[0-9]", NOT "");
1751        assert_pattern!("[0-9!]", "!");
1752        assert_pattern!("[0-9][a-b]", NOT "");
1753        assert_pattern!("[0-9][a-b]", NOT "a");
1754        assert_pattern!("[0-9][a-b]", NOT "a0");
1755        assert_pattern!("[0-9][a-b]", "0a");
1756        assert_pattern!(r"a[\]a\-]b", "aab");
1757
1758        // TODO: lenient: assert_pattern!("a[]-]b", NOT "aab");
1759        // TODO: lenient: assert_pattern!("]", "]");
1760        // TODO: lenient: assert_pattern!("a[]-]b", "a-]b");
1761        // TODO: lenient: assert_pattern!("a[]-]b", "a]b");
1762        // TODO: lenient: assert_pattern!("a[]]b", "a]b");
1763
1764        // Escapes in character classes
1765        assert_pattern!(r"[\\]", r"\");
1766        assert_pattern!(r"[\\]", NOT "a");
1767        assert_pattern!(r"[\]]", "]");
1768        assert_pattern!(r"[\]]", NOT "a");
1769        assert_pattern!(r"[\[]", "[");
1770        assert_pattern!(r"[\[]", NOT "a");
1771        assert_pattern!(r"[\]]", NOT r"\");
1772        assert_pattern!(r"[\!]", "!");
1773        assert_pattern!(r"[\!]", NOT "a");
1774        assert_pattern!(r"[a\-c]", "-");
1775        assert_pattern!(r"[a\-c]", NOT "b");
1776        assert_pattern!(r"[\!--]", "!");
1777        assert_pattern!(r"[\!--]", "-");
1778        assert_pattern!(r"[\!--]", NOT "a");
1779        assert_pattern!(r"[\[-a]", "[");
1780        assert_pattern!(r"[\[-a]", "a");
1781        assert_pattern!(r"[\[-a]", NOT "b");
1782        assert_pattern!(r"[A-\]]", "]");
1783        assert_pattern!(r"[A-\]]", "Z");
1784        assert_pattern!(r"[A-\]]", NOT "a");
1785        assert_pattern!(r"[A-\\]", r"\");
1786        assert_pattern!(r"[A-\\]", NOT "a");
1787        assert_pattern!(r"[\]-z]", "]");
1788        assert_pattern!(r"[\]-z]", "z");
1789        assert_pattern!(r"[\]-z]", NOT r"\");
1790        assert_pattern!(r"[\\-z]", r"\");
1791        assert_pattern!(r"[\\-z]", "z");
1792        assert_pattern!(r"[\\-z]", NOT "[");
1793        assert_pattern!(r"[\--z]", "-");
1794        assert_pattern!(r"[\--z]", "z");
1795        assert_pattern!(r"[\--z]", NOT "!");
1796        assert_pattern!("[*?{},]", "*");
1797        assert_pattern!("[*?{},]", "?");
1798        assert_pattern!("[*?{},]", "{");
1799        assert_pattern!("[*?{},]", "}");
1800        assert_pattern!("[*?{},]", ",");
1801        assert_pattern!("[*?{},]", NOT "a");
1802
1803        assert_pattern!("a[X-]b", "a-b");
1804        assert_pattern!("a[X-]b", "aXb");
1805    }
1806
1807    #[test]
1808    fn test_classes_case_insensitive() {
1809        assert_pattern!("[a]", "a", i);
1810        assert_pattern!("[a]", "A", i);
1811        assert_pattern!("x[ab]x", "xAX", i);
1812        assert_pattern!("x[ab]x", "XBx", i);
1813        assert_pattern!("x[ab]x", NOT "Xcx", i);
1814        assert_pattern!("x[ab]x", NOT "aAx", i);
1815        assert_pattern!("x[ab]x", NOT "xAa", i);
1816        assert_pattern!("[ǧ]", "Ǧ", i);
1817        assert_pattern!("[Ǧ]", "ǧ", i);
1818    }
1819
1820    #[test]
1821    fn test_classes_negated() {
1822        assert_pattern!("[!]", NOT "");
1823        assert_pattern!(r"[!\!]", "a");
1824        assert_pattern!(r"[!\!]", NOT "!");
1825        assert_pattern!("[!a]", "b");
1826        assert_pattern!("[!a]", "A");
1827        assert_pattern!("[!a]", "B");
1828        assert_pattern!("[!b]", NOT "b");
1829        assert_pattern!("[!ab]", NOT "a");
1830        assert_pattern!("[!ab]", NOT "b");
1831        assert_pattern!("[!ab]", "c");
1832        assert_pattern!("x[!ab]x", "xcx");
1833        assert_pattern!("x[!ab]x", NOT "xax");
1834        assert_pattern!("x[!ab]x", NOT "xbx");
1835        assert_pattern!("x[!ab]x", NOT "xxcx");
1836        assert_pattern!("x[!ab]x", NOT "xcxx");
1837        assert_pattern!("x[!ab]x", NOT "xc");
1838        assert_pattern!("x[!ab]x", NOT "cx");
1839        assert_pattern!("x[!ab]x", NOT "x");
1840        assert_pattern!("[!a-c]", NOT "a");
1841        assert_pattern!("[!a-c]", NOT "b");
1842        assert_pattern!("[!a-c]", NOT "c");
1843        assert_pattern!("[!a-c]", "d");
1844        assert_pattern!("[!a-c]", "A");
1845        assert_pattern!("[!a-c]", "ඞ");
1846        assert_pattern!(r"[!a-c\\]", "d");
1847        assert_pattern!(r"[!a-c\\]", NOT r"\");
1848        assert_pattern!(r"[!\]]", "a");
1849        assert_pattern!(r"[!\]]", NOT "]");
1850        assert_pattern!(r"[!!]", "a");
1851        assert_pattern!(r"[!!]", NOT "!");
1852    }
1853
1854    #[test]
1855    fn test_classes_negated_case_insensitive() {
1856        assert_pattern!("[!a]", "b", i);
1857        assert_pattern!("[!a]", "B", i);
1858        assert_pattern!("[!b]", NOT "b", i);
1859        assert_pattern!("[!b]", NOT "B", i);
1860        assert_pattern!("[!ab]", NOT "a", i);
1861        assert_pattern!("[!ab]", NOT "A", i);
1862        assert_pattern!("[!ab]", NOT "b", i);
1863        assert_pattern!("[!ab]", NOT "B", i);
1864        assert_pattern!("[!ab]", "c", i);
1865        assert_pattern!("[!ab]", "C", i);
1866    }
1867
1868    #[test]
1869    fn test_alternates() {
1870        assert_pattern!("{}foo{}", "foo");
1871        assert_pattern!("foo{}bar", "foobar");
1872        assert_pattern!("foo{}{}bar", "foobar");
1873        assert_pattern!("{foo}", "foo");
1874        assert_pattern!("{foo}", NOT "fOo");
1875        assert_pattern!("{foo}", NOT "bar");
1876        assert_pattern!("{foo,bar}", "foo");
1877        assert_pattern!("{foo,bar}", "bar");
1878        assert_pattern!(r"{foo,bar,baz\,}", "foo");
1879        assert_pattern!(r"{foo,bar,baz\,}", "baz,");
1880        assert_pattern!(r"{foo,bar,baz\,}", NOT "baz");
1881        assert_pattern!(r"{foo,bar,baz\,}", NOT "");
1882        assert_pattern!(r"{foo\,,}", "foo,");
1883        assert_pattern!(r"{foo\,,}", "");
1884        assert_pattern!(r"{foo\,,}", NOT "foo");
1885        assert_pattern!(r"{foo,bar\,,}", "bar,");
1886        assert_pattern!(r"{foo,bar\,,}", "");
1887        assert_pattern!(r"{foo,bar\,,}", NOT "bar");
1888        assert_pattern!("{foo,bar}", NOT "Foo");
1889        assert_pattern!("{foo,bar}", NOT "fOo");
1890        assert_pattern!("{foo,bar}", NOT "BAR");
1891        assert_pattern!("{foo,bar}", NOT "fooo");
1892        assert_pattern!("{foo,bar}", NOT "baar");
1893        assert_pattern!("{foo,bar,}baz", "foobaz");
1894        assert_pattern!("{foo,bar,}baz", "barbaz");
1895        assert_pattern!("{foo,bar,}baz", "baz");
1896        assert_pattern!("{foo,,bar}baz", "foobaz");
1897        assert_pattern!("{foo,,bar}baz", "barbaz");
1898        assert_pattern!("{foo,,bar}baz", "baz");
1899        assert_pattern!("{,foo,bar}baz", "foobaz");
1900        assert_pattern!("{,foo,bar}baz", "barbaz");
1901        assert_pattern!("{,foo,bar}baz", "baz");
1902        assert_pattern!("{foo*bar}", "foobar");
1903        assert_pattern!("{foo*bar}", "fooooobar");
1904        assert_pattern!("{foo*bar}", NOT "");
1905        assert_pattern!("{foo*bar,}", "foobar");
1906        assert_pattern!("{foo*bar,}", "fooooobar");
1907        assert_pattern!("{foo*bar,}", "");
1908        assert_pattern!("{foo*bar,baz}", "foobar");
1909        assert_pattern!("{foo*bar,baz}", "fooooobar");
1910        assert_pattern!("{foo*bar,baz}", "baz");
1911        assert_pattern!("{foo*bar,baz}", NOT "");
1912        assert_pattern!("{foo*bar,baz,}", "foobar");
1913        assert_pattern!("{foo*bar,baz,}", "fooooobar");
1914        assert_pattern!("{foo*bar,baz,}", "baz");
1915        assert_pattern!("{foo*bar,baz,}", "");
1916        assert_pattern!("{,,,,}", NOT "");
1917        assert_pattern!("{[fb][oa][or]}", "foo");
1918        assert_pattern!("{[fb][oa][or]}", "bar");
1919        assert_pattern!("{[fb][oa][or],baz}", "foo");
1920        assert_pattern!("{[fb][oa][or],baz}", "bar");
1921        assert_pattern!("{[fb][oa][or],baz}", "baz");
1922        assert_pattern!("{baz,[fb][oa][or]}", "baz");
1923        assert_pattern!("{baz,[fb][oa][or]}", "foo");
1924        assert_pattern!("{baz,[fb][oa][or]}", "bar");
1925        assert_pattern!("{baz,[fb][oa][or]}", "bor");
1926        assert_pattern!("{baz,[fb][oa][or]}", NOT "barr");
1927        assert_pattern!("{baz,[fb][oa][or]}", NOT "boz");
1928        assert_pattern!("{baz,[fb][oa][or]}", NOT "fbar");
1929        assert_pattern!("{baz,[fb][oa][or]}", NOT "bAr");
1930        assert_pattern!("{baz,[fb][oa][or]}", NOT "Foo");
1931        assert_pattern!("{baz,[fb][oa][or]}", NOT "Bar");
1932        assert_pattern!("{baz,b[aA]r}", NOT "bAz");
1933        assert_pattern!("{baz,b[!aA]r}", NOT "bar");
1934        assert_pattern!("{baz,b[!aA]r}", "bXr");
1935        assert_pattern!("{[a-z],[0-9]}", "a");
1936        assert_pattern!("{[a-z],[0-9]}", "3");
1937        assert_pattern!("a{[a-z],[0-9]}a", "a3a");
1938        assert_pattern!("a{[a-z],[0-9]}a", "aba");
1939        assert_pattern!("a{[a-z],[0-9]}a", NOT "aAa");
1940        assert_pattern!("a{[a-z],?}a", "aXa");
1941        assert_pattern!(r"a{[a-z],\?}a", "a?a");
1942        assert_pattern!(r"a{[a-z],\?}a", NOT "aXa");
1943        assert_pattern!(r"a{[a-z],\?}a", NOT r"a\a");
1944        assert_pattern!(r"a{\[\],\{\}}a", "a[]a");
1945        assert_pattern!(r"a{\[\],\{\}}a", "a{}a");
1946        assert_pattern!(r"a{\[\],\{\}}a", NOT "a[}a");
1947        assert_pattern!(r"a{\[\],\{\}}a", NOT "a{]a");
1948        assert_pattern!(r"a{\[\],\{\}}a", NOT "a[a");
1949        assert_pattern!(r"a{\[\],\{\}}a", NOT "a]a");
1950        assert_pattern!(r"a{\[\],\{\}}a", NOT "a{a");
1951        assert_pattern!(r"a{\[\],\{\}}a", NOT "a}a");
1952        assert_pattern!("foo/{*.js,*.html}", "foo/.js");
1953        assert_pattern!("foo/{*.js,*.html}", "foo/.html");
1954        assert_pattern!("foo/{*.js,*.html}", "foo/bar.js");
1955        assert_pattern!("foo/{*.js,*.html}", "foo/bar.html");
1956        assert_pattern!("foo/{*.js,*.html}", NOT "foo/bar.png");
1957        assert_pattern!("foo/{*.js,*.html}", NOT "bar/bar.js");
1958        assert_pattern!("{foo,abc}{def,bar}", "foodef");
1959        assert_pattern!("{foo,abc}{def,bar}", "foobar");
1960        assert_pattern!("{foo,abc}{def,bar}", "abcdef");
1961        assert_pattern!("{foo,abc}{def,bar}", "abcbar");
1962        assert_pattern!("{foo,abc}{def,bar}", NOT "foofoo");
1963        assert_pattern!("{foo,abc}{def,bar}", NOT "fooabc");
1964        assert_pattern!("{foo,abc}{def,bar}", NOT "defdef");
1965        assert_pattern!("{foo,abc}{def,bar}", NOT "defabc");
1966    }
1967
1968    #[test]
1969    fn test_alternates_many() {
1970        const N: usize = 100_000;
1971
1972        let pattern = Pattern::new(&"{ab,ba}".repeat(N)).unwrap();
1973        assert_eq!(pattern.is_match(&"ab".repeat(N), Gas::MAX), Ok(true));
1974        assert_eq!(pattern.is_match(&"ba".repeat(N), Gas::MAX), Ok(true));
1975        assert_eq!(pattern.is_match(&"abba".repeat(N / 2), Gas::MAX), Ok(true));
1976        assert_eq!(pattern.is_match(&"ab".repeat(N - 1), Gas::MAX), Ok(false));
1977        assert_eq!(
1978            pattern.is_match(&format!("{}aa", "ab".repeat(N - 1)), Gas::MAX),
1979            Ok(false)
1980        );
1981    }
1982
1983    #[test]
1984    fn test_alternates_optional() {
1985        assert_pattern!("{a,}{b,}", "ab");
1986        assert_pattern!("{a,}{b,}", "a");
1987        assert_pattern!("{a,}{b,}", "b");
1988        assert_pattern!("{a,}{b,}", "");
1989        assert_pattern!("{a,b,}{c,}", "ac");
1990        assert_pattern!("{a,b,}{c,}", "bc");
1991        assert_pattern!("{a,b,}{c,}", "a");
1992        assert_pattern!("{a,b,}{c,}", "b");
1993        assert_pattern!("{a,b,}{c,}", "c");
1994        assert_pattern!("{a,b,}{c,}", "");
1995        assert_pattern!("{a,b,}{c,}", NOT "ab");
1996        assert_pattern!("{a,b,}{c,}", NOT "abc");
1997    }
1998
1999    #[test]
2000    fn test_alternate_strategy() {
2001        // Empty alternates can be simplified.
2002        assert_strategy!("{}foo{}", Literal);
2003        assert_strategy!("foo{}bar", Literal);
2004        assert_strategy!("foo{}{}{}bar", Literal);
2005        assert_strategy!("foo{,,,}bar", Literal);
2006    }
2007
2008    #[test]
2009    fn test_optional_wildcard_strategy() {
2010        // Optional alternates after a wildcard can be folded into a wildcard.
2011        assert_strategy!("*{foo,}", Static);
2012        assert_strategy!("*{foo,bar,}", Static);
2013        assert_strategy!("foo*{bar,}", Prefix);
2014        assert_strategy!("foo*{bar,baz,}", Prefix);
2015        assert_strategy!("*{foo,}bar", Suffix);
2016        assert_strategy!("*{foo,baz,}bar", Suffix);
2017        assert_strategy!("*{bar,}foo*", Contains);
2018        assert_strategy!("*{bar,baz,}foo*", Contains);
2019
2020        // The same is true for the inverse, we can fold alterantes followed by a wildcard into a wildcard.
2021        assert_strategy!("{foo,}*", Static);
2022        assert_strategy!("{foo,bar,}*", Static);
2023        assert_strategy!("foo{bar,}*", Prefix);
2024        assert_strategy!("foo{bar,baz,}*", Prefix);
2025        assert_strategy!("{foo,}*bar", Suffix);
2026        assert_strategy!("{foo,baz,}*bar", Suffix);
2027        assert_strategy!("*foo{bar,}*", Contains);
2028        assert_strategy!("*foo{bar,baz,}*", Contains);
2029
2030        // This also applies for multiple chained alternates.
2031        assert_strategy!("*{bar,}{baz,qux,}foo", Suffix);
2032        assert_strategy!("{*,bar}{baz,qux,}foo", Suffix);
2033        assert_strategy!("foo{bar,}{baz,qux,}*", Prefix);
2034        assert_strategy!("foo{bar,}{baz,qux,}{bar,*}", Prefix);
2035    }
2036
2037    #[test]
2038    fn test_alternates_case_insensitive() {
2039        assert_pattern!("{foo}", "foo", i);
2040        assert_pattern!("{foo}", "fOo", i);
2041        assert_pattern!("{foo}", NOT "bar", i);
2042        assert_pattern!("{foo,bar}", "foo", i);
2043        assert_pattern!("{foo,bar}", "bar", i);
2044        assert_pattern!("{foo,bar}", "Foo", i);
2045        assert_pattern!("{foo,bar}", "fOo", i);
2046        assert_pattern!("{foo,bar}", "BAR", i);
2047        assert_pattern!("{foo,bar}", NOT "bao", i);
2048        assert_pattern!("{f[o0-9]o,b[a]r}", "foo", i);
2049        assert_pattern!("{f[o0-9]o,b[a]r}", "fOo", i);
2050        assert_pattern!("{f[o0-9]o,b[a]r}", "f1o", i);
2051        assert_pattern!("{f[o0-9]o,b[a]r}", "foO", i);
2052        assert_pattern!("{f[o0-9]o,b[a]r}", "FOO", i);
2053        assert_pattern!("{f[o0-9]o,b[a]r}", "bar", i);
2054        assert_pattern!("{f[o0-9]o,b[a]r}", "bAr", i);
2055        assert_pattern!("{f[o0-9]o,b[a]r}", "baR", i);
2056        assert_pattern!("{f[o0-9]o,b[a]r}", "BAR", i);
2057        assert_pattern!("{f[o0-9]o,b[!a]r}", "foo", i);
2058        assert_pattern!("{f[o0-9]o,b[!a]r}", "bXr", i);
2059        assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bar", i);
2060        assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bAr", i);
2061    }
2062
2063    #[test]
2064    fn test_complex() {
2065        assert_pattern!("*?", "\n");
2066        assert_pattern!("?*", "\n");
2067        assert_pattern!("*?*", "\n");
2068        assert_pattern!("1.18.[!0-4].*", "1.18.5.");
2069        assert_pattern!("1.18.[!0-4].*", "1.18.5.aBc");
2070        assert_pattern!("1.18.[!0-4].*", NOT "1.18.3.abc");
2071        assert_pattern!("!*!*.md", "!foo!.md"); // no `!` outside of character classes
2072        assert_pattern!("foo*foofoo*foobar", "foofoofooxfoofoobar");
2073        assert_pattern!("foo*fooFOO*fOobar", "fooFoofooXfoofooBAR", i);
2074        assert_pattern!("[0-9]*a", "0aaaaaaaaa", i);
2075        assert_pattern!("[0-9]*Bar[x]", "0foobarx", i);
2076
2077        assert_pattern!(
2078            r"/api/0/organizations/\{organization_slug\}/event*",
2079            "/api/0/organizations/{organization_slug}/event/foobar"
2080        );
2081        assert_pattern!(
2082            r"/api/0/organizations/\{organization_slug\}/event*",
2083            NOT r"/api/0/organizations/\{organization_slug\}/event/foobar"
2084        );
2085
2086        assert_pattern!(
2087            "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
2088            "foobarwithacrazylongprefixandanditactuallymatches"
2089        );
2090        assert_pattern!(
2091            "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
2092            "FOOBARWITHACRAZYLONGPREFIXANDANDITACTUALLYMATCHES",
2093            i
2094        );
2095    }
2096
2097    /// Tests collected by [Kirk J Krauss].
2098    ///
2099    /// Kirk J Krauss: http://developforperformance.com/MatchingWildcards_AnImprovedAlgorithmForBigData.html.
2100    #[test]
2101    fn test_kirk_j_krauss() {
2102        // Case with first wildcard after total match.
2103        assert_pattern!("Hi*", "Hi");
2104
2105        // Case with mismatch after '*'
2106        assert_pattern!("ab*d", NOT "abc");
2107
2108        // Cases with repeating character sequences.
2109        assert_pattern!("*ccd", "abcccd");
2110        assert_pattern!("*issip*ss*", "mississipissippi");
2111        assert_pattern!("xxxx*zzy*fffff", NOT "xxxx*zzzzzzzzy*f");
2112        assert_pattern!("xxx*zzy*f", "xxxx*zzzzzzzzy*f");
2113        assert_pattern!("xxxx*zzy*fffff", NOT "xxxxzzzzzzzzyf");
2114        assert_pattern!("xxxx*zzy*f", "xxxxzzzzzzzzyf");
2115        assert_pattern!("xy*z*xyz", "xyxyxyzyxyz");
2116        assert_pattern!("*sip*", "mississippi");
2117        assert_pattern!("xy*xyz", "xyxyxyxyz");
2118        assert_pattern!("mi*sip*", "mississippi");
2119        assert_pattern!("*abac*", "ababac");
2120        assert_pattern!("*abac*", "ababac");
2121        assert_pattern!("a*zz*", "aaazz");
2122        assert_pattern!("*12*23", NOT "a12b12");
2123        assert_pattern!("a12b", NOT "a12b12");
2124        assert_pattern!("*12*12*", "a12b12");
2125
2126        // From DDJ reader Andy Belf
2127        assert_pattern!("*a?b", "caaab");
2128
2129        // Additional cases where the '*' char appears in the tame string.
2130        assert_pattern!("*", "*");
2131        assert_pattern!("a*b", "a*abab");
2132        assert_pattern!("a*", "a*r");
2133        assert_pattern!("a*aar", NOT "a*ar");
2134
2135        // More double wildcard scenarios.
2136        assert_pattern!("XY*Z*XYz", "XYXYXYZYXYz");
2137        assert_pattern!("*SIP*", "missisSIPpi");
2138        assert_pattern!("*issip*PI", "mississipPI");
2139        assert_pattern!("xy*xyz", "xyxyxyxyz");
2140        assert_pattern!("mi*sip*", "miSsissippi");
2141        assert_pattern!("mi*Sip*", NOT "miSsissippi");
2142        assert_pattern!("*Abac*", "abAbac");
2143        assert_pattern!("*Abac*", "abAbac");
2144        assert_pattern!("a*zz*", "aAazz");
2145        assert_pattern!("*12*23", NOT "A12b12");
2146        assert_pattern!("*12*12*", "a12B12");
2147        assert_pattern!("*oWn*", "oWn");
2148
2149        // Completely tame (no wildcards) cases.
2150        assert_pattern!("bLah", "bLah");
2151        assert_pattern!("bLaH", NOT "bLah");
2152
2153        // Simple mixed wildcard tests suggested by Marlin Deckert.
2154        assert_pattern!("*?", "a");
2155        assert_pattern!("*?", "ab");
2156        assert_pattern!("*?", "abc");
2157
2158        // More mixed wildcard tests including coverage for false positives.
2159        assert_pattern!("??", NOT "a");
2160        assert_pattern!("?*?", "ab");
2161        assert_pattern!("*?*?*", "ab");
2162        assert_pattern!("?**?*?", "abc");
2163        assert_pattern!("?**?*&?", NOT "abc");
2164        assert_pattern!("?b*??", "abcd");
2165        assert_pattern!("?a*??", NOT "abcd");
2166        assert_pattern!("?**?c?", "abcd");
2167        assert_pattern!("?**?d?", NOT "abcd");
2168        assert_pattern!("?*b*?*d*?", "abcde");
2169
2170        // Single-character-match cases.
2171        assert_pattern!("bL?h", "bLah");
2172        assert_pattern!("bLa?", NOT "bLaaa");
2173        assert_pattern!("bLa?", "bLah");
2174        assert_pattern!("?Lah", NOT "bLaH");
2175        assert_pattern!("?LaH", "bLaH");
2176
2177        // Many-wildcard scenarios.
2178        assert_pattern!(
2179            "a*a*a*a*a*a*aa*aaa*a*a*b",
2180            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
2181        );
2182        assert_pattern!(
2183            "*a*b*ba*ca*a*aa*aaa*fa*ga*b*",
2184            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2185        );
2186        assert_pattern!(
2187            "*a*b*ba*ca*a*x*aaa*fa*ga*b*",
2188            NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2189        );
2190        assert_pattern!(
2191            "*a*b*ba*ca*aaaa*fa*ga*gggg*b*",
2192            NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2193        );
2194        assert_pattern!(
2195            "*a*b*ba*ca*aaaa*fa*ga*ggg*b*",
2196            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2197        );
2198        assert_pattern!("*aabbaa*a*", "aaabbaabbaab");
2199        assert_pattern!(
2200            "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
2201            "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*"
2202        );
2203        assert_pattern!("*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaaaaaaaa");
2204        assert_pattern!(
2205            "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
2206            NOT "aaaaaaaaaaaaaaaa"
2207        );
2208        assert_pattern!(
2209            "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
2210            NOT "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
2211        );
2212        assert_pattern!(
2213            "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
2214            "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
2215        );
2216        assert_pattern!("abc*abc*abc*abc*abc", NOT "abc*abcd*abcd*abc*abcd");
2217        assert_pattern!(
2218            "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",
2219            "abc*abcd*abcd*abc*abcd*abcd*abc*abcd*abc*abc*abcd"
2220        );
2221        assert_pattern!("********a********b********c********", "abc");
2222        assert_pattern!("abc", NOT "********a********b********c********");
2223        assert_pattern!("********a********b********b********", NOT "abc");
2224        assert_pattern!("***a*b*c***", "*abc*");
2225
2226        // A case-insensitive algorithm test.
2227        assert_pattern!("*issip*PI", "mississippi", i);
2228
2229        // Tests suggested by other DDJ readers
2230        assert_pattern!("?", NOT "");
2231        assert_pattern!("*?", NOT "");
2232        // assert_pattern!("", ""); - Removed, relay-pattern behaves differently for empty strings.
2233        assert_pattern!("", NOT "a");
2234
2235        // Tame tests:
2236        assert_pattern!("abd", NOT "abc");
2237
2238        // Cases with repeating character sequences.
2239        assert_pattern!("abcccd", "abcccd");
2240        assert_pattern!("mississipissippi", "mississipissippi");
2241        assert_pattern!("xxxxzzzzzzzzyfffff", NOT "xxxxzzzzzzzzyf");
2242        assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
2243        assert_pattern!("xxxxzzy.fffff", NOT "xxxxzzzzzzzzyf");
2244        assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
2245        assert_pattern!("xyxyxyzyxyz", "xyxyxyzyxyz");
2246        assert_pattern!("mississippi", "mississippi");
2247        assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
2248        assert_pattern!("m ississippi", "m ississippi");
2249        assert_pattern!("ababac?", NOT "ababac");
2250        assert_pattern!("ababac", NOT "dababac");
2251        assert_pattern!("aaazz", "aaazz");
2252        assert_pattern!("1212", NOT "a12b12");
2253        assert_pattern!("a12b", NOT "a12b12");
2254        assert_pattern!("a12b12", "a12b12");
2255
2256        // A mix of cases
2257        assert_pattern!("n", "n");
2258        assert_pattern!("aabab", "aabab");
2259        assert_pattern!("ar", "ar");
2260        assert_pattern!("aaar", NOT "aar");
2261        assert_pattern!("XYXYXYZYXYz", "XYXYXYZYXYz");
2262        assert_pattern!("missisSIPpi", "missisSIPpi");
2263        assert_pattern!("mississipPI", "mississipPI");
2264        assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
2265        assert_pattern!("miSsissippi", "miSsissippi");
2266        assert_pattern!("miSsisSippi", NOT "miSsissippi");
2267        assert_pattern!("abAbac", "abAbac");
2268        assert_pattern!("abAbac", "abAbac");
2269        assert_pattern!("aAazz", "aAazz");
2270        assert_pattern!("A12b123", NOT "A12b12");
2271        assert_pattern!("a12B12", "a12B12");
2272        assert_pattern!("oWn", "oWn");
2273        assert_pattern!("bLah", "bLah");
2274        assert_pattern!("bLaH", NOT "bLah");
2275
2276        // Single '?' cases.
2277        assert_pattern!("a", "a");
2278        assert_pattern!("a?", "ab");
2279        assert_pattern!("ab?", "abc");
2280
2281        // Mixed '?' cases.
2282        assert_pattern!("??", NOT "a");
2283        assert_pattern!("??", "ab");
2284        assert_pattern!("???", "abc");
2285        assert_pattern!("????", "abcd");
2286        assert_pattern!("????", NOT "abc");
2287        assert_pattern!("?b??", "abcd");
2288        assert_pattern!("?a??", NOT "abcd");
2289        assert_pattern!("??c?", "abcd");
2290        assert_pattern!("??d?", NOT "abcd");
2291        assert_pattern!("?b?d*?", "abcde");
2292
2293        // Longer string scenarios.
2294        assert_pattern!(
2295            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
2296            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
2297        );
2298        assert_pattern!(
2299            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2300            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2301        );
2302        assert_pattern!(
2303            "abababababababababababababababababababaacacacacacacacadaeafagahaiajaxalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2304            NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2305        );
2306        assert_pattern!(
2307            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaggggagaaaaaaaab",
2308            NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2309        );
2310        assert_pattern!(
2311            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2312            "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2313        );
2314        assert_pattern!("aaabbaabbaab", "aaabbaabbaab");
2315        assert_pattern!(
2316            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
2317            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
2318        );
2319        assert_pattern!("aaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaa");
2320        assert_pattern!("aaaaaaaaaaaaaaaaa", NOT "aaaaaaaaaaaaaaaa");
2321        assert_pattern!(
2322            "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc",
2323            NOT "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
2324        );
2325        assert_pattern!(
2326            "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn",
2327            "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
2328        );
2329        assert_pattern!("abcabc?abcabcabc", NOT "abcabcdabcdabcabcd");
2330        assert_pattern!(
2331            "abcabc?abc?abcabc?abc?abc?bc?abc?bc?bcd",
2332            "abcabcdabcdabcabcdabcdabcabcdabcabcabcd"
2333        );
2334        assert_pattern!("?abc?", "?abc?");
2335    }
2336
2337    #[test]
2338    fn test_builder_complexity() {
2339        assert!(
2340            Pattern::builder("{foo,bar}")
2341                .max_complexity(1)
2342                .build()
2343                .is_err()
2344        );
2345        assert!(
2346            Pattern::builder("{foo,bar}")
2347                .max_complexity(2)
2348                .build()
2349                .is_ok()
2350        );
2351        assert!(
2352            Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
2353                .max_complexity(5)
2354                .build()
2355                .is_err()
2356        );
2357        assert!(
2358            Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
2359                .max_complexity(6)
2360                .build()
2361                .is_ok()
2362        );
2363    }
2364
2365    #[test]
2366    fn test_patterns() {
2367        let patterns = patterns!("foobaR", "a*", "*a", "[0-9]*baz");
2368
2369        assert_eq!(patterns.is_match("foobaR", Gas::MAX), Ok(true));
2370        assert_eq!(patterns.is_match("abc", Gas::MAX), Ok(true));
2371        assert_eq!(patterns.is_match("cba", Gas::MAX), Ok(true));
2372        assert_eq!(patterns.is_match("3baz", Gas::MAX), Ok(true));
2373        assert_eq!(patterns.is_match("123456789baz", Gas::MAX), Ok(true));
2374        assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(false));
2375        assert_eq!(patterns.is_match("FOOBAR", Gas::MAX), Ok(false));
2376    }
2377
2378    #[test]
2379    fn test_patterns_case_insensitive() {
2380        let patterns = patterns!("fOObar", "a*", "*a", "[0-9]*baz", @ i);
2381
2382        assert_eq!(patterns.is_match("FooBar", Gas::MAX), Ok(true));
2383        assert_eq!(patterns.is_match("abC", Gas::MAX), Ok(true));
2384        assert_eq!(patterns.is_match("cbA", Gas::MAX), Ok(true));
2385        assert_eq!(patterns.is_match("3BAZ", Gas::MAX), Ok(true));
2386        assert_eq!(patterns.is_match("123456789baz", Gas::MAX), Ok(true));
2387        assert_eq!(patterns.is_match("b", Gas::MAX), Ok(false));
2388    }
2389
2390    #[test]
2391    fn test_patterns_take_clears_builder() {
2392        let mut builder = Patterns::builder().add("foo").unwrap();
2393
2394        let patterns = builder.take();
2395        assert_eq!(patterns, patterns!("foo"));
2396        assert_eq!(patterns.is_match("foo", Gas::MAX), Ok(true));
2397        assert_eq!(patterns.is_match("bar", Gas::MAX), Ok(false));
2398
2399        builder.add("bar").unwrap();
2400        let patterns = builder.build();
2401        assert_eq!(patterns, patterns!("bar"));
2402        assert_eq!(patterns.is_match("foo", Gas::MAX), Ok(false));
2403        assert_eq!(patterns.is_match("bar", Gas::MAX), Ok(true));
2404    }
2405
2406    #[test]
2407    fn test_pattern_eq() {
2408        let pattern1 = pattern!("Foo**", i);
2409        let pattern2 = pattern!("Foo**", i);
2410        let pattern3 = pattern!("foo*", i);
2411        assert_eq!(&pattern1, &pattern1);
2412        assert_eq!(&pattern1, &pattern2);
2413        assert_eq!(&pattern1, &pattern3);
2414        assert_eq!(&pattern2, &pattern3);
2415
2416        let pattern = Pattern::builder("foo*").max_complexity(1).build().unwrap();
2417        assert_eq!(pattern, Pattern::new("foo*").unwrap());
2418    }
2419
2420    #[test]
2421    fn test_pattern_neq() {
2422        assert_ne!(pattern!("Foo**"), pattern!("foo*"));
2423        assert_ne!(pattern!("foo*"), pattern!("foo*", i));
2424        assert_ne!(pattern!("foo*"), pattern!("bar*"));
2425    }
2426
2427    #[test]
2428    fn test_patterns_eq() {
2429        let patterns1 = patterns!("Foo**", "*[rt]X", @ i);
2430        let patterns2 = patterns1.clone();
2431        let patterns3 = patterns!("foo*", "*[rt]x", @ i);
2432        assert_eq!(&patterns1, &patterns1);
2433        assert_eq!(&patterns1, &patterns2);
2434        assert_eq!(&patterns1, &patterns3);
2435        assert_eq!(&patterns2, &patterns3);
2436        assert_eq!(Patterns::empty(), patterns!());
2437    }
2438
2439    #[test]
2440    fn test_patterns_neq() {
2441        let patterns = patterns!("foo*", "bar");
2442        let case_insensitive = patterns!("foo*", "bar", @ i);
2443        let reordered = patterns!("bar", "foo*");
2444        assert_ne!(patterns, case_insensitive);
2445        assert_ne!(patterns, reordered);
2446        assert_ne!(patterns, patterns!("foo*"));
2447        assert_ne!(patterns, patterns!());
2448        assert_ne!(patterns!(), patterns!(@ i));
2449    }
2450
2451    #[test]
2452    #[cfg(feature = "serde")]
2453    fn test_pattern_deserialize() {
2454        let pattern: Pattern = serde_json::from_str(r#""**[rt]x""#).unwrap();
2455        assert_eq!(pattern, Pattern::new("*[rt]x").unwrap());
2456        assert_eq!(pattern.is_match("foobar_rx", Gas::MAX), Ok(true));
2457        assert_eq!(pattern.is_match("foobar_tx", Gas::MAX), Ok(true));
2458        assert_eq!(pattern.is_match("foobar_RX", Gas::MAX), Ok(false));
2459        assert_eq!(pattern.is_match("foobar", Gas::MAX), Ok(false));
2460    }
2461
2462    #[test]
2463    #[cfg(feature = "serde")]
2464    fn test_pattern_deserialize_err() {
2465        for json in [r#""[invalid""#, "null", "true", "42", "[]", "{}"] {
2466            assert!(serde_json::from_str::<Pattern>(json).is_err(), "{json}",);
2467        }
2468    }
2469
2470    #[test]
2471    #[cfg(feature = "serde")]
2472    fn test_pattern_serialize() {
2473        for (source, expected) in [
2474            ("", r#""""#),
2475            ("**", r#""*""#),
2476            ("Foobar", r#""Foobar""#),
2477            ("Foo**", r#""Foo*""#),
2478            ("**Bar", r#""*Bar""#),
2479            ("**Foo**", r#""*Foo*""#),
2480            ("*[rt]x", r#""*[rt]x""#),
2481            (r"f\*o", r#""f\\*o""#),
2482            (r#"f"o"#, r#""f\"o""#),
2483        ] {
2484            let pattern = Pattern::new(source).unwrap();
2485            assert_eq!(serde_json::to_string(&pattern).unwrap(), expected);
2486        }
2487
2488        let pattern = pattern!("Foo**", i);
2489        assert_eq!(serde_json::to_string(&pattern).unwrap(), r#""foo*""#);
2490    }
2491
2492    #[test]
2493    #[cfg(feature = "serde")]
2494    fn test_pattern_serde_roundtrip() {
2495        for source in [
2496            "",
2497            "*",
2498            "Foobar",
2499            "Foo**",
2500            "*Bar",
2501            "*Foo*",
2502            "*[rt]x",
2503            "{foo,bar}",
2504            r"f\*o",
2505            r#"f"o"#,
2506            "Grüße",
2507        ] {
2508            let pattern = Pattern::new(source).unwrap();
2509            let json = serde_json::to_string(&pattern).unwrap();
2510            let deserialized: Pattern = serde_json::from_str(&json).unwrap();
2511            assert_eq!(pattern, deserialized);
2512        }
2513    }
2514
2515    #[test]
2516    #[cfg(feature = "serde")]
2517    fn test_patterns_deserialize() {
2518        let patterns: Patterns = serde_json::from_str(r#"["**[rt]x","Foobar"]"#).unwrap();
2519        let expected = patterns!("*[rt]x", "Foobar");
2520        assert_eq!(patterns, expected);
2521        assert_eq!(patterns.is_match("foobar_rx", Gas::MAX), Ok(true));
2522        assert_eq!(patterns.is_match("Foobar", Gas::MAX), Ok(true));
2523        assert_eq!(patterns.is_match("foobar_RX", Gas::MAX), Ok(false));
2524        assert_eq!(patterns.is_match("FOOBAR", Gas::MAX), Ok(false));
2525    }
2526
2527    #[test]
2528    #[cfg(feature = "serde")]
2529    fn test_patterns_deserialize_err() {
2530        for json in [
2531            r#"["[invalid","foobar"]"#,
2532            r#"["foobar","[invalid"]"#,
2533            r#"["foobar",42]"#,
2534            r#"["foobar",null]"#,
2535            r#"["foobar",[]]"#,
2536            r#""foobar""#,
2537            "null",
2538            "true",
2539            "42",
2540            "{}",
2541        ] {
2542            assert!(serde_json::from_str::<Patterns>(json).is_err());
2543        }
2544    }
2545
2546    #[test]
2547    #[cfg(feature = "serde")]
2548    fn test_patterns_serialize() {
2549        let p = patterns!(
2550            "", "**", "Foobar", "Foo**", "**Bar", "**Foo**", "*[rt]x", r"f\*o",
2551        );
2552        assert_eq!(
2553            serde_json::to_string(&p).unwrap(),
2554            r#"["","*","Foobar","Foo*","*Bar","*Foo*","*[rt]x","f\\*o"]"#,
2555        );
2556
2557        let p = patterns!(
2558            "", "**", "Foobar", "Foo**", "**Bar", "**Foo**", "*[rt]x", r"f\*o", @ i
2559        );
2560        assert_eq!(
2561            serde_json::to_string(&p).unwrap(),
2562            r#"["","*","foobar","foo*","*bar","*foo*","*[rt]x","f\\*o"]"#,
2563        );
2564    }
2565
2566    #[test]
2567    #[cfg(feature = "serde")]
2568    fn test_patterns_serde_empty() {
2569        let patterns: Patterns = serde_json::from_str("[]").unwrap();
2570        assert_eq!(patterns, patterns!());
2571        assert!(patterns.is_empty());
2572        assert_eq!(patterns.is_match("", Gas::MAX), Ok(false));
2573        assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(false));
2574        assert_eq!(serde_json::to_string(&patterns).unwrap(), "[]");
2575    }
2576}