1use std::fmt;
41use std::num::NonZeroUsize;
42
43mod typed;
44mod wildmatch;
45
46pub use typed::*;
47
48#[derive(Debug)]
50pub struct Error {
51 pattern: String,
52 kind: ErrorKind,
53}
54
55#[derive(Debug)]
56enum ErrorKind {
57 InvalidRange(char, char),
60 UnbalancedCharacterClass,
62 InvalidCharacterClass,
64 NestedAlternates,
66 UnbalancedAlternates,
68 DanglingEscape,
70 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#[derive(Debug, Clone)]
104pub struct Pattern {
105 pattern: String,
106 options: Options,
107 strategy: MatchStrategy,
108}
109
110impl Pattern {
111 pub fn new(pattern: &str) -> Result<Self, Error> {
113 Self::builder(pattern).build()
114 }
115
116 pub fn builder(pattern: &str) -> PatternBuilder {
119 PatternBuilder {
120 pattern,
121 options: Options::default(),
122 max_complexity: u64::MAX,
123 }
124 }
125
126 pub fn is_match(&self, haystack: &str) -> bool {
128 self.strategy.is_match(haystack, self.options)
129 }
130}
131
132impl fmt::Display for Pattern {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 f.write_str(&self.pattern)
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct Patterns {
141 strategies: Vec<MatchStrategy>,
142 options: Options,
143}
144
145impl Patterns {
146 pub fn empty() -> Self {
156 Self {
157 strategies: Vec::new(),
158 options: Options::default(),
159 }
160 }
161
162 pub fn builder() -> PatternsBuilder {
164 PatternsBuilder {
165 options: Options::default(),
166 }
167 }
168
169 pub fn is_match(&self, haystack: &str) -> bool {
171 self.strategies
172 .iter()
173 .any(|s| s.is_match(haystack, self.options))
174 }
175
176 pub fn is_empty(&self) -> bool {
180 self.strategies.is_empty()
181 }
182}
183
184#[derive(Debug)]
186pub struct PatternBuilder<'a> {
187 pattern: &'a str,
188 max_complexity: u64,
189 options: Options,
190}
191
192impl PatternBuilder<'_> {
193 pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
197 self.options.case_insensitive = enabled;
198 self
199 }
200
201 pub fn max_complexity(&mut self, max_complexity: u64) -> &mut Self {
208 self.max_complexity = max_complexity;
209 self
210 }
211
212 pub fn build(&self) -> Result<Pattern, Error> {
214 let mut parser = Parser::new(self.pattern, self.options);
215 parser.parse().map_err(|kind| Error {
216 pattern: self.pattern.to_owned(),
217 kind,
218 })?;
219
220 if parser.complexity > self.max_complexity {
221 return Err(Error {
222 pattern: self.pattern.to_owned(),
223 kind: ErrorKind::Complexity {
224 complexity: parser.complexity,
225 max_complexity: self.max_complexity,
226 },
227 });
228 }
229
230 let strategy =
231 MatchStrategy::from_tokens(parser.tokens, self.options).map_err(|kind| Error {
232 pattern: self.pattern.to_owned(),
233 kind,
234 })?;
235
236 Ok(Pattern {
237 pattern: self.pattern.to_owned(),
238 options: self.options,
239 strategy,
240 })
241 }
242}
243
244#[derive(Debug)]
246pub struct PatternsBuilder {
247 options: Options,
248}
249
250impl PatternsBuilder {
251 pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
255 self.options.case_insensitive = enabled;
256 self
257 }
258
259 pub fn patterns(&mut self) -> PatternsBuilderConfigured {
261 PatternsBuilderConfigured {
262 strategies: Vec::new(),
263 options: self.options,
264 }
265 }
266
267 pub fn add(&mut self, pattern: &str) -> Result<PatternsBuilderConfigured, Error> {
269 let mut builder = PatternsBuilderConfigured {
270 strategies: Vec::with_capacity(1),
271 options: self.options,
272 };
273 builder.add(pattern)?;
274 Ok(builder)
275 }
276}
277
278#[derive(Debug)]
282pub struct PatternsBuilderConfigured {
283 strategies: Vec<MatchStrategy>,
284 options: Options,
285}
286
287impl PatternsBuilderConfigured {
288 pub fn add(&mut self, pattern: &str) -> Result<&mut Self, Error> {
290 let mut parser = Parser::new(pattern, self.options);
291 parser.parse().map_err(|kind| Error {
292 pattern: pattern.to_owned(),
293 kind,
294 })?;
295
296 let strategy =
297 MatchStrategy::from_tokens(parser.tokens, self.options).map_err(|kind| Error {
298 pattern: pattern.to_owned(),
299 kind,
300 })?;
301
302 self.strategies.push(strategy);
303
304 Ok(self)
305 }
306
307 pub fn build(self) -> Patterns {
309 Patterns {
310 strategies: self.strategies,
311 options: self.options,
312 }
313 }
314
315 pub fn take(&mut self) -> Patterns {
319 Patterns {
320 strategies: std::mem::take(&mut self.strategies),
321 options: self.options,
322 }
323 }
324}
325
326#[derive(Debug, Clone, Copy, Default)]
328struct Options {
329 case_insensitive: bool,
330}
331
332#[derive(Debug, Clone)]
337enum MatchStrategy {
338 Literal(Literal),
344 Prefix(Literal),
351 Suffix(Literal),
358 Contains(Literal),
365 Static(bool),
369 Wildmatch(Tokens),
371 }
374
375impl MatchStrategy {
376 fn from_tokens(mut tokens: Tokens, _options: Options) -> Result<Self, ErrorKind> {
378 let s = match tokens.as_mut_slice() {
379 [] => Self::Static(false),
380 [Token::Wildcard] => Self::Static(true),
381 [Token::Literal(literal)] => Self::Literal(std::mem::take(literal)),
382 [Token::Literal(literal), Token::Wildcard] => Self::Prefix(std::mem::take(literal)),
383 [Token::Wildcard, Token::Literal(literal)] => Self::Suffix(std::mem::take(literal)),
384 [Token::Wildcard, Token::Literal(literal), Token::Wildcard] => {
385 Self::Contains(std::mem::take(literal))
386 }
387 _ => Self::Wildmatch(tokens),
388 };
389
390 Ok(s)
391 }
392
393 pub fn is_match(&self, haystack: &str, options: Options) -> bool {
395 match &self {
396 MatchStrategy::Literal(literal) => match_literal(literal, haystack, options),
397 MatchStrategy::Prefix(prefix) => match_prefix(prefix, haystack, options),
398 MatchStrategy::Suffix(suffix) => match_suffix(suffix, haystack, options),
399 MatchStrategy::Contains(contains) => match_contains(contains, haystack, options),
400 MatchStrategy::Static(matches) => *matches,
401 MatchStrategy::Wildmatch(tokens) => wildmatch::is_match(haystack, tokens, options),
402 }
403 }
404}
405
406#[inline(always)]
407fn match_literal(literal: &Literal, haystack: &str, options: Options) -> bool {
408 if options.case_insensitive {
409 let mut literal = literal.as_case_converted_str().chars();
412 let mut haystack = haystack.chars().flat_map(|c| c.to_lowercase());
413
414 loop {
415 match (literal.next(), haystack.next()) {
416 (None, None) => break true,
418 (None, _) | (_, None) => break false,
420 (Some(p), Some(h)) if p != h => break false,
421 _ => {}
422 }
423 }
424 } else {
425 literal.as_case_converted_str() == haystack
426 }
427}
428
429#[inline(always)]
430fn match_prefix(prefix: &Literal, haystack: &str, options: Options) -> bool {
431 if options.case_insensitive {
432 let mut prefix = prefix.as_case_converted_str().chars();
433 let mut haystack = haystack.chars().flat_map(|c| c.to_lowercase());
434
435 loop {
436 match (prefix.next(), haystack.next()) {
437 (None, _) => break true,
439 (Some(_), None) => break false,
441 (Some(p), Some(h)) if p != h => break false,
442 _ => {}
443 }
444 }
445 } else {
446 haystack.starts_with(prefix.as_case_converted_str())
447 }
448}
449
450#[inline(always)]
451fn match_suffix(suffix: &Literal, haystack: &str, options: Options) -> bool {
452 if options.case_insensitive {
453 let mut suffix = suffix.as_case_converted_str().chars().rev();
454 let mut haystack = haystack.chars().flat_map(|c| c.to_lowercase()).rev();
455
456 loop {
457 match (suffix.next(), haystack.next()) {
458 (None, _) => break true,
460 (Some(_), None) => break false,
462 (Some(s), Some(h)) if s != h => break false,
463 _ => {}
464 }
465 }
466 } else {
467 haystack.ends_with(suffix.as_case_converted_str())
468 }
469}
470
471#[inline(always)]
472fn match_contains(contains: &Literal, haystack: &str, options: Options) -> bool {
473 if options.case_insensitive {
474 let haystack = haystack.to_lowercase();
475 memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
476 } else {
477 memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
478 }
479}
480
481struct Parser<'a> {
482 chars: std::iter::Peekable<std::str::Chars<'a>>,
483 tokens: Tokens,
484 alternates: Option<Vec<Tokens>>,
485 current_literal: Option<String>,
486 options: Options,
487 complexity: u64,
488}
489
490impl<'a> Parser<'a> {
491 fn new(pattern: &'a str, options: Options) -> Self {
492 Self {
493 chars: pattern.chars().peekable(),
494 tokens: Default::default(),
495 alternates: None,
496 current_literal: None,
497 options,
498 complexity: 0,
499 }
500 }
501
502 fn parse(&mut self) -> Result<(), ErrorKind> {
503 while let Some(c) = self.advance() {
504 match c {
505 '?' => self.push_token(Token::Any(NonZeroUsize::MIN)),
506 '*' => self.push_token(Token::Wildcard),
507 '[' => self.parse_class()?,
508 ']' => return Err(ErrorKind::UnbalancedCharacterClass),
509 '{' => self.start_alternates()?,
510 '}' => self.end_alternates()?,
511 '\\' => match self.advance() {
512 Some(c) => self.push_literal(c),
513 None => return Err(ErrorKind::DanglingEscape),
514 },
515 ',' if self.alternates.is_some() => {
516 self.finish_literal();
517 let alternates = self.alternates.as_mut().unwrap();
519 alternates.push(Tokens::default());
520 }
521 c => self.push_literal(c),
522 }
523 }
524
525 self.finish_literal();
527
528 Ok(())
529 }
530
531 fn start_alternates(&mut self) -> Result<(), ErrorKind> {
532 if self.alternates.is_some() {
533 return Err(ErrorKind::NestedAlternates);
534 }
535 self.finish_literal();
536 self.alternates = Some(vec![Tokens::default()]);
537 Ok(())
538 }
539
540 fn end_alternates(&mut self) -> Result<(), ErrorKind> {
541 self.finish_literal();
542 match self.alternates.take() {
543 None => return Err(ErrorKind::UnbalancedAlternates),
544 Some(alternates) => {
545 if !alternates.is_empty() {
546 self.complexity = self
547 .complexity
548 .max(1)
549 .saturating_mul(alternates.len() as u64);
550 self.push_token(Token::Alternates(alternates));
551 }
552 }
553 }
554
555 Ok(())
556 }
557
558 fn parse_class(&mut self) -> Result<(), ErrorKind> {
559 let negated = self.advance_if(|c| c == '!');
560
561 let mut ranges = Ranges::default();
562
563 let mut first = true;
564 let mut in_range = false;
565 loop {
566 let Some(c) = self.advance() else {
567 return Err(ErrorKind::UnbalancedCharacterClass);
568 };
569
570 match c {
571 '[' => return Err(ErrorKind::InvalidCharacterClass),
573 ']' => break,
574 '-' => {
575 if first {
576 ranges.push(Range::single('-'));
577 } else if in_range {
578 ranges.last_mut().unwrap().set_end('-')?;
581 in_range = false;
582 } else {
583 assert!(!ranges.is_empty());
584 in_range = true;
585 }
586 }
587 c => {
588 let c = match c {
589 '\\' => self.advance().ok_or(ErrorKind::DanglingEscape)?,
590 c => c,
591 };
592
593 if in_range {
594 ranges.last_mut().unwrap().set_end(c)?;
597 in_range = false;
598 } else {
599 ranges.push(Range::single(c))
600 }
601 }
602 }
603
604 first = false;
605 }
606
607 if in_range {
608 ranges.push(Range::single('-'));
610 }
611
612 self.push_token(Token::Class { negated, ranges });
613
614 Ok(())
615 }
616
617 fn push_literal(&mut self, c: char) {
621 self.current_literal.get_or_insert_with(String::new).push(c);
622 }
623
624 fn finish_literal(&mut self) {
626 if let Some(literal) = self.current_literal.take() {
627 self.push_token(Token::Literal(Literal::new(literal, self.options)));
628 }
629 }
630
631 fn push_token(&mut self, token: Token) {
633 self.finish_literal();
634 match self.alternates.as_mut() {
635 Some(alternates) => match alternates.last_mut() {
636 Some(tokens) => tokens.push(token),
637 None => {
638 let mut tokens = Tokens::default();
639 tokens.push(token);
640 alternates.push(tokens);
641 }
642 },
643 None => self.tokens.push(token),
644 }
645 }
646
647 fn advance(&mut self) -> Option<char> {
648 self.chars.next()
649 }
650
651 fn advance_if(&mut self, matcher: impl FnOnce(char) -> bool) -> bool {
652 if self.peek().is_some_and(matcher) {
653 let _ = self.advance();
654 true
655 } else {
656 false
657 }
658 }
659
660 fn peek(&mut self) -> Option<char> {
661 self.chars.peek().copied()
662 }
663}
664
665#[derive(Clone, Debug, Default)]
675struct Tokens(Vec<Token>);
676
677impl Tokens {
678 fn push(&mut self, mut token: Token) {
679 if let Token::Alternates(mut alternates) = token {
681 let mut contains_empty = false;
682 let mut contains_wildcard = false;
683 alternates.retain_mut(|alternate| {
684 if alternate.0.is_empty() {
685 contains_empty = true;
686 return false;
687 }
688
689 if matches!(alternate.0.as_slice(), [Token::Wildcard]) {
690 contains_wildcard = true;
691 }
692
693 true
694 });
695
696 if contains_wildcard {
703 token = Token::Wildcard;
705 } else if alternates.len() == 1 {
706 if contains_empty {
707 token = Token::Optional(alternates.remove(0));
709 } else {
710 for t in alternates.remove(0).0 {
713 self.push(t);
714 }
715 return;
716 }
717 } else if alternates.len() > 1 {
718 if contains_empty {
719 token = Token::Optional(Tokens(vec![Token::Alternates(alternates)]));
721 } else {
722 token = Token::Alternates(alternates);
724 }
725 } else {
726 return;
728 }
729 }
730
731 match (self.0.last_mut(), token) {
732 (Some(Token::Any(n)), Token::Any(n2)) => *n = n.saturating_add(n2.get()),
734 (Some(Token::Wildcard), Token::Wildcard) => {}
737 (Some(Token::Literal(last)), Token::Literal(s)) => last.push(&s),
739 (_, Token::Class { negated: _, ranges }) if ranges.is_empty() => {}
741 (_, token) => self.0.push(token),
743 }
744 }
745
746 fn as_mut_slice(&mut self) -> &mut [Token] {
747 self.0.as_mut_slice()
748 }
749
750 fn as_slice(&self) -> &[Token] {
751 self.0.as_slice()
752 }
753}
754
755#[derive(Clone, Debug)]
757enum Token {
758 Literal(Literal),
760 Any(NonZeroUsize),
762 Wildcard,
764 Class { negated: bool, ranges: Ranges },
766 Alternates(Vec<Tokens>),
768 Optional(Tokens),
774}
775
776#[derive(Clone, Debug, Default)]
782struct Literal(String);
783
784impl Literal {
785 fn new(s: String, options: Options) -> Self {
787 match options.case_insensitive {
788 false => Self(s),
789 true => Self(s.to_lowercase()),
790 }
791 }
792
793 fn push(&mut self, Literal(other): &Literal) {
797 self.0.push_str(other);
798 }
799
800 fn as_case_converted_str(&self) -> &str {
802 &self.0
803 }
804
805 fn as_case_converted_bytes(&self) -> &[u8] {
807 self.as_case_converted_str().as_bytes()
808 }
809}
810
811#[derive(Clone, Debug, Default)]
817enum Ranges {
818 #[default]
822 Empty,
823 Single(Range),
827 Multiple(Vec<Range>),
832}
833
834impl Ranges {
835 fn push(&mut self, range: Range) {
840 match self {
841 Self::Empty => *self = Self::Single(range),
842 Self::Single(single) => *self = Self::Multiple(vec![*single, range]),
843 Self::Multiple(v) => v.push(range),
844 }
845 }
846
847 fn last_mut(&mut self) -> Option<&mut Range> {
849 match self {
850 Ranges::Empty => None,
851 Ranges::Single(range) => Some(range),
852 Ranges::Multiple(ranges) => ranges.last_mut(),
853 }
854 }
855
856 fn is_empty(&self) -> bool {
858 match self {
859 Ranges::Empty => true,
860 Ranges::Single(_) => false,
861 Ranges::Multiple(ranges) => {
862 debug_assert!(!ranges.is_empty());
864 ranges.is_empty()
865 }
866 }
867 }
868
869 #[inline(always)]
871 fn contains(&self, c: char) -> bool {
872 match self {
875 Self::Empty => false,
876 Self::Single(range) => range.contains(c),
877 Self::Multiple(ranges) => ranges.iter().any(|range| range.contains(c)),
878 }
879 }
880}
881
882#[derive(Clone, Copy, Debug)]
884struct Range {
885 start: char,
886 end: char,
887}
888
889impl Range {
890 fn single(c: char) -> Self {
892 Self { start: c, end: c }
893 }
894
895 fn set_end(&mut self, end: char) -> Result<(), ErrorKind> {
900 if self.start > end {
901 return Err(ErrorKind::InvalidRange(self.start, end));
902 }
903 self.end = end;
904 Ok(())
905 }
906
907 #[inline(always)]
909 fn contains(&self, c: char) -> bool {
910 self.start <= c && c <= self.end
911 }
912}
913
914#[cfg(test)]
915mod tests {
916 use super::*;
917
918 macro_rules! assert_pattern {
919 ($pattern:expr, $s:expr $(,$options:tt)?) => {{
920 let mut pattern = Pattern::builder($pattern);
921 for opt in stringify!($($options)?).chars() {
922 match opt {
923 'i' => { pattern.case_insensitive(true); }
924 _ => {}
925 }
926 }
927 let pattern = pattern.build().unwrap();
928 assert!(
929 pattern.is_match($s),
930 "expected pattern '{}' to match '{}' - {pattern:?}",
931 $pattern,
932 $s
933 );
934 }};
935 ($pattern:expr, NOT $s:expr $(,$options:tt)?) => {{
936 let mut pattern = Pattern::builder($pattern);
937 for opt in stringify!($($options)?).chars() {
938 match opt {
939 'i' => { pattern.case_insensitive(true); }
940 _ => {}
941 }
942 }
943 let pattern = pattern.build().unwrap();
944 assert!(
945 !pattern.is_match($s),
946 "expected pattern '{}' to not match '{}' - {pattern:?}",
947 $pattern,
948 $s
949 );
950 }};
951 }
952
953 macro_rules! assert_strategy {
954 ($pattern:expr, $expected:pat) => {{
955 let pattern = Pattern::new($pattern).unwrap();
956 let kind = match &pattern.strategy {
957 MatchStrategy::Literal(_) => "Literal",
958 MatchStrategy::Prefix(_) => "Prefix",
959 MatchStrategy::Suffix(_) => "Suffix",
960 MatchStrategy::Contains(_) => "Contains",
961 MatchStrategy::Static(_) => "Static",
962 MatchStrategy::Wildmatch(_) => "Wildmatch",
963 };
964 assert_eq!(
965 kind,
966 stringify!($expected),
967 "expected pattern '{}' to have strategy '{}' - {pattern:?}",
968 $pattern,
969 stringify!($expected)
970 );
971 }};
972 }
973
974 macro_rules! assert_invalid {
975 ($pattern:expr) => {{
976 if let Ok(pattern) = Pattern::new($pattern) {
977 assert!(
978 false,
979 "expected pattern '{}' to not compile - {pattern:?}",
980 $pattern
981 );
982 }
983 }};
984 }
985
986 #[test]
987 fn test_empty() {
988 assert_pattern!("", NOT "");
989 assert_pattern!("", NOT "foo");
990 }
991
992 #[test]
993 fn test_literal() {
994 assert_pattern!("foo", "foo");
995 assert_pattern!("foo", NOT "fOo");
996 assert_pattern!("foo", NOT "FOO");
997 assert_pattern!(r"f\{\}o", "f{}o");
998 assert_pattern!(r"f\}o", "f}o");
999 assert_pattern!(r"f\{o", "f{o");
1000 assert_pattern!(r"f\{b,a,r\}o", "f{b,a,r}o");
1001 assert_pattern!(r"f\\o", r"f\o");
1002 assert_pattern!("fà¶žo", "fà¶žo");
1003 }
1004
1005 #[test]
1006 fn test_literal_case_insensitive() {
1007 assert_pattern!("foo", "foo", i);
1008 assert_pattern!("foo", "fOo", i);
1009 assert_pattern!("fOo", "Foo", i);
1010 assert_pattern!("İ", "i\u{307}", i);
1011 assert_pattern!("İ", "i̇", i);
1012 }
1013
1014 #[test]
1015 fn test_literal_strategy() {
1016 assert_strategy!("foo", Literal);
1017 assert_strategy!(r"f\{b,a,r\}o", Literal);
1018 assert_strategy!(r"f\\o", Literal);
1019 assert_strategy!("fà¶žo", Literal);
1020 }
1021
1022 #[test]
1023 fn test_prefix() {
1024 assert_pattern!("foo*", "foo___");
1025 assert_pattern!("foo*", "foo");
1026 assert_pattern!("foo**", "foo");
1027 assert_pattern!("foo*?*", NOT "foo");
1028 assert_pattern!("foo*?*", "foo_");
1029 assert_pattern!("foo*?*?", "foo_____");
1030 assert_pattern!("foo*?*?", NOT "foo");
1031 assert_pattern!("foo*?*?", "foo__");
1032 assert_pattern!("foo*?*?", "foo_____");
1033 assert_pattern!("foo**", "foo___");
1034 assert_pattern!("foo*?*", "foo___");
1035 assert_pattern!("foo*?*?", "foo___");
1036 assert_pattern!("foo*", "fooà¶ž");
1037 assert_pattern!("à¶ž*", "à¶žfoo");
1038 assert_pattern!("foo*", NOT "___");
1039 assert_pattern!("foo*", NOT "fo");
1040 assert_pattern!("foo*", NOT "fob");
1041 assert_pattern!("foo*", NOT "boo");
1042 assert_pattern!("foo*", NOT "Foo");
1043 assert_pattern!("foo*", NOT "FOO___");
1044
1045 assert_pattern!("foo/bar*", "foo/bar___");
1047 assert_pattern!("foo*", "foo/bar___");
1048 assert_pattern!("foo*", NOT "/foo");
1049 }
1050
1051 #[test]
1052 fn test_prefix_case_insensitive() {
1053 assert_pattern!("foo*", "foo___", i);
1054 assert_pattern!("foo*", "fOo___", i);
1055 assert_pattern!("foo*", "FOO___", i);
1056 assert_pattern!("fOo*", "FOO___", i);
1057 assert_pattern!("fOo*", "Foo___", i);
1058
1059 assert_pattern!("İ*", "İ___", i);
1060 assert_pattern!("İ*", "İ", i);
1061 assert_pattern!("İ*", "i̇", i);
1062 assert_pattern!("İ*", "i\u{307}___", i);
1063 assert_pattern!("İ*", NOT "i____", i);
1064 }
1065
1066 #[test]
1067 fn test_prefix_strategy() {
1068 assert_strategy!("foo*", Prefix);
1069 assert_strategy!("foo**", Prefix);
1070 assert_strategy!("foo?*", Wildmatch);
1071 }
1072
1073 #[test]
1074 fn test_suffix() {
1075 assert_pattern!("*foo", "___foo");
1076 assert_pattern!("*foo", "foo");
1077 assert_pattern!("**foo", "foo");
1078 assert_pattern!("*?*foo", NOT "foo");
1079 assert_pattern!("*?*foo", "_foo");
1080 assert_pattern!("*?*foo", "_____foo");
1081 assert_pattern!("?*?*foo", NOT "foo");
1082 assert_pattern!("?*?*foo", NOT "_foo");
1083 assert_pattern!("?*?*foo", "__foo");
1084 assert_pattern!("?*?*foo", "_____foo");
1085 assert_pattern!("**foo", "___foo");
1086 assert_pattern!("*?*foo", "___foo");
1087 assert_pattern!("*?*?foo", "__foo");
1088 assert_pattern!("*foo", "à¶žfoo");
1089 assert_pattern!("*à¶ž", "fooà¶ž");
1090 assert_pattern!("*foo", NOT "bar");
1091 assert_pattern!("*foo", NOT "fo");
1092 assert_pattern!("*foo", NOT "fob");
1093 assert_pattern!("*foo", NOT "boo");
1094 assert_pattern!("*foo", NOT "Foo");
1095 assert_pattern!("*foo", NOT "___FOO");
1096
1097 assert_pattern!("*foo/bar", "___foo/bar");
1099 assert_pattern!("*bar", "___foo/bar");
1100 assert_pattern!("*foo", NOT "foo/");
1101 }
1102
1103 #[test]
1104 fn test_suffix_case_insensitive() {
1105 assert_pattern!("foo*", "foo___", i);
1106 assert_pattern!("foo*", "fOo___", i);
1107 assert_pattern!("foo*", "FOO___", i);
1108 assert_pattern!("fOo*", "FOO___", i);
1109 assert_pattern!("fOo*", "Foo___", i);
1110
1111 assert_pattern!("*İ", "___İ", i);
1112 assert_pattern!("*İ", "İ", i);
1113 assert_pattern!("*İ", "i̇", i);
1114 assert_pattern!("*İ", "___i\u{307}", i);
1115 assert_pattern!("*İ", NOT "___i", i);
1116 }
1117
1118 #[test]
1119 fn test_suffix_strategy() {
1120 assert_strategy!("*foo", Suffix);
1121 assert_strategy!("**foo", Suffix);
1122 assert_strategy!("*?foo", Wildmatch);
1123 }
1124
1125 #[test]
1126 fn test_contains() {
1127 assert_pattern!("*foo*", "foo");
1128 assert_pattern!("*foo*", "foo___");
1129 assert_pattern!("*foo*", "___foo");
1130 assert_pattern!("*foo*", "___foo___");
1131 assert_pattern!("*foo*", NOT "___fo");
1132 assert_pattern!("*foo*", NOT "oo___");
1133 assert_pattern!("*foo*", NOT "___fo___");
1134 assert_pattern!("*foo*", NOT "fà¶žo");
1135 assert_pattern!("*foo*", NOT "___fOo___");
1136 assert_pattern!("*foo*", NOT "___FOO___");
1137
1138 assert_pattern!("*foo*", "foo");
1140 assert_pattern!("*foo*", "foo_/_");
1141 assert_pattern!("*foo*", "_/_foo");
1142 assert_pattern!("*foo*", "_/_foo_/_");
1143 assert_pattern!("*f/o*", "_/_f/o_/_");
1144 }
1145
1146 #[test]
1147 fn test_contains_case_insensitive() {
1148 assert_pattern!("*foo*", "foo", i);
1149 assert_pattern!("*foo*", "fOo", i);
1150 assert_pattern!("*fOo*", "Foo", i);
1151 assert_pattern!("*foo*", "___foo___", i);
1152 assert_pattern!("*foo*", "___fOo___", i);
1153 assert_pattern!("*foo*", "___FOO___", i);
1154 assert_pattern!("*fOo*", "___FOO___", i);
1155 assert_pattern!("*fOo*", "___Foo___", i);
1156
1157 assert_pattern!("*İ*", "___İ___", i);
1158 assert_pattern!("*İ*", "İ", i);
1159 assert_pattern!("*İ*", "___İ", i);
1160 assert_pattern!("*İ*", "İ___", i);
1161 assert_pattern!("*İ*", "___İ___", i);
1162 assert_pattern!("*İ*", "i̇", i);
1163 assert_pattern!("*İ*", "___i̇", i);
1164 assert_pattern!("*İ*", "i̇___", i);
1165 assert_pattern!("*İ*", "___i̇___", i);
1166 assert_pattern!("*İ*", "___i\u{307}", i);
1167 assert_pattern!("*İ*", "i\u{307}___", i);
1168 assert_pattern!("*İ*", "___i\u{307}___", i);
1169 assert_pattern!("*İ*", NOT "i", i);
1170 assert_pattern!("*İ*", NOT "i___", i);
1171 assert_pattern!("*İ*", NOT "___i", i);
1172 assert_pattern!("*İ*", NOT "___i___", i);
1173 }
1174
1175 #[test]
1176 fn test_contains_strategy() {
1177 assert_strategy!("*foo*", Contains);
1178 assert_strategy!("**foo**", Contains);
1179 assert_strategy!("*?foo*", Wildmatch);
1180 assert_strategy!("*foo?*", Wildmatch);
1181 assert_strategy!("*foo*?", Wildmatch);
1182 assert_strategy!("?*foo*", Wildmatch);
1183 }
1184
1185 #[test]
1186 fn test_wildcard() {
1187 assert_pattern!("*", "");
1188 assert_pattern!("*", "a");
1189 assert_pattern!("*", "\n");
1190 assert_pattern!("*", "\n\n");
1191 assert_pattern!("*", "\na\n");
1192 assert_pattern!("*", "\na\nb\nc");
1193 assert_pattern!("*", "à¶žfooà¶žfooà¶ž");
1194
1195 assert_pattern!("*", "/");
1197 assert_pattern!("*", "_/");
1198 assert_pattern!("*", "/_");
1199 assert_pattern!("*", "_/_");
1200 assert_pattern!("*", "/?/?/");
1201 }
1202
1203 #[test]
1204 fn test_wildcard_strategy() {
1205 assert_strategy!("*", Static);
1206 assert_strategy!("{*}", Static);
1207 assert_strategy!("{*,}", Static);
1208 assert_strategy!("{foo,*}", Static);
1209 assert_strategy!("{foo,*}?{*,bar}", Wildmatch);
1210 assert_strategy!("{*,}?{*,}", Wildmatch);
1211 }
1212
1213 #[test]
1214 fn test_any() {
1215 assert_pattern!("?", NOT "");
1216 assert_pattern!("?", "à¶ž");
1217 assert_pattern!("?", "?");
1218 assert_pattern!("?", "\n");
1219 assert_pattern!("?", "_");
1220 assert_pattern!("?", NOT "aa");
1221 assert_pattern!("?", NOT "aaaaaaaaaaaaaaaaaa");
1222 assert_pattern!("??", "aa");
1223 assert_pattern!("??", NOT "aaa");
1224 assert_pattern!("a?a?a", "aaaaa");
1225 assert_pattern!("a?a?a", "abaca");
1226 assert_pattern!("a?a?a", NOT "ab_ca");
1227 assert_pattern!("a?a?a", NOT "aaAaa");
1228 assert_pattern!("???????????x???????????", "???????????x???????????");
1229 assert_pattern!("???????????x???????????", "??______???x?????_?????");
1230 assert_pattern!("???????????x???????????", NOT "?______???x?????_?????");
1231 assert_pattern!("???????????x???????????", NOT "??______???_?????_?????");
1232 assert_pattern!(
1233 "??????????????????????????????????????????????????",
1234 "?????????????????????????????????????????????????!"
1235 );
1236 assert_pattern!("foo?bar", "foo?bar");
1237 assert_pattern!("foo?bar", "foo!bar");
1238 assert_pattern!("a??a", "aà¶žà¶ža");
1239
1240 assert_pattern!("?", "/");
1242 }
1243
1244 #[test]
1245 fn test_any_wildcard() {
1246 assert_pattern!("??*", NOT "");
1247 assert_pattern!("??*", NOT "a");
1248 assert_pattern!("??*", "ab");
1249 assert_pattern!("??*", "abc");
1250 assert_pattern!("??*", "abcde");
1251
1252 assert_pattern!("*??", NOT "");
1253 assert_pattern!("*??", NOT "a");
1254 assert_pattern!("*??", "ab");
1255 assert_pattern!("*??", "abc");
1256 assert_pattern!("*??", "abcde");
1257
1258 assert_pattern!("*??*", NOT "");
1259 assert_pattern!("*??*", NOT "a");
1260 assert_pattern!("*??*", "ab");
1261 assert_pattern!("*??*", "abc");
1262 assert_pattern!("*??*", "abcde");
1263
1264 assert_pattern!("*?*?*", NOT "");
1265 assert_pattern!("*?*?*", NOT "a");
1266 assert_pattern!("*?*?*", "ab");
1267 assert_pattern!("*?*?*", "abc");
1268 assert_pattern!("*?*?*", "abcde");
1269 }
1270
1271 #[test]
1272 fn test_escapes() {
1273 assert_pattern!(r"f\\o", r"f\o");
1274 assert_pattern!(r"f\*o", r"f*o");
1275 assert_pattern!(r"f\*o", NOT r"f\*o");
1276 assert_pattern!(r"f\\*o", r"f\*o");
1277 assert_pattern!(r"f\\*o", r"f\o");
1278 assert_pattern!(r"f\\*o", r"f\___o");
1279 assert_pattern!(r"f\\\*o", r"f\*o");
1280 assert_pattern!(r"f\[\]o", r"f[]o");
1281 assert_pattern!(r"f\[?\]o", r"f[?]o");
1282 assert_pattern!(r"f\[a-z\]o", r"f[a-z]o");
1283 assert_pattern!(r"f\[o", r"f[o");
1284 assert_pattern!(r"f\]o", r"f]o");
1285 assert_pattern!(r"\[", r"[");
1286 }
1287
1288 #[test]
1289 fn test_invalid() {
1290 assert_invalid!(r"\");
1291 assert_invalid!(r"f\");
1292 assert_invalid!(r"*\");
1293 assert_invalid!("[");
1294 assert_invalid!("[a-z");
1295 assert_invalid!(r"[a-z\");
1296 assert_invalid!("[[]");
1297 assert_invalid!("[]]");
1298 assert_invalid!("]");
1299 assert_invalid!("[a-z");
1300 assert_invalid!("[b-a]");
1301 assert_invalid!("[a-A]");
1302 }
1303
1304 #[test]
1305 fn test_classes() {
1306 assert_pattern!("[]", NOT "");
1307 assert_pattern!("[]", NOT "_");
1308 assert_pattern!("[a]", "a");
1309 assert_pattern!("[a]", NOT "[a]");
1310 assert_pattern!("[a]", NOT "b");
1311 assert_pattern!("[a]", NOT "A");
1312 assert_pattern!("[à¶ž]", "à¶ž");
1313 assert_pattern!("[à¶ž]", NOT "a");
1314 assert_pattern!("[à¶ža]", "a");
1315 assert_pattern!("[aà¶ž]", "à¶ž");
1316 assert_pattern!("[à¶ža]", NOT "b");
1317 assert_pattern!("[ab]", "a");
1318 assert_pattern!("[ab]", "b");
1319 assert_pattern!("[ab]", NOT "c");
1320 assert_pattern!("x[ab]x", "xax");
1321 assert_pattern!("x[ab]x", "xbx");
1322 assert_pattern!("x[ab]x", NOT "xBx");
1323 assert_pattern!("x[ab]x", NOT "xcx");
1324 assert_pattern!("x[ab]x", NOT "aax");
1325 assert_pattern!("x[ab]x", NOT "xaa");
1326 assert_pattern!("x[ab]x", NOT "xaax");
1327 assert_pattern!("x[ab]x", NOT "xxax");
1328 assert_pattern!("x[ab]x", NOT "xaxx");
1329 assert_pattern!("[a-b]", "a");
1330 assert_pattern!("[a-b]", "b");
1331 assert_pattern!("[a-b]", NOT "c");
1332 assert_pattern!("[a-c]", "a");
1333 assert_pattern!("[a-c]", "b");
1334 assert_pattern!("[a-c]", "c");
1335 assert_pattern!("[a-c]", NOT "d");
1336 assert_pattern!("[a-c]", NOT "1");
1337 assert_pattern!("[a-c]", NOT "à¶ž");
1338 assert_pattern!("[A-z]", "a");
1339 assert_pattern!("[A-z]", "z");
1340 assert_pattern!("[A-z]", "["); assert_pattern!("[A-z]", "A");
1342 assert_pattern!("[A-z]", "Z");
1343 assert_pattern!("[A-z]", NOT "0");
1344 assert_pattern!("[0-9]", "0");
1345 assert_pattern!("[0-9]", "1");
1346 assert_pattern!("[0-9]", "2");
1347 assert_pattern!("[0-9]", "3");
1348 assert_pattern!("[0-9]", "4");
1349 assert_pattern!("[0-9]", "5");
1350 assert_pattern!("[0-9]", "6");
1351 assert_pattern!("[0-9]", "7");
1352 assert_pattern!("[0-9]", "8");
1353 assert_pattern!("[0-9]", "9");
1354 assert_pattern!(
1355 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1356 "3bYf"
1357 );
1358 assert_pattern!(
1359 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1360 NOT "3cYf"
1361 );
1362 assert_pattern!(
1363 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1364 NOT "3à¶žYf"
1365 );
1366 assert_pattern!("[0-9]", NOT "a9");
1367 assert_pattern!("[0-9]", NOT "9a");
1368 assert_pattern!("[0-9]", NOT "a9a");
1369 assert_pattern!("[0-9]", NOT "");
1370 assert_pattern!("[0-9!]", "!");
1371 assert_pattern!("[0-9][a-b]", NOT "");
1372 assert_pattern!("[0-9][a-b]", NOT "a");
1373 assert_pattern!("[0-9][a-b]", NOT "a0");
1374 assert_pattern!("[0-9][a-b]", "0a");
1375 assert_pattern!(r"a[\]a\-]b", "aab");
1376
1377 assert_pattern!(r"[\\]", r"\");
1385 assert_pattern!(r"[\\]", NOT "a");
1386 assert_pattern!(r"[\]]", "]");
1387 assert_pattern!(r"[\]]", NOT "a");
1388 assert_pattern!(r"[\[]", "[");
1389 assert_pattern!(r"[\[]", NOT "a");
1390 assert_pattern!(r"[\]]", NOT r"\");
1391
1392 assert_pattern!("a[X-]b", "a-b");
1393 assert_pattern!("a[X-]b", "aXb");
1394 }
1395
1396 #[test]
1397 fn test_classes_case_insensitive() {
1398 assert_pattern!("[a]", "a", i);
1399 assert_pattern!("[a]", "A", i);
1400 assert_pattern!("x[ab]x", "xAX", i);
1401 assert_pattern!("x[ab]x", "XBx", i);
1402 assert_pattern!("x[ab]x", NOT "Xcx", i);
1403 assert_pattern!("x[ab]x", NOT "aAx", i);
1404 assert_pattern!("x[ab]x", NOT "xAa", i);
1405 assert_pattern!("[ǧ]", "Ǧ", i);
1406 assert_pattern!("[Ǧ]", "ǧ", i);
1407 }
1408
1409 #[test]
1410 fn test_classes_negated() {
1411 assert_pattern!("[!]", NOT "");
1412 assert_pattern!("[!a]", "b");
1413 assert_pattern!("[!a]", "A");
1414 assert_pattern!("[!a]", "B");
1415 assert_pattern!("[!b]", NOT "b");
1416 assert_pattern!("[!ab]", NOT "a");
1417 assert_pattern!("[!ab]", NOT "b");
1418 assert_pattern!("[!ab]", "c");
1419 assert_pattern!("x[!ab]x", "xcx");
1420 assert_pattern!("x[!ab]x", NOT "xax");
1421 assert_pattern!("x[!ab]x", NOT "xbx");
1422 assert_pattern!("x[!ab]x", NOT "xxcx");
1423 assert_pattern!("x[!ab]x", NOT "xcxx");
1424 assert_pattern!("x[!ab]x", NOT "xc");
1425 assert_pattern!("x[!ab]x", NOT "cx");
1426 assert_pattern!("x[!ab]x", NOT "x");
1427 assert_pattern!("[!a-c]", NOT "a");
1428 assert_pattern!("[!a-c]", NOT "b");
1429 assert_pattern!("[!a-c]", NOT "c");
1430 assert_pattern!("[!a-c]", "d");
1431 assert_pattern!("[!a-c]", "A");
1432 assert_pattern!("[!a-c]", "à¶ž");
1433 assert_pattern!(r"[!a-c\\]", "d");
1434 assert_pattern!(r"[!a-c\\]", NOT r"\");
1435 assert_pattern!(r"[!\]]", "a");
1436 assert_pattern!(r"[!\]]", NOT "]");
1437 assert_pattern!(r"[!!]", "a");
1438 assert_pattern!(r"[!!]", NOT "!");
1439 }
1440
1441 #[test]
1442 fn test_classes_negated_case_insensitive() {
1443 assert_pattern!("[!a]", "b", i);
1444 assert_pattern!("[!a]", "B", i);
1445 assert_pattern!("[!b]", NOT "b", i);
1446 assert_pattern!("[!b]", NOT "B", i);
1447 assert_pattern!("[!ab]", NOT "a", i);
1448 assert_pattern!("[!ab]", NOT "A", i);
1449 assert_pattern!("[!ab]", NOT "b", i);
1450 assert_pattern!("[!ab]", NOT "B", i);
1451 assert_pattern!("[!ab]", "c", i);
1452 assert_pattern!("[!ab]", "C", i);
1453 }
1454
1455 #[test]
1456 fn test_alternates() {
1457 assert_pattern!("{}foo{}", "foo");
1458 assert_pattern!("foo{}bar", "foobar");
1459 assert_pattern!("foo{}{}bar", "foobar");
1460 assert_pattern!("{foo}", "foo");
1461 assert_pattern!("{foo}", NOT "fOo");
1462 assert_pattern!("{foo}", NOT "bar");
1463 assert_pattern!("{foo,bar}", "foo");
1464 assert_pattern!("{foo,bar}", "bar");
1465 assert_pattern!("{foo,bar}", NOT "Foo");
1466 assert_pattern!("{foo,bar}", NOT "fOo");
1467 assert_pattern!("{foo,bar}", NOT "BAR");
1468 assert_pattern!("{foo,bar}", NOT "fooo");
1469 assert_pattern!("{foo,bar}", NOT "baar");
1470 assert_pattern!("{foo,bar,}baz", "foobaz");
1471 assert_pattern!("{foo,bar,}baz", "barbaz");
1472 assert_pattern!("{foo,bar,}baz", "baz");
1473 assert_pattern!("{foo,,bar}baz", "foobaz");
1474 assert_pattern!("{foo,,bar}baz", "barbaz");
1475 assert_pattern!("{foo,,bar}baz", "baz");
1476 assert_pattern!("{,foo,bar}baz", "foobaz");
1477 assert_pattern!("{,foo,bar}baz", "barbaz");
1478 assert_pattern!("{,foo,bar}baz", "baz");
1479 assert_pattern!("{foo*bar}", "foobar");
1480 assert_pattern!("{foo*bar}", "fooooobar");
1481 assert_pattern!("{foo*bar}", NOT "");
1482 assert_pattern!("{foo*bar,}", "foobar");
1483 assert_pattern!("{foo*bar,}", "fooooobar");
1484 assert_pattern!("{foo*bar,}", "");
1485 assert_pattern!("{foo*bar,baz}", "foobar");
1486 assert_pattern!("{foo*bar,baz}", "fooooobar");
1487 assert_pattern!("{foo*bar,baz}", "baz");
1488 assert_pattern!("{foo*bar,baz}", NOT "");
1489 assert_pattern!("{foo*bar,baz,}", "foobar");
1490 assert_pattern!("{foo*bar,baz,}", "fooooobar");
1491 assert_pattern!("{foo*bar,baz,}", "baz");
1492 assert_pattern!("{foo*bar,baz,}", "");
1493 assert_pattern!("{,,,,}", NOT "");
1494 assert_pattern!("{[fb][oa][or]}", "foo");
1495 assert_pattern!("{[fb][oa][or]}", "bar");
1496 assert_pattern!("{[fb][oa][or],baz}", "foo");
1497 assert_pattern!("{[fb][oa][or],baz}", "bar");
1498 assert_pattern!("{[fb][oa][or],baz}", "baz");
1499 assert_pattern!("{baz,[fb][oa][or]}", "baz");
1500 assert_pattern!("{baz,[fb][oa][or]}", "foo");
1501 assert_pattern!("{baz,[fb][oa][or]}", "bar");
1502 assert_pattern!("{baz,[fb][oa][or]}", "bor");
1503 assert_pattern!("{baz,[fb][oa][or]}", NOT "barr");
1504 assert_pattern!("{baz,[fb][oa][or]}", NOT "boz");
1505 assert_pattern!("{baz,[fb][oa][or]}", NOT "fbar");
1506 assert_pattern!("{baz,[fb][oa][or]}", NOT "bAr");
1507 assert_pattern!("{baz,[fb][oa][or]}", NOT "Foo");
1508 assert_pattern!("{baz,[fb][oa][or]}", NOT "Bar");
1509 assert_pattern!("{baz,b[aA]r}", NOT "bAz");
1510 assert_pattern!("{baz,b[!aA]r}", NOT "bar");
1511 assert_pattern!("{baz,b[!aA]r}", "bXr");
1512 assert_pattern!("{[a-z],[0-9]}", "a");
1513 assert_pattern!("{[a-z],[0-9]}", "3");
1514 assert_pattern!("a{[a-z],[0-9]}a", "a3a");
1515 assert_pattern!("a{[a-z],[0-9]}a", "aba");
1516 assert_pattern!("a{[a-z],[0-9]}a", NOT "aAa");
1517 assert_pattern!("a{[a-z],?}a", "aXa");
1518 assert_pattern!(r"a{[a-z],\?}a", "a?a");
1519 assert_pattern!(r"a{[a-z],\?}a", NOT "aXa");
1520 assert_pattern!(r"a{[a-z],\?}a", NOT r"a\a");
1521 assert_pattern!(r"a{\[\],\{\}}a", "a[]a");
1522 assert_pattern!(r"a{\[\],\{\}}a", "a{}a");
1523 assert_pattern!(r"a{\[\],\{\}}a", NOT "a[}a");
1524 assert_pattern!(r"a{\[\],\{\}}a", NOT "a{]a");
1525 assert_pattern!(r"a{\[\],\{\}}a", NOT "a[a");
1526 assert_pattern!(r"a{\[\],\{\}}a", NOT "a]a");
1527 assert_pattern!(r"a{\[\],\{\}}a", NOT "a{a");
1528 assert_pattern!(r"a{\[\],\{\}}a", NOT "a}a");
1529 assert_pattern!("foo/{*.js,*.html}", "foo/.js");
1530 assert_pattern!("foo/{*.js,*.html}", "foo/.html");
1531 assert_pattern!("foo/{*.js,*.html}", "foo/bar.js");
1532 assert_pattern!("foo/{*.js,*.html}", "foo/bar.html");
1533 assert_pattern!("foo/{*.js,*.html}", NOT "foo/bar.png");
1534 assert_pattern!("foo/{*.js,*.html}", NOT "bar/bar.js");
1535 assert_pattern!("{foo,abc}{def,bar}", "foodef");
1536 assert_pattern!("{foo,abc}{def,bar}", "foobar");
1537 assert_pattern!("{foo,abc}{def,bar}", "abcdef");
1538 assert_pattern!("{foo,abc}{def,bar}", "abcbar");
1539 assert_pattern!("{foo,abc}{def,bar}", NOT "foofoo");
1540 assert_pattern!("{foo,abc}{def,bar}", NOT "fooabc");
1541 assert_pattern!("{foo,abc}{def,bar}", NOT "defdef");
1542 assert_pattern!("{foo,abc}{def,bar}", NOT "defabc");
1543 }
1544
1545 #[test]
1546 fn test_alternate_strategy() {
1547 assert_strategy!("{}foo{}", Literal);
1549 assert_strategy!("foo{}bar", Literal);
1550 assert_strategy!("foo{}{}{}bar", Literal);
1551 assert_strategy!("foo{,,,}bar", Literal);
1552 }
1553
1554 #[test]
1555 fn test_alternates_case_insensitive() {
1556 assert_pattern!("{foo}", "foo", i);
1557 assert_pattern!("{foo}", "fOo", i);
1558 assert_pattern!("{foo}", NOT "bar", i);
1559 assert_pattern!("{foo,bar}", "foo", i);
1560 assert_pattern!("{foo,bar}", "bar", i);
1561 assert_pattern!("{foo,bar}", "Foo", i);
1562 assert_pattern!("{foo,bar}", "fOo", i);
1563 assert_pattern!("{foo,bar}", "BAR", i);
1564 assert_pattern!("{foo,bar}", NOT "bao", i);
1565 assert_pattern!("{f[o0-9]o,b[a]r}", "foo", i);
1566 assert_pattern!("{f[o0-9]o,b[a]r}", "fOo", i);
1567 assert_pattern!("{f[o0-9]o,b[a]r}", "f1o", i);
1568 assert_pattern!("{f[o0-9]o,b[a]r}", "foO", i);
1569 assert_pattern!("{f[o0-9]o,b[a]r}", "FOO", i);
1570 assert_pattern!("{f[o0-9]o,b[a]r}", "bar", i);
1571 assert_pattern!("{f[o0-9]o,b[a]r}", "bAr", i);
1572 assert_pattern!("{f[o0-9]o,b[a]r}", "baR", i);
1573 assert_pattern!("{f[o0-9]o,b[a]r}", "BAR", i);
1574 assert_pattern!("{f[o0-9]o,b[!a]r}", "foo", i);
1575 assert_pattern!("{f[o0-9]o,b[!a]r}", "bXr", i);
1576 assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bar", i);
1577 assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bAr", i);
1578 }
1579
1580 #[test]
1581 fn test_complex() {
1582 assert_pattern!("*?", "\n");
1583 assert_pattern!("?*", "\n");
1584 assert_pattern!("*?*", "\n");
1585 assert_pattern!("1.18.[!0-4].*", "1.18.5.");
1586 assert_pattern!("1.18.[!0-4].*", "1.18.5.aBc");
1587 assert_pattern!("1.18.[!0-4].*", NOT "1.18.3.abc");
1588 assert_pattern!("!*!*.md", "!foo!.md"); assert_pattern!("foo*foofoo*foobar", "foofoofooxfoofoobar");
1590 assert_pattern!("foo*fooFOO*fOobar", "fooFoofooXfoofooBAR", i);
1591 assert_pattern!("[0-9]*a", "0aaaaaaaaa", i);
1592 assert_pattern!("[0-9]*Bar[x]", "0foobarx", i);
1593
1594 assert_pattern!(
1595 r"/api/0/organizations/\{organization_slug\}/event*",
1596 "/api/0/organizations/{organization_slug}/event/foobar"
1597 );
1598 assert_pattern!(
1599 r"/api/0/organizations/\{organization_slug\}/event*",
1600 NOT r"/api/0/organizations/\{organization_slug\}/event/foobar"
1601 );
1602
1603 assert_pattern!(
1604 "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
1605 "foobarwithacrazylongprefixandanditactuallymatches"
1606 );
1607 assert_pattern!(
1608 "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
1609 "FOOBARWITHACRAZYLONGPREFIXANDANDITACTUALLYMATCHES",
1610 i
1611 );
1612 }
1613
1614 #[test]
1618 fn test_kirk_j_krauss() {
1619 assert_pattern!("Hi*", "Hi");
1621
1622 assert_pattern!("ab*d", NOT "abc");
1624
1625 assert_pattern!("*ccd", "abcccd");
1627 assert_pattern!("*issip*ss*", "mississipissippi");
1628 assert_pattern!("xxxx*zzy*fffff", NOT "xxxx*zzzzzzzzy*f");
1629 assert_pattern!("xxx*zzy*f", "xxxx*zzzzzzzzy*f");
1630 assert_pattern!("xxxx*zzy*fffff", NOT "xxxxzzzzzzzzyf");
1631 assert_pattern!("xxxx*zzy*f", "xxxxzzzzzzzzyf");
1632 assert_pattern!("xy*z*xyz", "xyxyxyzyxyz");
1633 assert_pattern!("*sip*", "mississippi");
1634 assert_pattern!("xy*xyz", "xyxyxyxyz");
1635 assert_pattern!("mi*sip*", "mississippi");
1636 assert_pattern!("*abac*", "ababac");
1637 assert_pattern!("*abac*", "ababac");
1638 assert_pattern!("a*zz*", "aaazz");
1639 assert_pattern!("*12*23", NOT "a12b12");
1640 assert_pattern!("a12b", NOT "a12b12");
1641 assert_pattern!("*12*12*", "a12b12");
1642
1643 assert_pattern!("*a?b", "caaab");
1645
1646 assert_pattern!("*", "*");
1648 assert_pattern!("a*b", "a*abab");
1649 assert_pattern!("a*", "a*r");
1650 assert_pattern!("a*aar", NOT "a*ar");
1651
1652 assert_pattern!("XY*Z*XYz", "XYXYXYZYXYz");
1654 assert_pattern!("*SIP*", "missisSIPpi");
1655 assert_pattern!("*issip*PI", "mississipPI");
1656 assert_pattern!("xy*xyz", "xyxyxyxyz");
1657 assert_pattern!("mi*sip*", "miSsissippi");
1658 assert_pattern!("mi*Sip*", NOT "miSsissippi");
1659 assert_pattern!("*Abac*", "abAbac");
1660 assert_pattern!("*Abac*", "abAbac");
1661 assert_pattern!("a*zz*", "aAazz");
1662 assert_pattern!("*12*23", NOT "A12b12");
1663 assert_pattern!("*12*12*", "a12B12");
1664 assert_pattern!("*oWn*", "oWn");
1665
1666 assert_pattern!("bLah", "bLah");
1668 assert_pattern!("bLaH", NOT "bLah");
1669
1670 assert_pattern!("*?", "a");
1672 assert_pattern!("*?", "ab");
1673 assert_pattern!("*?", "abc");
1674
1675 assert_pattern!("??", NOT "a");
1677 assert_pattern!("?*?", "ab");
1678 assert_pattern!("*?*?*", "ab");
1679 assert_pattern!("?**?*?", "abc");
1680 assert_pattern!("?**?*&?", NOT "abc");
1681 assert_pattern!("?b*??", "abcd");
1682 assert_pattern!("?a*??", NOT "abcd");
1683 assert_pattern!("?**?c?", "abcd");
1684 assert_pattern!("?**?d?", NOT "abcd");
1685 assert_pattern!("?*b*?*d*?", "abcde");
1686
1687 assert_pattern!("bL?h", "bLah");
1689 assert_pattern!("bLa?", NOT "bLaaa");
1690 assert_pattern!("bLa?", "bLah");
1691 assert_pattern!("?Lah", NOT "bLaH");
1692 assert_pattern!("?LaH", "bLaH");
1693
1694 assert_pattern!(
1696 "a*a*a*a*a*a*aa*aaa*a*a*b",
1697 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
1698 );
1699 assert_pattern!(
1700 "*a*b*ba*ca*a*aa*aaa*fa*ga*b*",
1701 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1702 );
1703 assert_pattern!(
1704 "*a*b*ba*ca*a*x*aaa*fa*ga*b*",
1705 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1706 );
1707 assert_pattern!(
1708 "*a*b*ba*ca*aaaa*fa*ga*gggg*b*",
1709 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1710 );
1711 assert_pattern!(
1712 "*a*b*ba*ca*aaaa*fa*ga*ggg*b*",
1713 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1714 );
1715 assert_pattern!("*aabbaa*a*", "aaabbaabbaab");
1716 assert_pattern!(
1717 "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
1718 "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*"
1719 );
1720 assert_pattern!("*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaaaaaaaa");
1721 assert_pattern!(
1722 "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
1723 NOT "aaaaaaaaaaaaaaaa"
1724 );
1725 assert_pattern!(
1726 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
1727 NOT "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
1728 );
1729 assert_pattern!(
1730 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
1731 "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
1732 );
1733 assert_pattern!("abc*abc*abc*abc*abc", NOT "abc*abcd*abcd*abc*abcd");
1734 assert_pattern!(
1735 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",
1736 "abc*abcd*abcd*abc*abcd*abcd*abc*abcd*abc*abc*abcd"
1737 );
1738 assert_pattern!("********a********b********c********", "abc");
1739 assert_pattern!("abc", NOT "********a********b********c********");
1740 assert_pattern!("********a********b********b********", NOT "abc");
1741 assert_pattern!("***a*b*c***", "*abc*");
1742
1743 assert_pattern!("*issip*PI", "mississippi", i);
1745
1746 assert_pattern!("?", NOT "");
1748 assert_pattern!("*?", NOT "");
1749 assert_pattern!("", NOT "a");
1751
1752 assert_pattern!("abd", NOT "abc");
1754
1755 assert_pattern!("abcccd", "abcccd");
1757 assert_pattern!("mississipissippi", "mississipissippi");
1758 assert_pattern!("xxxxzzzzzzzzyfffff", NOT "xxxxzzzzzzzzyf");
1759 assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
1760 assert_pattern!("xxxxzzy.fffff", NOT "xxxxzzzzzzzzyf");
1761 assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
1762 assert_pattern!("xyxyxyzyxyz", "xyxyxyzyxyz");
1763 assert_pattern!("mississippi", "mississippi");
1764 assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
1765 assert_pattern!("m ississippi", "m ississippi");
1766 assert_pattern!("ababac?", NOT "ababac");
1767 assert_pattern!("ababac", NOT "dababac");
1768 assert_pattern!("aaazz", "aaazz");
1769 assert_pattern!("1212", NOT "a12b12");
1770 assert_pattern!("a12b", NOT "a12b12");
1771 assert_pattern!("a12b12", "a12b12");
1772
1773 assert_pattern!("n", "n");
1775 assert_pattern!("aabab", "aabab");
1776 assert_pattern!("ar", "ar");
1777 assert_pattern!("aaar", NOT "aar");
1778 assert_pattern!("XYXYXYZYXYz", "XYXYXYZYXYz");
1779 assert_pattern!("missisSIPpi", "missisSIPpi");
1780 assert_pattern!("mississipPI", "mississipPI");
1781 assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
1782 assert_pattern!("miSsissippi", "miSsissippi");
1783 assert_pattern!("miSsisSippi", NOT "miSsissippi");
1784 assert_pattern!("abAbac", "abAbac");
1785 assert_pattern!("abAbac", "abAbac");
1786 assert_pattern!("aAazz", "aAazz");
1787 assert_pattern!("A12b123", NOT "A12b12");
1788 assert_pattern!("a12B12", "a12B12");
1789 assert_pattern!("oWn", "oWn");
1790 assert_pattern!("bLah", "bLah");
1791 assert_pattern!("bLaH", NOT "bLah");
1792
1793 assert_pattern!("a", "a");
1795 assert_pattern!("a?", "ab");
1796 assert_pattern!("ab?", "abc");
1797
1798 assert_pattern!("??", NOT "a");
1800 assert_pattern!("??", "ab");
1801 assert_pattern!("???", "abc");
1802 assert_pattern!("????", "abcd");
1803 assert_pattern!("????", NOT "abc");
1804 assert_pattern!("?b??", "abcd");
1805 assert_pattern!("?a??", NOT "abcd");
1806 assert_pattern!("??c?", "abcd");
1807 assert_pattern!("??d?", NOT "abcd");
1808 assert_pattern!("?b?d*?", "abcde");
1809
1810 assert_pattern!(
1812 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
1813 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
1814 );
1815 assert_pattern!(
1816 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
1817 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1818 );
1819 assert_pattern!(
1820 "abababababababababababababababababababaacacacacacacacadaeafagahaiajaxalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
1821 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1822 );
1823 assert_pattern!(
1824 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaggggagaaaaaaaab",
1825 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1826 );
1827 assert_pattern!(
1828 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
1829 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
1830 );
1831 assert_pattern!("aaabbaabbaab", "aaabbaabbaab");
1832 assert_pattern!(
1833 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1834 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
1835 );
1836 assert_pattern!("aaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaa");
1837 assert_pattern!("aaaaaaaaaaaaaaaaa", NOT "aaaaaaaaaaaaaaaa");
1838 assert_pattern!(
1839 "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc",
1840 NOT "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
1841 );
1842 assert_pattern!(
1843 "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn",
1844 "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
1845 );
1846 assert_pattern!("abcabc?abcabcabc", NOT "abcabcdabcdabcabcd");
1847 assert_pattern!(
1848 "abcabc?abc?abcabc?abc?abc?bc?abc?bc?bcd",
1849 "abcabcdabcdabcabcdabcdabcabcdabcabcabcd"
1850 );
1851 assert_pattern!("?abc?", "?abc?");
1852 }
1853
1854 #[test]
1855 fn test_builder_complexity() {
1856 assert!(
1857 Pattern::builder("{foo,bar}")
1858 .max_complexity(1)
1859 .build()
1860 .is_err()
1861 );
1862 assert!(
1863 Pattern::builder("{foo,bar}")
1864 .max_complexity(2)
1865 .build()
1866 .is_ok()
1867 );
1868 assert!(
1869 Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
1870 .max_complexity(5)
1871 .build()
1872 .is_err()
1873 );
1874 assert!(
1875 Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
1876 .max_complexity(6)
1877 .build()
1878 .is_ok()
1879 );
1880 }
1881
1882 #[test]
1883 fn test_patterns() {
1884 let patterns = Patterns::builder()
1885 .add("foobaR")
1886 .unwrap()
1887 .add("a*")
1888 .unwrap()
1889 .add("*a")
1890 .unwrap()
1891 .add("[0-9]*baz")
1892 .unwrap()
1893 .take();
1894
1895 assert!(patterns.is_match("foobaR"));
1896 assert!(patterns.is_match("abc"));
1897 assert!(patterns.is_match("cba"));
1898 assert!(patterns.is_match("3baz"));
1899 assert!(patterns.is_match("123456789baz"));
1900 assert!(!patterns.is_match("foobar"));
1901 assert!(!patterns.is_match("FOOBAR"));
1902 }
1903
1904 #[test]
1905 fn test_patterns_case_insensitive() {
1906 let patterns = Patterns::builder()
1907 .case_insensitive(true)
1908 .add("fOObar")
1909 .unwrap()
1910 .add("a*")
1911 .unwrap()
1912 .add("*a")
1913 .unwrap()
1914 .add("[0-9]*baz")
1915 .unwrap()
1916 .take();
1917
1918 assert!(patterns.is_match("FooBar"));
1919 assert!(patterns.is_match("abC"));
1920 assert!(patterns.is_match("cbA"));
1921 assert!(patterns.is_match("3BAZ"));
1922 assert!(patterns.is_match("123456789baz"));
1923 assert!(!patterns.is_match("b"));
1924 }
1925
1926 #[test]
1927 fn test_patterns_take_clears_builder() {
1928 let mut builder = Patterns::builder().add("foo").unwrap();
1929
1930 let patterns = builder.take();
1931 assert!(patterns.is_match("foo"));
1932 assert!(!patterns.is_match("bar"));
1933
1934 builder.add("bar").unwrap();
1935 let patterns = builder.build();
1936 assert!(!patterns.is_match("foo"));
1937 assert!(patterns.is_match("bar"));
1938 }
1939}