1use regex::Regex;
2
3macro_rules! regex {
4 ($pattern:expr) => {
5 regex::Regex::new($pattern).unwrap()
6 };
7}
8
9#[test]
10fn unclosed_group_error() {
11 let err = Regex::new(r"(").unwrap_err();
12 let msg = err.to_string();
13 assert!(msg.contains("unclosed group"), "error message: {:?}", msg);
14}
15
16#[test]
17fn regex_string() {
18 assert_eq!(r"[a-zA-Z0-9]+", regex!(r"[a-zA-Z0-9]+").as_str());
19 assert_eq!(r"[a-zA-Z0-9]+", &format!("{}", regex!(r"[a-zA-Z0-9]+")));
20 assert_eq!(
21 r#"Regex("[a-zA-Z0-9]+")"#,
22 &format!("{:?}", regex!(r"[a-zA-Z0-9]+"))
23 );
24}
25
26#[test]
27fn capture_names() {
28 let re = regex!(r"(.)(?P<a>.)");
29 assert_eq!(3, re.captures_len());
30 assert_eq!((3, Some(3)), re.capture_names().size_hint());
31 assert_eq!(
32 vec![None, None, Some("a")],
33 re.capture_names().collect::<Vec<_>>()
34 );
35}
36
37#[test]
38fn capture_index() {
39 let re = regex!(r"^(?P<name>.+)$");
40 let cap = re.captures("abc").unwrap();
41 assert_eq!(&cap[0], "abc");
42 assert_eq!(&cap[1], "abc");
43 assert_eq!(&cap["name"], "abc");
44}
45
46#[test]
47#[should_panic]
48fn capture_index_panic_usize() {
49 let re = regex!(r"^(?P<name>.+)$");
50 let cap = re.captures("abc").unwrap();
51 let _ = cap[2];
52}
53
54#[test]
55#[should_panic]
56fn capture_index_panic_name() {
57 let re = regex!(r"^(?P<name>.+)$");
58 let cap = re.captures("abc").unwrap();
59 let _ = cap["bad name"];
60}
61
62#[test]
63fn capture_index_lifetime() {
64 // This is a test of whether the types on `caps["..."]` are general
65 // enough. If not, this will fail to typecheck.
66 fn inner(s: &str) -> usize {
67 let re = regex!(r"(?P<number>[0-9]+)");
68 let caps = re.captures(s).unwrap();
69 caps["number"].len()
70 }
71 assert_eq!(3, inner("123"));
72}
73
74#[test]
75fn capture_misc() {
76 let re = regex!(r"(.)(?P<a>a)?(.)(?P<b>.)");
77 let cap = re.captures("abc").unwrap();
78
79 assert_eq!(5, cap.len());
80
81 assert_eq!((0, 3), {
82 let m = cap.get(0).unwrap();
83 (m.start(), m.end())
84 });
85 assert_eq!(None, cap.get(2));
86 assert_eq!((2, 3), {
87 let m = cap.get(4).unwrap();
88 (m.start(), m.end())
89 });
90
91 assert_eq!("abc", cap.get(0).unwrap().as_str());
92 assert_eq!(None, cap.get(2));
93 assert_eq!("c", cap.get(4).unwrap().as_str());
94
95 assert_eq!(None, cap.name("a"));
96 assert_eq!("c", cap.name("b").unwrap().as_str());
97}
98
99#[test]
100fn sub_capture_matches() {
101 let re = regex!(r"([a-z])(([a-z])|([0-9]))");
102 let cap = re.captures("a5").unwrap();
103 let subs: Vec<_> = cap.iter().collect();
104
105 assert_eq!(5, subs.len());
106 assert!(subs[0].is_some());
107 assert!(subs[1].is_some());
108 assert!(subs[2].is_some());
109 assert!(subs[3].is_none());
110 assert!(subs[4].is_some());
111
112 assert_eq!("a5", subs[0].unwrap().as_str());
113 assert_eq!("a", subs[1].unwrap().as_str());
114 assert_eq!("5", subs[2].unwrap().as_str());
115 assert_eq!("5", subs[4].unwrap().as_str());
116}
117
118// Test that the DFA can handle pathological cases. (This should result in the
119// DFA's cache being flushed too frequently, which should cause it to quit and
120// fall back to the NFA algorithm.)
121#[test]
122fn dfa_handles_pathological_case() {
123 fn ones_and_zeroes(count: usize) -> String {
124 let mut s = String::new();
125 for i in 0..count {
126 if i % 3 == 0 {
127 s.push('1');
128 } else {
129 s.push('0');
130 }
131 }
132 s
133 }
134
135 let re = regex!(r"[01]*1[01]{20}$");
136 let text = {
137 let mut pieces = ones_and_zeroes(100_000);
138 pieces.push('1');
139 pieces.push_str(&ones_and_zeroes(20));
140 pieces
141 };
142 assert!(re.is_match(&text));
143}
144