1use regex_automata::{DenseDFA, Regex, RegexBuilder, SparseDFA};
2
3use collection::{RegexTester, SUITE};
4
5#[test]
6fn unminimized_standard() {
7 let mut builder = RegexBuilder::new();
8 builder.minimize(false).premultiply(false).byte_classes(false);
9
10 let mut tester = RegexTester::new().skip_expensive();
11 tester.test_all(builder, SUITE.tests());
12 tester.assert();
13}
14
15#[test]
16fn unminimized_premultiply() {
17 let mut builder = RegexBuilder::new();
18 builder.minimize(false).premultiply(true).byte_classes(false);
19
20 let mut tester = RegexTester::new().skip_expensive();
21 tester.test_all(builder, SUITE.tests());
22 tester.assert();
23}
24
25#[test]
26fn unminimized_byte_class() {
27 let mut builder = RegexBuilder::new();
28 builder.minimize(false).premultiply(false).byte_classes(true);
29
30 let mut tester = RegexTester::new();
31 tester.test_all(builder, SUITE.tests());
32 tester.assert();
33}
34
35#[test]
36fn unminimized_premultiply_byte_class() {
37 let mut builder = RegexBuilder::new();
38 builder.minimize(false).premultiply(true).byte_classes(true);
39
40 let mut tester = RegexTester::new();
41 tester.test_all(builder, SUITE.tests());
42 tester.assert();
43}
44
45#[test]
46fn unminimized_standard_no_nfa_shrink() {
47 let mut builder = RegexBuilder::new();
48 builder
49 .minimize(false)
50 .premultiply(false)
51 .byte_classes(false)
52 .shrink(false);
53
54 let mut tester = RegexTester::new().skip_expensive();
55 tester.test_all(builder, SUITE.tests());
56 tester.assert();
57}
58
59#[test]
60fn minimized_standard() {
61 let mut builder = RegexBuilder::new();
62 builder.minimize(true).premultiply(false).byte_classes(false);
63
64 let mut tester = RegexTester::new().skip_expensive();
65 tester.test_all(builder, SUITE.tests());
66 tester.assert();
67}
68
69#[test]
70fn minimized_premultiply() {
71 let mut builder = RegexBuilder::new();
72 builder.minimize(true).premultiply(true).byte_classes(false);
73
74 let mut tester = RegexTester::new().skip_expensive();
75 tester.test_all(builder, SUITE.tests());
76 tester.assert();
77}
78
79#[test]
80fn minimized_byte_class() {
81 let mut builder = RegexBuilder::new();
82 builder.minimize(true).premultiply(false).byte_classes(true);
83
84 let mut tester = RegexTester::new();
85 tester.test_all(builder, SUITE.tests());
86 tester.assert();
87}
88
89#[test]
90fn minimized_premultiply_byte_class() {
91 let mut builder = RegexBuilder::new();
92 builder.minimize(true).premultiply(true).byte_classes(true);
93
94 let mut tester = RegexTester::new();
95 tester.test_all(builder, SUITE.tests());
96 tester.assert();
97}
98
99#[test]
100fn minimized_standard_no_nfa_shrink() {
101 let mut builder = RegexBuilder::new();
102 builder
103 .minimize(true)
104 .premultiply(false)
105 .byte_classes(false)
106 .shrink(false);
107
108 let mut tester = RegexTester::new().skip_expensive();
109 tester.test_all(builder, SUITE.tests());
110 tester.assert();
111}
112
113// A basic sanity test that checks we can convert a regex to a smaller
114// representation and that the resulting regex still passes our tests.
115//
116// If tests grow minimal regexes that cannot be represented in 16 bits, then
117// we'll either want to skip those or increase the size to test to u32.
118#[test]
119fn u16() {
120 let mut builder = RegexBuilder::new();
121 builder.minimize(true).premultiply(false).byte_classes(true);
122
123 let mut tester = RegexTester::new().skip_expensive();
124 for test in SUITE.tests() {
125 let builder = builder.clone();
126 let re: Regex = match tester.build_regex(builder, test) {
127 None => continue,
128 Some(re) => re,
129 };
130 let small_re = Regex::from_dfas(
131 re.forward().to_u16().unwrap(),
132 re.reverse().to_u16().unwrap(),
133 );
134
135 tester.test(test, &small_re);
136 }
137 tester.assert();
138}
139
140// Test that sparse DFAs work using the standard configuration.
141#[test]
142fn sparse_unminimized_standard() {
143 let mut builder = RegexBuilder::new();
144 builder.minimize(false).premultiply(false).byte_classes(false);
145
146 let mut tester = RegexTester::new().skip_expensive();
147 for test in SUITE.tests() {
148 let builder = builder.clone();
149 let re: Regex = match tester.build_regex(builder, test) {
150 None => continue,
151 Some(re) => re,
152 };
153 let fwd = re.forward().to_sparse().unwrap();
154 let rev = re.reverse().to_sparse().unwrap();
155 let sparse_re = Regex::from_dfas(fwd, rev);
156
157 tester.test(test, &sparse_re);
158 }
159 tester.assert();
160}
161
162// Test that sparse DFAs work after converting them to a different state ID
163// representation.
164#[test]
165fn sparse_u16() {
166 let mut builder = RegexBuilder::new();
167 builder.minimize(true).premultiply(false).byte_classes(false);
168
169 let mut tester = RegexTester::new().skip_expensive();
170 for test in SUITE.tests() {
171 let builder = builder.clone();
172 let re: Regex = match tester.build_regex(builder, test) {
173 None => continue,
174 Some(re) => re,
175 };
176 let fwd = re.forward().to_sparse().unwrap().to_u16().unwrap();
177 let rev = re.reverse().to_sparse().unwrap().to_u16().unwrap();
178 let sparse_re = Regex::from_dfas(fwd, rev);
179
180 tester.test(test, &sparse_re);
181 }
182 tester.assert();
183}
184
185// Another basic sanity test that checks we can serialize and then deserialize
186// a regex, and that the resulting regex can be used for searching correctly.
187#[test]
188fn serialization_roundtrip() {
189 let mut builder = RegexBuilder::new();
190 builder.premultiply(false).byte_classes(true);
191
192 let mut tester = RegexTester::new().skip_expensive();
193 for test in SUITE.tests() {
194 let builder = builder.clone();
195 let re: Regex = match tester.build_regex(builder, test) {
196 None => continue,
197 Some(re) => re,
198 };
199
200 let fwd_bytes = re.forward().to_bytes_native_endian().unwrap();
201 let rev_bytes = re.reverse().to_bytes_native_endian().unwrap();
202 let fwd: DenseDFA<&[usize], usize> =
203 unsafe { DenseDFA::from_bytes(&fwd_bytes) };
204 let rev: DenseDFA<&[usize], usize> =
205 unsafe { DenseDFA::from_bytes(&rev_bytes) };
206 let re = Regex::from_dfas(fwd, rev);
207
208 tester.test(test, &re);
209 }
210 tester.assert();
211}
212
213// A basic sanity test that checks we can serialize and then deserialize a
214// regex using sparse DFAs, and that the resulting regex can be used for
215// searching correctly.
216#[test]
217fn sparse_serialization_roundtrip() {
218 let mut builder = RegexBuilder::new();
219 builder.byte_classes(true);
220
221 let mut tester = RegexTester::new().skip_expensive();
222 for test in SUITE.tests() {
223 let builder = builder.clone();
224 let re: Regex = match tester.build_regex(builder, test) {
225 None => continue,
226 Some(re) => re,
227 };
228
229 let fwd_bytes = re
230 .forward()
231 .to_sparse()
232 .unwrap()
233 .to_bytes_native_endian()
234 .unwrap();
235 let rev_bytes = re
236 .reverse()
237 .to_sparse()
238 .unwrap()
239 .to_bytes_native_endian()
240 .unwrap();
241 let fwd: SparseDFA<&[u8], usize> =
242 unsafe { SparseDFA::from_bytes(&fwd_bytes) };
243 let rev: SparseDFA<&[u8], usize> =
244 unsafe { SparseDFA::from_bytes(&rev_bytes) };
245 let re = Regex::from_dfas(fwd, rev);
246
247 tester.test(test, &re);
248 }
249 tester.assert();
250}
251