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