1 /*
2  * Copyright © 2019-today Peter M. Stahl pemistahl@gmail.com
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use grex::RegExpBuilder;
18 use indoc::indoc;
19 use regex::Regex;
20 use rstest::rstest;
21 use std::io::Write;
22 use tempfile::NamedTempFile;
23 
24 mod no_conversion {
25     use super::*;
26 
27     mod no_repetition {
28         use super::*;
29 
30         #[rstest(test_cases, expected_output,
31             case(vec![""], "^$"),
32             case(vec![" "], "^ $"),
33             case(vec!["   "], "^   $"),
34             case(vec!["["], "^\\[$"),
35             case(vec!["a", "("], "^[(a]$"),
36             case(vec!["a", "\n"], "^[\\na]$"),
37             case(vec!["a", "["], "^[\\[a]$"),
38             case(vec!["a", "-", "c", "!"], "^[!\\-ac]$"),
39             case(vec!["a", "b"], "^[ab]$"),
40             case(vec!["a", "b", "c"], "^[a-c]$"),
41             case(vec!["a", "c", "d", "e", "f"], "^[ac-f]$"),
42             case(vec!["a", "b", "x", "d", "e"], "^[abdex]$"),
43             case(vec!["a", "b", "x", "de"], "^(?:de|[abx])$"),
44             case(vec!["a", "b", "c", "x", "d", "e"], "^[a-ex]$"),
45             case(vec!["a", "b", "c", "x", "de"], "^(?:de|[a-cx])$"),
46             case(vec!["a", "b", "c", "d", "e", "f", "o", "x", "y", "z"], "^[a-fox-z]$"),
47             case(vec!["a", "b", "d", "e", "f", "o", "x", "y", "z"], "^[abd-fox-z]$"),
48             case(vec!["1", "2"], "^[12]$"),
49             case(vec!["1", "2", "3"], "^[1-3]$"),
50             case(vec!["1", "3", "4", "5", "6"], "^[13-6]$"),
51             case(vec!["1", "2", "8", "4", "5"], "^[12458]$"),
52             case(vec!["1", "2", "8", "45"], "^(?:45|[128])$"),
53             case(vec!["1", "2", "3", "8", "4", "5"], "^[1-58]$"),
54             case(vec!["1", "2", "3", "8", "45"], "^(?:45|[1-38])$"),
55             case(vec!["1", "2", "3", "5", "7", "8", "9"], "^[1-357-9]$"),
56             case(vec!["a", "b", "bc"], "^(?:bc?|a)$"),
57             case(vec!["a", "b", "bcd"], "^(?:b(?:cd)?|a)$"),
58             case(vec!["a", "ab", "abc"], "^a(?:bc?)?$"),
59             case(vec!["ac", "bc"], "^[ab]c$"),
60             case(vec!["ab", "ac"], "^a[bc]$"),
61             case(vec!["bc", "abc"], "^a?bc$"),
62             case(vec!["ac", "abc"], "^ab?c$"),
63             case(vec!["abc", "abxyc"], "^ab(?:xy)?c$"),
64             case(vec!["ab", "abc"], "^abc?$"),
65             case(vec!["abx", "cdx"], "^(?:ab|cd)x$"),
66             case(vec!["abd", "acd"], "^a[bc]d$"),
67             case(vec!["abc", "abcd"], "^abcd?$"),
68             case(vec!["abc", "abcde"], "^abc(?:de)?$"),
69             case(vec!["ade", "abcde"], "^a(?:bc)?de$"),
70             case(vec!["abcxy", "adexy"], "^a(?:bc|de)xy$"),
71             case(vec!["axy", "abcxy", "adexy"], "^a(?:(?:bc)?|de)xy$"), // goal: "^a(bc|de)?xy$"
72             case(vec!["abcxy", "abcw", "efgh"], "^(?:abc(?:xy|w)|efgh)$"),
73             case(vec!["abcxy", "efgh", "abcw"], "^(?:abc(?:xy|w)|efgh)$"),
74             case(vec!["efgh", "abcxy", "abcw"], "^(?:abc(?:xy|w)|efgh)$"),
75             case(vec!["abxy", "cxy", "efgh"], "^(?:(?:ab|c)xy|efgh)$"),
76             case(vec!["abxy", "efgh", "cxy"], "^(?:(?:ab|c)xy|efgh)$"),
77             case(vec!["efgh", "abxy", "cxy"], "^(?:(?:ab|c)xy|efgh)$"),
78             case(vec!["a", "ä", "o", "ö", "u", "ü"], "^[aouäöü]$"),
79             case(vec!["y̆", "a", "z"], "^(?:y̆|[az])$"), // goal: "^[az]|y\\u{306}$"
80             case(vec!["a", "b\n", "c"], "^(?:b\\n|[ac])$"),
81             case(vec!["a", "b\\n", "c"], "^(?:b\\\\n|[ac])$"),
82             case(vec!["[a-z]", "(d,e,f)"], "^(?:\\(d,e,f\\)|\\[a\\-z\\])$"),
83             case(vec!["3.5", "4.5", "4,5"], "^(?:3\\.5|4[,.]5)$"),
84             case(vec!["\u{b}"], "^\\v$"), // U+000B Line Tabulation
85             case(vec!["\\u{b}"], "^\\\\u\\{b\\}$"),
86             case(vec!["I ♥ cake"], "^I ♥ cake$"),
87             case(vec!["I \u{2665} cake"], "^I ♥ cake$"),
88             case(vec!["I \\u{2665} cake"], "^I \\\\u\\{2665\\} cake$"),
89             case(vec!["I \\u2665 cake"], "^I \\\\u2665 cake$"),
90             case(vec!["My ♥ is yours.", "My �� is yours."], "^My [♥��] is yours\\.$"),
91             case(vec!["[\u{c3e}"], "^\\[\u{c3e}$"),
92             case(vec!["\\\u{10376}"], "^\\\\\u{10376}$"),
93             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^I   ♥♥♥ 36 and ٣ and y̆y̆ and ����\\.$")
94         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)95         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
96             let regexp = RegExpBuilder::from(&test_cases).build();
97             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
98             assert_that_regexp_matches_test_cases(expected_output, test_cases);
99         }
100 
101         #[rstest(test_cases, expected_output,
102             case(vec!["ABC", "abc", "AbC", "aBc"], "(?i)^abc$"),
103             case(vec!["ABC", "zBC", "abc", "AbC", "aBc"], "(?i)^[az]bc$"),
104             case(vec!["Ä@Ö€Ü", "ä@ö€ü", "Ä@ö€Ü", "ä@Ö€ü"], "(?i)^ä@ö€ü$"),
105         )]
succeeds_with_ignore_case_option(test_cases: Vec<&str>, expected_output: &str)106         fn succeeds_with_ignore_case_option(test_cases: Vec<&str>, expected_output: &str) {
107             let regexp = RegExpBuilder::from(&test_cases)
108                 .with_case_insensitive_matching()
109                 .build();
110             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
111             assert_that_regexp_matches_test_cases(expected_output, test_cases);
112         }
113 
114         #[rstest(test_cases, expected_output,
115             case(vec!["My ♥ and �� is yours."], "^My \\u{2665} and \\u{1f4a9} is yours\\.$"),
116             case(vec!["My ♥ is yours.", "My �� is yours."], "^My (?:\\u{2665}|\\u{1f4a9}) is yours\\.$"),
117             case(
118                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
119                 "^I   \\u{2665}\\u{2665}\\u{2665} 36 and \\u{663} and y\\u{306}y\\u{306} and \\u{1f4a9}\\u{1f4a9}\\.$"
120             )
121         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)122         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
123             let regexp = RegExpBuilder::from(&test_cases)
124                 .with_escaping_of_non_ascii_chars(false)
125                 .build();
126             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
127             assert_that_regexp_matches_test_cases(expected_output, test_cases);
128         }
129 
130         #[rstest(test_cases, expected_output,
131             case(vec!["My ♥ and �� is yours."], "^My \\u{2665} and \\u{d83d}\\u{dca9} is yours\\.$"),
132             case(vec!["My ♥ is yours.", "My �� is yours."], "^My (?:\\u{2665}|\\u{d83d}\\u{dca9}) is yours\\.$"),
133             case(
134                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
135                 "^I   \\u{2665}\\u{2665}\\u{2665} 36 and \\u{663} and y\\u{306}y\\u{306} and \\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
136             )
137         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)138         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
139             let regexp = RegExpBuilder::from(&test_cases)
140                 .with_escaping_of_non_ascii_chars(true)
141                 .build();
142             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
143         }
144 
145         #[rstest(test_cases, expected_output,
146             case(vec!["a", "b", "bc"], "^(bc?|a)$"),
147             case(vec!["a", "b", "bcd"], "^(b(cd)?|a)$"),
148             case(vec!["a", "ab", "abc"], "^a(bc?)?$"),
149             case(vec!["efgh", "abcxy", "abcw"], "^(abc(xy|w)|efgh)$"),
150         )]
succeeds_with_capturing_groups_option(test_cases: Vec<&str>, expected_output: &str)151         fn succeeds_with_capturing_groups_option(test_cases: Vec<&str>, expected_output: &str) {
152             let regexp = RegExpBuilder::from(&test_cases)
153                 .with_capturing_groups()
154                 .build();
155             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
156             assert_that_regexp_matches_test_cases(expected_output, test_cases);
157         }
158 
159         #[rstest(test_cases, expected_output,
160             case(vec![""], indoc!(
161                 r#"
162                 (?x)
163                 ^
164                 $"#
165             )),
166             case(vec![" "], indoc!(
167                 r#"
168                 (?x)
169                 ^
170                   \
171                 $"#
172             )),
173             case(vec!["   "], indoc!(
174                 r#"
175                 (?x)
176                 ^
177                   \ \ \
178                 $"#
179             )),
180             case(vec!["a", "b", "c"], indoc!(
181                 r#"
182                 (?x)
183                 ^
184                   [a-c]
185                 $"#
186             )),
187             case(vec!["a", "b", "bc"], indoc!(
188                 r#"
189                 (?x)
190                 ^
191                   (?:
192                     bc?
193                     |
194                     a
195                   )
196                 $"#
197             )),
198             case(vec!["a", "ab", "abc"], indoc!(
199                 r#"
200                 (?x)
201                 ^
202                   a
203                   (?:
204                     bc?
205                   )?
206                 $"#
207             )),
208             case(vec!["a", "b", "bcd"], indoc!(
209                 r#"
210                 (?x)
211                 ^
212                   (?:
213                     b
214                     (?:
215                       cd
216                     )?
217                     |
218                     a
219                   )
220                 $"#
221             )),
222             case(vec!["a", "b", "x", "de"], indoc!(
223                 r#"
224                 (?x)
225                 ^
226                   (?:
227                     de
228                     |
229                     [abx]
230                   )
231                 $"#
232             )),
233             case(vec!["[a-z]", "(d,e,f)"], indoc!(
234                 r#"
235                 (?x)
236                 ^
237                   (?:
238                     \(d,e,f\)
239                     |
240                     \[a\-z\]
241                   )
242                 $"#
243             )),
244             case(vec!["3.5", "4.5", "4,5"], indoc!(
245                 r#"
246                 (?x)
247                 ^
248                   (?:
249                     3\.5
250                     |
251                     4[,.]5
252                   )
253                 $"#
254             ))
255         )]
succeeds_with_verbose_mode_option(test_cases: Vec<&str>, expected_output: &str)256         fn succeeds_with_verbose_mode_option(test_cases: Vec<&str>, expected_output: &str) {
257             let regexp = RegExpBuilder::from(&test_cases).with_verbose_mode().build();
258             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
259             assert_that_regexp_matches_test_cases(expected_output, test_cases);
260         }
261 
262         #[rstest(test_cases, expected_output,
263             case(vec!["ABC", "abc", "AbC", "aBc"], indoc!(
264                 r#"
265                 (?ix)
266                 ^
267                   abc
268                 $"#
269             )),
270             case(vec!["ABC", "zBC", "abc", "AbC", "aBc"], indoc!(
271                 r#"
272                 (?ix)
273                 ^
274                   [az]bc
275                 $"#
276             )),
277             case(vec!["Ä@Ö€Ü", "ä@ö€ü", "Ä@ö€Ü", "ä@Ö€ü"], indoc!(
278                 r#"
279                 (?ix)
280                 ^
281                   ä@ö€ü
282                 $"#
283             ))
284         )]
succeeds_with_ignore_case_and_verbose_mode_option( test_cases: Vec<&str>, expected_output: &str, )285         fn succeeds_with_ignore_case_and_verbose_mode_option(
286             test_cases: Vec<&str>,
287             expected_output: &str,
288         ) {
289             let regexp = RegExpBuilder::from(&test_cases)
290                 .with_case_insensitive_matching()
291                 .with_verbose_mode()
292                 .build();
293             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
294             assert_that_regexp_matches_test_cases(expected_output, test_cases);
295         }
296 
297         #[test]
succeeds_with_file_input()298         fn succeeds_with_file_input() {
299             let mut file = NamedTempFile::new().unwrap();
300             writeln!(file, "a\nb\nc\r\nxyz").unwrap();
301 
302             let expected_output = "^(?:xyz|[a-c])$";
303             let test_cases = vec!["a", "b", "c", "xyz"];
304 
305             let regexp = RegExpBuilder::from_file(file.path()).build();
306             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
307             assert_that_regexp_matches_test_cases(expected_output, test_cases);
308         }
309 
310         #[rstest(test_cases, expected_output,
311             case(vec!["bab", "b", "cb", "bba"], "(?:b(?:ba|ab)?|cb)"),
312             case(vec!["a", "aba", "baaa", "aaab"], "(?:baaa|a(?:aab|ba)?)"),
313             case(vec!["a", "abab", "bbb", "aaac"], "(?:a(?:bab|aac)?|bbb)"),
314             case(
315                 // https://github.com/pemistahl/grex/issues/31
316                 vec!["agbhd", "eibcd", "egbcd", "fbjbf", "agbh", "eibc", "egbc", "ebc", "fbc", "cd", "f", "c", "abcd", "ebcd", "fbcd"],
317                 "(?:a(?:gbhd?|bcd)|e(?:ibcd?|gbcd?|bcd?)|f(?:b(?:jbf|cd?))?|cd?)")
318         )]
succeeds_without_anchors(test_cases: Vec<&str>, expected_output: &str)319         fn succeeds_without_anchors(test_cases: Vec<&str>, expected_output: &str) {
320             let regexp = RegExpBuilder::from(&test_cases).without_anchors().build();
321             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
322             assert_that_regexp_matches_test_cases(expected_output, test_cases);
323         }
324     }
325 
326     mod repetition {
327         use super::*;
328 
329         #[rstest(test_cases, expected_output,
330             case(vec![""], "^$"),
331             case(vec![" "], "^ $"),
332             case(vec!["   "], "^ {3}$"),
333             case(vec!["a"], "^a$"),
334             case(vec!["aa"], "^a{2}$"),
335             case(vec!["aaa"], "^a{3}$"),
336             case(vec!["aaa aaa"], "^a{3} a{3}$"),
337             case(vec!["ababab ababab"], "^(?:ab){3} (?:ab){3}$"),
338             case(vec!["ababab  ababab"], "^(?:ab){3} {2}(?:ab){3}$"),
339             case(vec!["a ababab ababab"], "^a(?: (?:ab){3}){2}$"),
340             case(vec!["ababab ababab a"], "^a(?:b(?:ab){2} a){2}$"),
341             case(vec!["ababababab abab ababab"], "^ababab(?:(?:ab){2} ){2}(?:ab){3}$"),
342             case(vec!["a", "aa"], "^a{1,2}$"),
343             case(vec!["aaa", "a", "aa"], "^a{1,3}$"),
344             case(vec!["aaaa", "a", "aa"], "^(?:a{1,2}|a{4})$"),
345             case(vec!["a", "aa", "aaa", "aaaa", "aaab"], "^(?:a{3}b|a{1,4})$"),
346             case(vec!["baabaaaaaabb"], "^ba{2}ba{6}b{2}$"),
347             case(vec!["aabbaabbaaa"], "^(?:a{2}b{2}){2}a{3}$"),
348             case(vec!["aabbaa"], "^a{2}b{2}a{2}$"),
349             case(vec!["aabbabb"], "^a(?:ab{2}){2}$"),
350             case(vec!["ababab"], "^(?:ab){3}$"),
351             case(vec!["abababa"], "^a(?:ba){3}$"),
352             case(vec!["aababab"], "^a(?:ab){3}$"),
353             case(vec!["abababaa"], "^(?:ab){3}a{2}$"),
354             case(vec!["aaaaaabbbbb"], "^a{6}b{5}$"),
355             case(vec!["aabaababab"], "^a{2}ba(?:ab){3}$"),
356             case(vec!["aaaaaaabbbbbba"], "^a{7}b{6}a$"),
357             case(vec!["abaaaabaaba"], "^abaaa(?:aba){2}$"),
358             case(vec!["bbaababb"], "^b{2}a{2}bab{2}$"),
359             case(vec!["b", "ba"], "^ba?$"),
360             case(vec!["b", "ba", "baa"], "^b(?:a{1,2})?$"),
361             case(vec!["b", "ba", "baaa", "baa"], "^b(?:a{1,3})?$"),
362             case(vec!["b", "ba", "baaaa", "baa"], "^b(?:a{1,2}|a{4})?$"),
363             case(vec!["axy", "abcxyxy", "adexy"], "^a(?:(?:de)?xy|bc(?:xy){2})$"),
364             case(vec!["xy̆y̆y̆y̆z"], "^x(?:y̆){4}z$"),
365             case(vec!["xy̆y̆z", "xy̆y̆y̆z"], "^x(?:y̆){2,3}z$"),
366             case(vec!["xy̆y̆z", "xy̆y̆y̆y̆z"], "^x(?:(?:y̆){2}|(?:y̆){4})z$"),
367             case(vec!["zyxx", "yxx"], "^z?yx{2}$"),
368             case(vec!["zyxx", "yxx", "yxxx"], "^(?:zyx{2}|yx{2,3})$"),
369             case(vec!["zyxxx", "yxx", "yxxx"], "^(?:zyx{3}|yx{2,3})$"),
370             case(vec!["a", "b\n\n", "c"], "^(?:b\\n{2}|[ac])$"),
371             case(vec!["a", "b\nb\nb", "c"], "^(?:b(?:\\nb){2}|[ac])$"),
372             case(vec!["a", "b\nx\nx", "c"], "^(?:b(?:\\nx){2}|[ac])$"),
373             case(vec!["a", "b\n\t\n\t", "c"], "^(?:b(?:\\n\\t){2}|[ac])$"),
374             case(vec!["a", "b\n", "b\n\n", "b\n\n\n", "c"], "^(?:b\\n{1,3}|[ac])$"),
375             case(vec!["4.5", "3.55"], "^(?:4\\.5|3\\.5{2})$"),
376             case(vec!["4.5", "4.55"], "^4\\.5{1,2}$"),
377             case(vec!["4.5", "4.55", "3.5"], "^(?:3\\.5|4\\.5{1,2})$"),
378             case(vec!["4.5", "44.5", "44.55", "4.55"], "^4{1,2}\\.5{1,2}$"),
379             case(vec!["I ♥♥ cake"], "^I ♥{2} cake$"),
380             case(vec!["I ♥ cake", "I ♥♥ cake"], "^I ♥{1,2} cake$"),
381             case(vec!["I \u{2665}\u{2665} cake"], "^I ♥{2} cake$"),
382             case(vec!["I \\u{2665} cake"], "^I \\\\u\\{26{2}5\\} cake$"),
383             case(vec!["I \\u{2665}\\u{2665} cake"], "^I (?:\\\\u\\{26{2}5\\}){2} cake$"),
384             case(vec!["I \\u2665\\u2665 cake"], "^I (?:\\\\u26{2}5){2} cake$"),
385             case(vec!["My ♥♥♥ is yours.", "My ���� is yours."], "^My (?:��{2}|♥{3}) is yours\\.$"),
386             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^I {3}♥{3} 36 and ٣ and (?:y̆){2} and ��{2}\\.$")
387         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)388         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
389             let regexp = RegExpBuilder::from(&test_cases)
390                 .with_conversion_of_repetitions()
391                 .build();
392             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
393             assert_that_regexp_matches_test_cases(expected_output, test_cases);
394         }
395 
396         #[rstest(test_cases, expected_output,
397             case(vec!["AAAAB", "aaaab", "AaAaB", "aAaAB"], "(?i)^a{4}b$"),
398             case(vec!["ÄÖÜäöü@Ö€", "äöüÄöÜ@ö€"], "(?i)^(?:äöü){2}@ö€$"),
399         )]
succeeds_with_ignore_case_option(test_cases: Vec<&str>, expected_output: &str)400         fn succeeds_with_ignore_case_option(test_cases: Vec<&str>, expected_output: &str) {
401             let regexp = RegExpBuilder::from(&test_cases)
402                 .with_conversion_of_repetitions()
403                 .with_case_insensitive_matching()
404                 .build();
405             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
406             assert_that_regexp_matches_test_cases(expected_output, test_cases);
407         }
408 
409         #[rstest(test_cases, expected_output,
410             case(vec!["My ♥♥♥ and ���� is yours."], "^My \\u{2665}{3} and \\u{1f4a9}{2} is yours\\.$"),
411             case(vec!["My ♥♥♥ is yours.", "My ���� is yours."], "^My (?:\\u{1f4a9}{2}|\\u{2665}{3}) is yours\\.$"),
412             case(
413                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
414                 "^I {3}\\u{2665}{3} 36 and \\u{663} and (?:y\\u{306}){2} and \\u{1f4a9}{2}\\.$"
415             )
416         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)417         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
418             let regexp = RegExpBuilder::from(&test_cases)
419                 .with_conversion_of_repetitions()
420                 .with_escaping_of_non_ascii_chars(false)
421                 .build();
422             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
423             assert_that_regexp_matches_test_cases(expected_output, test_cases);
424         }
425 
426         #[rstest(test_cases, expected_output,
427             case(vec!["My ♥♥♥ and ���� is yours."], "^My \\u{2665}{3} and (?:\\u{d83d}\\u{dca9}){2} is yours\\.$"),
428             case(vec!["My ♥♥♥ is yours.", "My ���� is yours."], "^My (?:(?:\\u{d83d}\\u{dca9}){2}|\\u{2665}{3}) is yours\\.$"),
429             case(
430                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
431                 "^I {3}\\u{2665}{3} 36 and \\u{663} and (?:y\\u{306}){2} and (?:\\u{d83d}\\u{dca9}){2}\\.$"
432             )
433         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)434         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
435             let regexp = RegExpBuilder::from(&test_cases)
436                 .with_conversion_of_repetitions()
437                 .with_escaping_of_non_ascii_chars(true)
438                 .build();
439             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
440         }
441 
442         #[rstest(test_cases, expected_output,
443             case(vec!["   "], indoc!(
444                 r#"
445                 (?x)
446                 ^
447                   \ {3}
448                 $"#
449             )),
450             case(vec!["aa"], indoc!(
451                 r#"
452                 (?x)
453                 ^
454                   a{2}
455                 $"#
456             )),
457             case(vec!["aaa", "a", "aa"], indoc!(
458                 r#"
459                 (?x)
460                 ^
461                   a{1,3}
462                 $"#
463             )),
464             case(vec!["aaaa", "a", "aa"], indoc!(
465                 r#"
466                 (?x)
467                 ^
468                   (?:
469                     a{1,2}
470                     |
471                     a{4}
472                   )
473                 $"#
474             )),
475             case(vec!["ababab"], indoc!(
476                 r#"
477                 (?x)
478                 ^
479                   (?:
480                     ab
481                   ){3}
482                 $"#
483             )),
484             case(vec!["abababa"], indoc!(
485                 r#"
486                 (?x)
487                 ^
488                   a
489                   (?:
490                     ba
491                   ){3}
492                 $"#
493             )),
494             case(vec!["abababaa"], indoc!(
495                 r#"
496                 (?x)
497                 ^
498                   (?:
499                     ab
500                   ){3}
501                   a{2}
502                 $"#
503             )),
504             case(vec!["aabaababab"], indoc!(
505                 r#"
506                 (?x)
507                 ^
508                   a{2}ba
509                   (?:
510                     ab
511                   ){3}
512                 $"#
513             )),
514             case(vec!["abaaaabaaba"], indoc!(
515                 r#"
516                 (?x)
517                 ^
518                   abaaa
519                   (?:
520                     aba
521                   ){2}
522                 $"#
523             )),
524             case(vec!["xy̆y̆z", "xy̆y̆y̆y̆z"], indoc!(
525                 r#"
526                 (?x)
527                 ^
528                   x
529                   (?:
530                     (?:
531 
532                     ){2}
533                     |
534                     (?:
535 
536                     ){4}
537                   )
538                   z
539                 $"#
540             )),
541             case(vec!["a", "b\n\t\n\t", "c"], indoc!(
542                 r#"
543                 (?x)
544                 ^
545                   (?:
546                     b
547                     (?:
548                       \n\t
549                     ){2}
550                     |
551                     [ac]
552                   )
553                 $"#
554             )),
555             case(vec!["My ♥♥♥ is yours.", "My ���� is yours."], indoc!(
556                 r#"
557                 (?x)
558                 ^
559                   My\
560                   (?:
561                     ��{2}
562                     |
563                     ♥{3}
564                   )
565                   \ is\ yours\.
566                 $"#
567             ))
568         )]
succeeds_with_verbose_mode_option(test_cases: Vec<&str>, expected_output: &str)569         fn succeeds_with_verbose_mode_option(test_cases: Vec<&str>, expected_output: &str) {
570             let regexp = RegExpBuilder::from(&test_cases)
571                 .with_conversion_of_repetitions()
572                 .with_verbose_mode()
573                 .build();
574             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
575             assert_that_regexp_matches_test_cases(expected_output, test_cases);
576         }
577 
578         #[rstest(test_cases, expected_output,
579             case(vec![""], "^$"),
580             case(vec![" "], "^ $"),
581             case(vec!["   "], "^   $"),
582             case(vec!["    "], "^ {4}$"),
583             case(vec!["      "], "^ {6}$"),
584             case(vec!["a"], "^a$"),
585             case(vec!["aa"], "^aa$"),
586             case(vec!["aaa"], "^aaa$"),
587             case(vec!["aaaa"], "^a{4}$"),
588             case(vec!["aaaaa"], "^a{5}$"),
589             case(vec!["ababababab abab ababab"], "^(?:ab){5} abab ababab$"),
590             case(vec!["aabbaaaabbbabbbbba"], "^aabba{4}bbbab{5}a$"),
591             case(vec!["baabaaaaaabb"], "^baaba{6}bb$"),
592             case(vec!["ababab"], "^ababab$"),
593             case(vec!["abababab"], "^(?:ab){4}$"),
594             case(vec!["abababa"], "^abababa$"),
595             case(vec!["ababababa"], "^a(?:ba){4}$"),
596             case(vec!["aababab"], "^aababab$"),
597             case(vec!["aabababab"], "^a(?:ab){4}$"),
598             case(vec!["xy̆y̆z", "xy̆y̆y̆y̆z"], "^x(?:y̆y̆|(?:y̆){4})z$"),
599             case(vec!["aaa", "a", "aa"], "^a(?:aa?)?$"),
600             case(vec!["a", "aa", "aaa", "aaaa"], "^(?:aaa|aa?|a{4})$"),
601             case(vec!["a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa"], "^(?:aaa|aa?|a{4,6})$")
602         )]
succeeds_with_increased_minimum_repetitions( test_cases: Vec<&str>, expected_output: &str, )603         fn succeeds_with_increased_minimum_repetitions(
604             test_cases: Vec<&str>,
605             expected_output: &str,
606         ) {
607             let regexp = RegExpBuilder::from(&test_cases)
608                 .with_conversion_of_repetitions()
609                 .with_minimum_repetitions(3)
610                 .build();
611             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
612             assert_that_regexp_matches_test_cases(expected_output, test_cases);
613         }
614 
615         #[rstest(test_cases, expected_output,
616             case(vec!["aaa"], "^aaa$"),
617             case(vec!["ababab"], "^ababab$"),
618             case(vec!["abcabcabc"], "^(?:abc){3}$"),
619             case(vec!["abcabcabc", "dede"], "^(?:dede|(?:abc){3})$"),
620             case(vec!["abcabcabc", "defgdefg"], "^(?:(?:defg){2}|(?:abc){3})$"),
621             case(vec!["ababababab abab ababab"], "^ababab(?:abab ){2}ababab$")
622         )]
succeeds_with_increased_minimum_substring_length( test_cases: Vec<&str>, expected_output: &str, )623         fn succeeds_with_increased_minimum_substring_length(
624             test_cases: Vec<&str>,
625             expected_output: &str,
626         ) {
627             let regexp = RegExpBuilder::from(&test_cases)
628                 .with_conversion_of_repetitions()
629                 .with_minimum_substring_length(3)
630                 .build();
631             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
632             assert_that_regexp_matches_test_cases(expected_output, test_cases);
633         }
634 
635         #[rstest(test_cases, expected_output,
636             case(vec!["abababab"], "^abababab$"),
637             case(vec!["abcabcabc"], "^abcabcabc$"),
638             case(vec!["abcabcabcabc"], "^(?:abc){4}$"),
639             case(vec!["aaaaaaaaaaaa"], "^aaaaaaaaaaaa$"),
640             case(vec!["abababab", "abcabcabcabc"], "^(?:abababab|(?:abc){4})$"),
641             case(vec!["ababababab abab ababab"], "^ababababab abab ababab$")
642         )]
succeeds_with_increased_minimum_repetitions_and_substring_length( test_cases: Vec<&str>, expected_output: &str, )643         fn succeeds_with_increased_minimum_repetitions_and_substring_length(
644             test_cases: Vec<&str>,
645             expected_output: &str,
646         ) {
647             let regexp = RegExpBuilder::from(&test_cases)
648                 .with_conversion_of_repetitions()
649                 .with_minimum_repetitions(3)
650                 .with_minimum_substring_length(3)
651                 .build();
652             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
653             assert_that_regexp_matches_test_cases(expected_output, test_cases);
654         }
655     }
656 }
657 
658 mod digit_conversion {
659     use super::*;
660 
661     mod no_repetition {
662         use super::*;
663 
664         #[rstest(test_cases, expected_output,
665             case(vec![""], "^$"),
666             case(vec!["a"], "^a$"),
667             case(vec!["1"], "^\\d$"),
668             case(vec!["-1"], "^\\-\\d$"),
669             case(vec!["12"], "^\\d\\d$"),
670             case(vec!["1", "2"], "^\\d$"),
671             case(vec!["1", "23"], "^\\d(?:\\d)?$"),
672             case(vec!["1", "234"], "^\\d(?:\\d\\d)?$"),
673             case(vec!["8", "234"], "^\\d(?:\\d\\d)?$"),
674             case(vec!["890", "34"], "^\\d\\d(?:\\d)?$"),
675             case(vec!["abc123"], "^abc\\d\\d\\d$"),
676             case(vec!["a1b2c3"], "^a\\db\\dc\\d$"),
677             case(vec!["abc", "123"], "^(?:\\d\\d\\d|abc)$"),
678             case(vec!["١", "٣", "٥"], "^\\d$"), // Arabic digits: ١ = 1, ٣ = 3, ٥ = 5
679             case(vec!["١٣٥"], "^\\d\\d\\d$"),
680             case(vec!["a٣3", "b5٥"], "^[ab]\\d\\d$"),
681             case(vec!["I ♥ 123"], "^I ♥ \\d\\d\\d$"),
682             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^I   ♥♥♥ \\d\\d and \\d and y̆y̆ and ����\\.$")
683         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)684         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
685             let regexp = RegExpBuilder::from(&test_cases)
686                 .with_conversion_of_digits()
687                 .build();
688             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
689             assert_that_regexp_matches_test_cases(expected_output, test_cases);
690         }
691 
692         #[rstest(test_cases, expected_output,
693             case(
694                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
695                 "^I   \\u{2665}\\u{2665}\\u{2665} \\d\\d and \\d and y\\u{306}y\\u{306} and \\u{1f4a9}\\u{1f4a9}\\.$"
696             )
697         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)698         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
699             let regexp = RegExpBuilder::from(&test_cases)
700                 .with_conversion_of_digits()
701                 .with_escaping_of_non_ascii_chars(false)
702                 .build();
703             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
704             assert_that_regexp_matches_test_cases(expected_output, test_cases);
705         }
706 
707         #[rstest(test_cases, expected_output,
708             case(
709                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
710                 "^I   \\u{2665}\\u{2665}\\u{2665} \\d\\d and \\d and y\\u{306}y\\u{306} and \\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
711             )
712         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)713         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
714             let regexp = RegExpBuilder::from(&test_cases)
715                 .with_conversion_of_digits()
716                 .with_escaping_of_non_ascii_chars(true)
717                 .build();
718             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
719         }
720     }
721 
722     mod repetition {
723         use super::*;
724 
725         #[rstest(test_cases, expected_output,
726             case(
727                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
728                 "^I {3}♥{3} \\d(?:\\d and ){2}(?:y̆){2} and ��{2}\\.$"
729             )
730         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)731         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
732             let regexp = RegExpBuilder::from(&test_cases)
733                 .with_conversion_of_repetitions()
734                 .with_conversion_of_digits()
735                 .build();
736             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
737             assert_that_regexp_matches_test_cases(expected_output, test_cases);
738         }
739 
740         #[rstest(test_cases, expected_output,
741             case(
742                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
743                 "^I {3}\\u{2665}{3} \\d(?:\\d and ){2}(?:y\\u{306}){2} and \\u{1f4a9}{2}\\.$"
744             )
745         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)746         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
747             let regexp = RegExpBuilder::from(&test_cases)
748                 .with_conversion_of_repetitions()
749                 .with_conversion_of_digits()
750                 .with_escaping_of_non_ascii_chars(false)
751                 .build();
752             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
753             assert_that_regexp_matches_test_cases(expected_output, test_cases);
754         }
755 
756         #[rstest(test_cases, expected_output,
757             case(
758                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
759                 "^I {3}\\u{2665}{3} \\d(?:\\d and ){2}(?:y\\u{306}){2} and (?:\\u{d83d}\\u{dca9}){2}\\.$"
760             )
761         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)762         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
763             let regexp = RegExpBuilder::from(&test_cases)
764                 .with_conversion_of_repetitions()
765                 .with_conversion_of_digits()
766                 .with_escaping_of_non_ascii_chars(true)
767                 .build();
768             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
769         }
770 
771         #[rstest(test_cases, expected_output,
772             case(vec!["1"], "^\\d$"),
773             case(vec!["12"], "^\\d\\d$"),
774             case(vec!["123"], "^\\d{3}$"),
775             case(vec!["1", "12", "123"], "^(?:\\d\\d|\\d|\\d{3})$"),
776             case(vec!["12", "123", "1234"], "^(?:\\d\\d|\\d{3,4})$"),
777             case(vec!["123", "1234", "12345"], "^\\d{3,5}$"),
778             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^I {3}♥{3} \\d\\d and \\d and y̆y̆ and ����\\.$")
779         )]
succeeds_with_increased_minimum_repetitions( test_cases: Vec<&str>, expected_output: &str, )780         fn succeeds_with_increased_minimum_repetitions(
781             test_cases: Vec<&str>,
782             expected_output: &str,
783         ) {
784             let regexp = RegExpBuilder::from(&test_cases)
785                 .with_conversion_of_repetitions()
786                 .with_conversion_of_digits()
787                 .with_minimum_repetitions(2)
788                 .build();
789             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
790             assert_that_regexp_matches_test_cases(expected_output, test_cases);
791         }
792     }
793 }
794 
795 mod space_conversion {
796     use super::*;
797 
798     mod no_repetition {
799         use super::*;
800 
801         #[rstest(test_cases, expected_output,
802             case(vec![""], "^$"),
803             case(vec![" "], "^\\s$"),
804             case(vec!["   "], "^\\s\\s\\s$"),
805             case(vec!["\n"], "^\\s$"),
806             case(vec!["\u{c}"], "^\\s$"), // form feed \f
807             case(vec!["\u{b}"], "^\\s$"), // vertical tab \v
808             case(vec!["\n", "\r"], "^\\s$"),
809             case(vec!["\n\t", "\r"], "^\\s(?:\\s)?$"),
810             case(vec!["a"], "^a$"),
811             case(vec!["1"], "^1$"),
812             case(vec!["I ♥ 123"], "^I\\s♥\\s123$"),
813             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^I\\s\\s\\s♥♥♥\\s36\\sand\\s٣\\sand\\sy̆y̆\\sand\\s����\\.$")
814         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)815         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
816             let regexp = RegExpBuilder::from(&test_cases)
817                 .with_conversion_of_whitespace()
818                 .build();
819             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
820             assert_that_regexp_matches_test_cases(expected_output, test_cases);
821         }
822 
823         #[rstest(test_cases, expected_output,
824             case(
825                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
826                 "^I\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s36\\sand\\s\\u{663}\\sand\\sy\\u{306}y\\u{306}\\sand\\s\\u{1f4a9}\\u{1f4a9}\\.$"
827             )
828         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)829         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
830             let regexp = RegExpBuilder::from(&test_cases)
831                 .with_conversion_of_whitespace()
832                 .with_escaping_of_non_ascii_chars(false)
833                 .build();
834             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
835             assert_that_regexp_matches_test_cases(expected_output, test_cases);
836         }
837 
838         #[rstest(test_cases, expected_output,
839             case(
840                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
841                 "^I\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s36\\sand\\s\\u{663}\\sand\\sy\\u{306}y\\u{306}\\sand\\s\\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
842             )
843         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)844         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
845             let regexp = RegExpBuilder::from(&test_cases)
846                 .with_conversion_of_whitespace()
847                 .with_escaping_of_non_ascii_chars(true)
848                 .build();
849             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
850         }
851     }
852 
853     mod repetition {
854         use super::*;
855 
856         #[rstest(test_cases, expected_output,
857             case(
858                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
859                 "^I\\s{3}♥{3}\\s36\\sand\\s٣\\sand\\s(?:y̆){2}\\sand\\s��{2}\\.$"
860             )
861         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)862         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
863             let regexp = RegExpBuilder::from(&test_cases)
864                 .with_conversion_of_repetitions()
865                 .with_conversion_of_whitespace()
866                 .build();
867             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
868             assert_that_regexp_matches_test_cases(expected_output, test_cases);
869         }
870 
871         #[rstest(test_cases, expected_output,
872             case(
873                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
874                 "^I\\s{3}\\u{2665}{3}\\s36\\sand\\s\\u{663}\\sand\\s(?:y\\u{306}){2}\\sand\\s\\u{1f4a9}{2}\\.$"
875             )
876         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)877         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
878             let regexp = RegExpBuilder::from(&test_cases)
879                 .with_conversion_of_repetitions()
880                 .with_conversion_of_whitespace()
881                 .with_escaping_of_non_ascii_chars(false)
882                 .build();
883             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
884             assert_that_regexp_matches_test_cases(expected_output, test_cases);
885         }
886 
887         #[rstest(test_cases, expected_output,
888             case(
889                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
890                 "^I\\s{3}\\u{2665}{3}\\s36\\sand\\s\\u{663}\\sand\\s(?:y\\u{306}){2}\\sand\\s(?:\\u{d83d}\\u{dca9}){2}\\.$"
891             )
892         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)893         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
894             let regexp = RegExpBuilder::from(&test_cases)
895                 .with_conversion_of_repetitions()
896                 .with_conversion_of_whitespace()
897                 .with_escaping_of_non_ascii_chars(true)
898                 .build();
899             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
900         }
901 
902         #[rstest(test_cases, expected_output,
903             case(vec![" "], "^\\s$"),
904             case(vec!["  "], "^\\s\\s$"),
905             case(vec!["   "], "^\\s{3}$"),
906             case(vec![" ", "  ", "   "], "^(?:\\s\\s|\\s|\\s{3})$"),
907             case(vec!["  ", "   ", "    "], "^(?:\\s\\s|\\s{3,4})$"),
908             case(vec!["   ", "    ", "     "], "^\\s{3,5}$"),
909             case(
910                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
911                 "^I\\s{3}♥{3}\\s36\\sand\\s٣\\sand\\sy\u{306}y\u{306}\\sand\\s����\\.$"
912             )
913         )]
succeeds_with_increased_minimum_repetitions( test_cases: Vec<&str>, expected_output: &str, )914         fn succeeds_with_increased_minimum_repetitions(
915             test_cases: Vec<&str>,
916             expected_output: &str,
917         ) {
918             let regexp = RegExpBuilder::from(&test_cases)
919                 .with_conversion_of_repetitions()
920                 .with_conversion_of_whitespace()
921                 .with_minimum_repetitions(2)
922                 .build();
923             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
924             assert_that_regexp_matches_test_cases(expected_output, test_cases);
925         }
926     }
927 }
928 
929 mod word_conversion {
930     use super::*;
931 
932     mod no_repetition {
933         use super::*;
934 
935         #[rstest(test_cases, expected_output,
936             case(vec![""], "^$"),
937             case(vec![" "], "^ $"),
938             case(vec!["a"], "^\\w$"),
939             case(vec!["1"], "^\\w$"),
940             case(vec!["-1"], "^\\-\\w$"),
941             case(vec!["1", "2"], "^\\w$"),
942             case(vec!["ä", "ß"], "^\\w$"),
943             case(vec!["abc", "1234"], "^\\w\\w\\w(?:\\w)?$"),
944             case(vec!["١", "٣", "٥"], "^\\w$"), // Arabic digits: ١ = 1, ٣ = 3, ٥ = 5
945             case(vec!["١٣٥"], "^\\w\\w\\w$"),
946             case(vec!["a٣3", "b5٥"], "^\\w\\w\\w$"),
947             case(vec!["I ♥ 123"], "^\\w ♥ \\w\\w\\w$"),
948             case(
949                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
950                 "^\\w   ♥♥♥ \\w\\w \\w\\w\\w \\w \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w ����\\.$"
951             )
952         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)953         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
954             let regexp = RegExpBuilder::from(&test_cases)
955                 .with_conversion_of_words()
956                 .build();
957             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
958             assert_that_regexp_matches_test_cases(expected_output, test_cases);
959         }
960 
961         #[rstest(test_cases, expected_output,
962             case(
963                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
964                 "^\\w   \\u{2665}\\u{2665}\\u{2665} \\w\\w \\w\\w\\w \\w \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w \\u{1f4a9}\\u{1f4a9}\\.$"
965             )
966         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)967         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
968             let regexp = RegExpBuilder::from(&test_cases)
969                 .with_conversion_of_words()
970                 .with_escaping_of_non_ascii_chars(false)
971                 .build();
972             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
973             assert_that_regexp_matches_test_cases(expected_output, test_cases);
974         }
975 
976         #[rstest(test_cases, expected_output,
977             case(
978                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
979                 "^\\w   \\u{2665}\\u{2665}\\u{2665} \\w\\w \\w\\w\\w \\w \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w \\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
980             )
981         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)982         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
983             let regexp = RegExpBuilder::from(&test_cases)
984                 .with_conversion_of_words()
985                 .with_escaping_of_non_ascii_chars(true)
986                 .build();
987             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
988         }
989     }
990 
991     mod repetition {
992         use super::*;
993 
994         #[rstest(test_cases, expected_output,
995             case(
996                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
997                 "^\\w {3}♥{3} \\w{2}(?: \\w{3} \\w){2}(?:\\w{3} ){2}��{2}\\.$"
998             )
999         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1000         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1001             let regexp = RegExpBuilder::from(&test_cases)
1002                 .with_conversion_of_repetitions()
1003                 .with_conversion_of_words()
1004                 .build();
1005             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1006             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1007         }
1008 
1009         #[rstest(test_cases, expected_output,
1010             case(
1011                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1012                 "^\\w {3}\\u{2665}{3} \\w{2}(?: \\w{3} \\w){2}(?:\\w{3} ){2}\\u{1f4a9}{2}\\.$"
1013             )
1014         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1015         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1016             let regexp = RegExpBuilder::from(&test_cases)
1017                 .with_conversion_of_repetitions()
1018                 .with_conversion_of_words()
1019                 .with_escaping_of_non_ascii_chars(false)
1020                 .build();
1021             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1022             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1023         }
1024 
1025         #[rstest(test_cases, expected_output,
1026             case(
1027                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1028                 "^\\w {3}\\u{2665}{3} \\w{2}(?: \\w{3} \\w){2}(?:\\w{3} ){2}(?:\\u{d83d}\\u{dca9}){2}\\.$"
1029             )
1030         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1031         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1032             let regexp = RegExpBuilder::from(&test_cases)
1033                 .with_conversion_of_repetitions()
1034                 .with_conversion_of_words()
1035                 .with_escaping_of_non_ascii_chars(true)
1036                 .build();
1037             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1038         }
1039 
1040         #[rstest(test_cases, expected_output,
1041             case(vec!["a"], "^\\w$"),
1042             case(vec!["ab"], "^\\w\\w$"),
1043             case(vec!["abc"], "^\\w{3}$"),
1044             case(vec!["a", "ab", "abc"], "^(?:\\w\\w|\\w|\\w{3})$"),
1045             case(vec!["ab", "abc", "abcd"], "^(?:\\w\\w|\\w{3,4})$"),
1046             case(vec!["abc", "abcd", "abcde"], "^\\w{3,5}$"),
1047             case(
1048                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1049                 "^\\w {3}♥{3} \\w\\w \\w{3} \\w \\w{3} \\w{4} \\w{3} ����\\.$"
1050             )
1051         )]
succeeds_with_increased_minimum_repetitions( test_cases: Vec<&str>, expected_output: &str, )1052         fn succeeds_with_increased_minimum_repetitions(
1053             test_cases: Vec<&str>,
1054             expected_output: &str,
1055         ) {
1056             let regexp = RegExpBuilder::from(&test_cases)
1057                 .with_conversion_of_repetitions()
1058                 .with_conversion_of_words()
1059                 .with_minimum_repetitions(2)
1060                 .build();
1061             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1062             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1063         }
1064     }
1065 }
1066 
1067 mod digit_space_conversion {
1068     use super::*;
1069 
1070     mod no_repetition {
1071         use super::*;
1072 
1073         #[rstest(test_cases, expected_output,
1074             case(
1075                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1076                 "^I\\s\\s\\s♥♥♥\\s\\d\\d\\sand\\s\\d\\sand\\sy̆y̆\\sand\\s����\\.$"
1077             )
1078         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1079         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1080             let regexp = RegExpBuilder::from(&test_cases)
1081                 .with_conversion_of_digits()
1082                 .with_conversion_of_whitespace()
1083                 .build();
1084             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1085             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1086         }
1087 
1088         #[rstest(test_cases, expected_output,
1089             case(
1090                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1091                 "^I\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\d\\d\\sand\\s\\d\\sand\\sy\\u{306}y\\u{306}\\sand\\s\\u{1f4a9}\\u{1f4a9}\\.$"
1092             )
1093         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1094         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1095             let regexp = RegExpBuilder::from(&test_cases)
1096                 .with_conversion_of_digits()
1097                 .with_conversion_of_whitespace()
1098                 .with_escaping_of_non_ascii_chars(false)
1099                 .build();
1100             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1101             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1102         }
1103 
1104         #[rstest(test_cases, expected_output,
1105             case(
1106                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1107                 "^I\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\d\\d\\sand\\s\\d\\sand\\sy\\u{306}y\\u{306}\\sand\\s\\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
1108             )
1109         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1110         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1111             let regexp = RegExpBuilder::from(&test_cases)
1112                 .with_conversion_of_digits()
1113                 .with_conversion_of_whitespace()
1114                 .with_escaping_of_non_ascii_chars(true)
1115                 .build();
1116             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1117         }
1118     }
1119 
1120     mod repetition {
1121         use super::*;
1122 
1123         #[rstest(test_cases, expected_output,
1124             case(
1125                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1126                 "^I\\s{3}♥{3}\\s\\d(?:\\d\\sand\\s){2}(?:y̆){2}\\sand\\s��{2}\\.$"
1127             )
1128         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1129         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1130             let regexp = RegExpBuilder::from(&test_cases)
1131                 .with_conversion_of_repetitions()
1132                 .with_conversion_of_digits()
1133                 .with_conversion_of_whitespace()
1134                 .build();
1135             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1136             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1137         }
1138 
1139         #[rstest(test_cases, expected_output,
1140             case(
1141                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1142                 "^I\\s{3}\\u{2665}{3}\\s\\d(?:\\d\\sand\\s){2}(?:y\\u{306}){2}\\sand\\s\\u{1f4a9}{2}\\.$"
1143             )
1144         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1145         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1146             let regexp = RegExpBuilder::from(&test_cases)
1147                 .with_conversion_of_repetitions()
1148                 .with_conversion_of_digits()
1149                 .with_conversion_of_whitespace()
1150                 .with_escaping_of_non_ascii_chars(false)
1151                 .build();
1152             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1153             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1154         }
1155 
1156         #[rstest(test_cases, expected_output,
1157             case(
1158                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1159                 "^I\\s{3}\\u{2665}{3}\\s\\d(?:\\d\\sand\\s){2}(?:y\\u{306}){2}\\sand\\s(?:\\u{d83d}\\u{dca9}){2}\\.$"
1160             )
1161         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1162         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1163             let regexp = RegExpBuilder::from(&test_cases)
1164                 .with_conversion_of_repetitions()
1165                 .with_conversion_of_digits()
1166                 .with_conversion_of_whitespace()
1167                 .with_escaping_of_non_ascii_chars(true)
1168                 .build();
1169             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1170         }
1171 
1172         #[rstest(test_cases, expected_output,
1173             case(vec!["1\n"], "^\\d\\s$"),
1174             case(vec!["1\n1\n"], "^\\d\\s\\d\\s$"),
1175             case(vec!["1\n1\n1\n"], "^(?:\\d\\s){3}$"),
1176             case(vec!["1\n", "1\n1\n", "1\n1\n1\n"], "^(?:\\d\\s\\d\\s|\\d\\s|(?:\\d\\s){3})$"),
1177             case(vec!["1\n1\n", "1\n1\n1\n", "1\n1\n1\n1\n"], "^(?:\\d\\s\\d\\s|(?:\\d\\s){3,4})$"),
1178             case(vec!["1\n1\n1\n", "1\n1\n1\n1\n", "1\n1\n1\n1\n1\n"], "^(?:\\d\\s){3,5}$"),
1179             case(
1180                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1181                 "^I\\s{3}♥{3}\\s\\d\\d\\sand\\s\\d\\sand\\sy̆y̆\\sand\\s����\\.$"
1182             )
1183         )]
succeeds_with_increased_minimum_repetitions( test_cases: Vec<&str>, expected_output: &str, )1184         fn succeeds_with_increased_minimum_repetitions(
1185             test_cases: Vec<&str>,
1186             expected_output: &str,
1187         ) {
1188             let regexp = RegExpBuilder::from(&test_cases)
1189                 .with_conversion_of_repetitions()
1190                 .with_conversion_of_digits()
1191                 .with_conversion_of_whitespace()
1192                 .with_minimum_repetitions(2)
1193                 .build();
1194             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1195             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1196         }
1197 
1198         #[rstest(test_cases, expected_output,
1199             case(vec!["1\n1\n"], "^1\\n1\\n$"),
1200             case(vec!["1\n\n1\n\n"], "^(?:1\\n\\n){2}$")
1201         )]
succeeds_with_increased_minimum_substring_length( test_cases: Vec<&str>, expected_output: &str, )1202         fn succeeds_with_increased_minimum_substring_length(
1203             test_cases: Vec<&str>,
1204             expected_output: &str,
1205         ) {
1206             let regexp = RegExpBuilder::from(&test_cases)
1207                 .with_conversion_of_repetitions()
1208                 .with_minimum_substring_length(3)
1209                 .build();
1210             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1211             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1212         }
1213 
1214         #[rstest(test_cases, expected_output,
1215             case(vec!["1\n1\n"], "^1\\n1\\n$"),
1216             case(vec!["1\n1\n1\n"], "^1\\n1\\n1\\n$"),
1217             case(vec!["1\n\n1\n\n"], "^1\\n\\n1\\n\\n$"),
1218             case(vec!["1\n\n1\n\n1\n\n"], "^(?:1\\n\\n){3}$")
1219         )]
succeeds_with_increased_minimum_repetitions_and_substring_length( test_cases: Vec<&str>, expected_output: &str, )1220         fn succeeds_with_increased_minimum_repetitions_and_substring_length(
1221             test_cases: Vec<&str>,
1222             expected_output: &str,
1223         ) {
1224             let regexp = RegExpBuilder::from(&test_cases)
1225                 .with_conversion_of_repetitions()
1226                 .with_minimum_repetitions(2)
1227                 .with_minimum_substring_length(3)
1228                 .build();
1229             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1230             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1231         }
1232     }
1233 }
1234 
1235 mod digit_word_conversion {
1236     use super::*;
1237 
1238     mod no_repetition {
1239         use super::*;
1240 
1241         #[rstest(test_cases, expected_output,
1242             case(
1243                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1244                 "^\\w   ♥♥♥ \\d\\d \\w\\w\\w \\d \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w ����\\.$"
1245             )
1246         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1247         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1248             let regexp = RegExpBuilder::from(&test_cases)
1249                 .with_conversion_of_digits()
1250                 .with_conversion_of_words()
1251                 .build();
1252             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1253             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1254         }
1255 
1256         #[rstest(test_cases, expected_output,
1257             case(
1258                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1259                 "^\\w   \\u{2665}\\u{2665}\\u{2665} \\d\\d \\w\\w\\w \\d \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w \\u{1f4a9}\\u{1f4a9}\\.$"
1260             )
1261         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1262         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1263             let regexp = RegExpBuilder::from(&test_cases)
1264                 .with_conversion_of_digits()
1265                 .with_conversion_of_words()
1266                 .with_escaping_of_non_ascii_chars(false)
1267                 .build();
1268             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1269             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1270         }
1271 
1272         #[rstest(test_cases, expected_output,
1273             case(
1274                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1275                 "^\\w   \\u{2665}\\u{2665}\\u{2665} \\d\\d \\w\\w\\w \\d \\w\\w\\w \\w\\w\\w\\w \\w\\w\\w \\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
1276             )
1277         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1278         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1279             let regexp = RegExpBuilder::from(&test_cases)
1280                 .with_conversion_of_digits()
1281                 .with_conversion_of_words()
1282                 .with_escaping_of_non_ascii_chars(true)
1283                 .build();
1284             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1285         }
1286     }
1287 
1288     mod repetition {
1289         use super::*;
1290 
1291         #[rstest(test_cases, expected_output,
1292             case(
1293                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1294                 "^\\w {3}♥{3} \\d(?:\\d \\w{3} ){2}\\w(?:\\w{3} ){2}��{2}\\.$"
1295             )
1296         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1297         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1298             let regexp = RegExpBuilder::from(&test_cases)
1299                 .with_conversion_of_repetitions()
1300                 .with_conversion_of_digits()
1301                 .with_conversion_of_words()
1302                 .build();
1303             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1304             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1305         }
1306 
1307         #[rstest(test_cases, expected_output,
1308             case(
1309                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1310                 "^\\w {3}\\u{2665}{3} \\d(?:\\d \\w{3} ){2}\\w(?:\\w{3} ){2}\\u{1f4a9}{2}\\.$"
1311             )
1312         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1313         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1314             let regexp = RegExpBuilder::from(&test_cases)
1315                 .with_conversion_of_repetitions()
1316                 .with_conversion_of_digits()
1317                 .with_conversion_of_words()
1318                 .with_escaping_of_non_ascii_chars(false)
1319                 .build();
1320             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1321             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1322         }
1323 
1324         #[rstest(test_cases, expected_output,
1325             case(
1326                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1327                 "^\\w {3}\\u{2665}{3} \\d(?:\\d \\w{3} ){2}\\w(?:\\w{3} ){2}(?:\\u{d83d}\\u{dca9}){2}\\.$"
1328             )
1329         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1330         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1331             let regexp = RegExpBuilder::from(&test_cases)
1332                 .with_conversion_of_repetitions()
1333                 .with_conversion_of_digits()
1334                 .with_conversion_of_words()
1335                 .with_escaping_of_non_ascii_chars(true)
1336                 .build();
1337             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1338         }
1339     }
1340 }
1341 
1342 mod space_word_conversion {
1343     use super::*;
1344 
1345     mod no_repetition {
1346         use super::*;
1347 
1348         #[rstest(test_cases, expected_output,
1349             case(
1350                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1351                 "^\\w\\s\\s\\s♥♥♥\\s\\w\\w\\s\\w\\w\\w\\s\\w\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s����\\.$"
1352             )
1353         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1354         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1355             let regexp = RegExpBuilder::from(&test_cases)
1356                 .with_conversion_of_whitespace()
1357                 .with_conversion_of_words()
1358                 .build();
1359             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1360             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1361         }
1362 
1363         #[rstest(test_cases, expected_output,
1364             case(
1365                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1366                 "^\\w\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\w\\w\\s\\w\\w\\w\\s\\w\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s\\u{1f4a9}\\u{1f4a9}\\.$"
1367             )
1368         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1369         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1370             let regexp = RegExpBuilder::from(&test_cases)
1371                 .with_conversion_of_whitespace()
1372                 .with_conversion_of_words()
1373                 .with_escaping_of_non_ascii_chars(false)
1374                 .build();
1375             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1376             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1377         }
1378 
1379         #[rstest(test_cases, expected_output,
1380             case(
1381                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1382                 "^\\w\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\w\\w\\s\\w\\w\\w\\s\\w\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s\\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
1383             )
1384         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1385         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1386             let regexp = RegExpBuilder::from(&test_cases)
1387                 .with_conversion_of_whitespace()
1388                 .with_conversion_of_words()
1389                 .with_escaping_of_non_ascii_chars(true)
1390                 .build();
1391             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1392         }
1393     }
1394 
1395     mod repetition {
1396         use super::*;
1397 
1398         #[rstest(test_cases, expected_output,
1399             case(
1400                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1401                 "^\\w\\s{3}♥{3}\\s\\w{2}(?:\\s\\w{3}\\s\\w){2}(?:\\w{3}\\s){2}��{2}\\.$"
1402             )
1403         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1404         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1405             let regexp = RegExpBuilder::from(&test_cases)
1406                 .with_conversion_of_repetitions()
1407                 .with_conversion_of_whitespace()
1408                 .with_conversion_of_words()
1409                 .build();
1410             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1411             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1412         }
1413 
1414         #[rstest(test_cases, expected_output,
1415             case(
1416                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1417                 "^\\w\\s{3}\\u{2665}{3}\\s\\w{2}(?:\\s\\w{3}\\s\\w){2}(?:\\w{3}\\s){2}\\u{1f4a9}{2}\\.$"
1418             )
1419         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1420         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1421             let regexp = RegExpBuilder::from(&test_cases)
1422                 .with_conversion_of_repetitions()
1423                 .with_conversion_of_whitespace()
1424                 .with_conversion_of_words()
1425                 .with_escaping_of_non_ascii_chars(false)
1426                 .build();
1427             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1428             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1429         }
1430 
1431         #[rstest(test_cases, expected_output,
1432             case(
1433                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1434                 "^\\w\\s{3}\\u{2665}{3}\\s\\w{2}(?:\\s\\w{3}\\s\\w){2}(?:\\w{3}\\s){2}(?:\\u{d83d}\\u{dca9}){2}\\.$"
1435             )
1436         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1437         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1438             let regexp = RegExpBuilder::from(&test_cases)
1439                 .with_conversion_of_repetitions()
1440                 .with_conversion_of_whitespace()
1441                 .with_conversion_of_words()
1442                 .with_escaping_of_non_ascii_chars(true)
1443                 .build();
1444             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1445         }
1446     }
1447 }
1448 
1449 mod digit_space_word_conversion {
1450     use super::*;
1451 
1452     mod no_repetition {
1453         use super::*;
1454 
1455         #[rstest(test_cases, expected_output,
1456             case(
1457                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1458                 "^\\w\\s\\s\\s♥♥♥\\s\\d\\d\\s\\w\\w\\w\\s\\d\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s����\\.$"
1459             )
1460         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1461         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1462             let regexp = RegExpBuilder::from(&test_cases)
1463                 .with_conversion_of_digits()
1464                 .with_conversion_of_whitespace()
1465                 .with_conversion_of_words()
1466                 .build();
1467             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1468             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1469         }
1470 
1471         #[rstest(test_cases, expected_output,
1472             case(
1473                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1474                 "^\\w\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\d\\d\\s\\w\\w\\w\\s\\d\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s\\u{1f4a9}\\u{1f4a9}\\.$"
1475             )
1476         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1477         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1478             let regexp = RegExpBuilder::from(&test_cases)
1479                 .with_conversion_of_digits()
1480                 .with_conversion_of_whitespace()
1481                 .with_conversion_of_words()
1482                 .with_escaping_of_non_ascii_chars(false)
1483                 .build();
1484             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1485             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1486         }
1487 
1488         #[rstest(test_cases, expected_output,
1489             case(
1490                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1491                 "^\\w\\s\\s\\s\\u{2665}\\u{2665}\\u{2665}\\s\\d\\d\\s\\w\\w\\w\\s\\d\\s\\w\\w\\w\\s\\w\\w\\w\\w\\s\\w\\w\\w\\s\\u{d83d}\\u{dca9}\\u{d83d}\\u{dca9}\\.$"
1492             )
1493         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1494         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1495             let regexp = RegExpBuilder::from(&test_cases)
1496                 .with_conversion_of_digits()
1497                 .with_conversion_of_whitespace()
1498                 .with_conversion_of_words()
1499                 .with_escaping_of_non_ascii_chars(true)
1500                 .build();
1501             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1502         }
1503     }
1504 
1505     mod repetition {
1506         use super::*;
1507 
1508         #[rstest(test_cases, expected_output,
1509             case(
1510                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1511                 "^\\w\\s{3}♥{3}\\s\\d(?:\\d\\s\\w{3}\\s){2}\\w(?:\\w{3}\\s){2}��{2}\\.$"
1512             )
1513         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1514         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1515             let regexp = RegExpBuilder::from(&test_cases)
1516                 .with_conversion_of_repetitions()
1517                 .with_conversion_of_digits()
1518                 .with_conversion_of_whitespace()
1519                 .with_conversion_of_words()
1520                 .build();
1521             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1522             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1523         }
1524 
1525         #[rstest(test_cases, expected_output,
1526             case(
1527                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1528                 "^\\w\\s{3}\\u{2665}{3}\\s\\d(?:\\d\\s\\w{3}\\s){2}\\w(?:\\w{3}\\s){2}\\u{1f4a9}{2}\\.$"
1529             )
1530         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1531         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1532             let regexp = RegExpBuilder::from(&test_cases)
1533                 .with_conversion_of_repetitions()
1534                 .with_conversion_of_digits()
1535                 .with_conversion_of_whitespace()
1536                 .with_conversion_of_words()
1537                 .with_escaping_of_non_ascii_chars(false)
1538                 .build();
1539             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1540             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1541         }
1542 
1543         #[rstest(test_cases, expected_output,
1544             case(
1545                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1546                 "^\\w\\s{3}\\u{2665}{3}\\s\\d(?:\\d\\s\\w{3}\\s){2}\\w(?:\\w{3}\\s){2}(?:\\u{d83d}\\u{dca9}){2}\\.$"
1547             )
1548         )]
succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str)1549         fn succeeds_with_escape_and_surrogate_option(test_cases: Vec<&str>, expected_output: &str) {
1550             let regexp = RegExpBuilder::from(&test_cases)
1551                 .with_conversion_of_repetitions()
1552                 .with_conversion_of_digits()
1553                 .with_conversion_of_whitespace()
1554                 .with_conversion_of_words()
1555                 .with_escaping_of_non_ascii_chars(true)
1556                 .build();
1557             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1558         }
1559     }
1560 }
1561 
1562 mod non_digit_conversion {
1563     use super::*;
1564 
1565     mod no_repetition {
1566         use super::*;
1567 
1568         #[rstest(test_cases, expected_output,
1569             case(
1570                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1571                 "^\\D\\D\\D\\D\\D\\D\\D\\D36\\D\\D\\D\\D\\D٣\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1572             )
1573         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1574         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1575             let regexp = RegExpBuilder::from(&test_cases)
1576                 .with_conversion_of_non_digits()
1577                 .build();
1578             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1579             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1580         }
1581 
1582         #[rstest(test_cases, expected_output,
1583             case(
1584                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1585                 "^\\D\\D\\D\\D\\D\\D\\D\\D36\\D\\D\\D\\D\\D\\u{663}\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1586             )
1587         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1588         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1589             let regexp = RegExpBuilder::from(&test_cases)
1590                 .with_conversion_of_non_digits()
1591                 .with_escaping_of_non_ascii_chars(false)
1592                 .build();
1593             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1594             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1595         }
1596     }
1597 
1598     mod repetition {
1599         use super::*;
1600 
1601         #[rstest(test_cases, expected_output,
1602             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}36\\D{5}٣\\D{17}$")
1603         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1604         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1605             let regexp = RegExpBuilder::from(&test_cases)
1606                 .with_conversion_of_repetitions()
1607                 .with_conversion_of_non_digits()
1608                 .build();
1609             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1610             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1611         }
1612 
1613         #[rstest(test_cases, expected_output,
1614             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}36\\D{5}\\u{663}\\D{17}$")
1615         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1616         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1617             let regexp = RegExpBuilder::from(&test_cases)
1618                 .with_conversion_of_repetitions()
1619                 .with_conversion_of_non_digits()
1620                 .with_escaping_of_non_ascii_chars(false)
1621                 .build();
1622             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1623             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1624         }
1625     }
1626 }
1627 
1628 mod non_space_conversion {
1629     use super::*;
1630 
1631     mod no_repetition {
1632         use super::*;
1633 
1634         #[rstest(test_cases, expected_output,
1635             case(
1636                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1637                 "^\\S   \\S\\S\\S \\S\\S \\S\\S\\S \\S \\S\\S\\S \\S\\S\\S\\S \\S\\S\\S \\S\\S\\S$"
1638             )
1639         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1640         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1641             let regexp = RegExpBuilder::from(&test_cases)
1642                 .with_conversion_of_non_whitespace()
1643                 .build();
1644             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1645             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1646         }
1647     }
1648 
1649     mod repetition {
1650         use super::*;
1651 
1652         #[rstest(test_cases, expected_output,
1653             case(
1654                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1655                 "^\\S {3}\\S(?:\\S{2} ){2}\\S{3} (?:\\S(?: \\S{3}){2}){2}$"
1656             )
1657         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1658         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1659             let regexp = RegExpBuilder::from(&test_cases)
1660                 .with_conversion_of_repetitions()
1661                 .with_conversion_of_non_whitespace()
1662                 .build();
1663             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1664             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1665         }
1666     }
1667 }
1668 
1669 mod non_word_conversion {
1670     use super::*;
1671 
1672     mod no_repetition {
1673         use super::*;
1674 
1675         #[rstest(test_cases, expected_output,
1676             case(
1677                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1678                 "^I\\W\\W\\W\\W\\W\\W\\W36\\Wand\\W٣\\Wand\\Wy̆y̆\\Wand\\W\\W\\W\\W$"
1679             )
1680         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1681         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1682             let regexp = RegExpBuilder::from(&test_cases)
1683                 .with_conversion_of_non_words()
1684                 .build();
1685             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1686             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1687         }
1688 
1689         #[rstest(test_cases, expected_output,
1690             case(
1691                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1692                 "^I\\W\\W\\W\\W\\W\\W\\W36\\Wand\\W\\u{663}\\Wand\\Wy\\u{306}y\\u{306}\\Wand\\W\\W\\W\\W$"
1693             )
1694         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1695         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1696             let regexp = RegExpBuilder::from(&test_cases)
1697                 .with_conversion_of_non_words()
1698                 .with_escaping_of_non_ascii_chars(false)
1699                 .build();
1700             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1701             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1702         }
1703     }
1704 
1705     mod repetition {
1706         use super::*;
1707 
1708         #[rstest(test_cases, expected_output,
1709             case(
1710                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1711                 "^I\\W{7}36\\Wand\\W٣\\Wand\\W(?:y̆){2}\\Wand\\W{4}$"
1712             )
1713         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1714         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1715             let regexp = RegExpBuilder::from(&test_cases)
1716                 .with_conversion_of_repetitions()
1717                 .with_conversion_of_non_words()
1718                 .build();
1719             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1720             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1721         }
1722 
1723         #[rstest(test_cases, expected_output,
1724             case(
1725                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1726                 "^I\\W{7}36\\Wand\\W\\u{663}\\Wand\\W(?:y\\u{306}){2}\\Wand\\W{4}$"
1727             )
1728         )]
succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str)1729         fn succeeds_with_escape_option(test_cases: Vec<&str>, expected_output: &str) {
1730             let regexp = RegExpBuilder::from(&test_cases)
1731                 .with_conversion_of_repetitions()
1732                 .with_conversion_of_non_words()
1733                 .with_escaping_of_non_ascii_chars(false)
1734                 .build();
1735             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1736             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1737         }
1738     }
1739 }
1740 
1741 mod non_digit_non_space_conversion {
1742     use super::*;
1743 
1744     mod no_repetition {
1745         use super::*;
1746 
1747         #[rstest(test_cases, expected_output,
1748             case(
1749                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1750                 "^\\D\\D\\D\\D\\D\\D\\D\\D\\S\\S\\D\\D\\D\\D\\D\\S\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1751             )
1752         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1753         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1754             let regexp = RegExpBuilder::from(&test_cases)
1755                 .with_conversion_of_non_digits()
1756                 .with_conversion_of_non_whitespace()
1757                 .build();
1758             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1759             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1760         }
1761     }
1762 
1763     mod repetition {
1764         use super::*;
1765 
1766         #[rstest(test_cases, expected_output,
1767             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}\\S{2}\\D{5}\\S\\D{17}$")
1768         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1769         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1770             let regexp = RegExpBuilder::from(&test_cases)
1771                 .with_conversion_of_repetitions()
1772                 .with_conversion_of_non_digits()
1773                 .with_conversion_of_non_whitespace()
1774                 .build();
1775             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1776             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1777         }
1778     }
1779 }
1780 
1781 mod non_digit_non_word_conversion {
1782     use super::*;
1783 
1784     mod no_repetition {
1785         use super::*;
1786 
1787         #[rstest(test_cases, expected_output,
1788             case(
1789                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1790                 "^\\D\\D\\D\\D\\D\\D\\D\\D36\\D\\D\\D\\D\\D٣\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1791             )
1792         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1793         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1794             let regexp = RegExpBuilder::from(&test_cases)
1795                 .with_conversion_of_non_digits()
1796                 .with_conversion_of_non_words()
1797                 .build();
1798             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1799             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1800         }
1801     }
1802 
1803     mod repetition {
1804         use super::*;
1805 
1806         #[rstest(test_cases, expected_output,
1807             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}36\\D{5}٣\\D{17}$")
1808         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1809         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1810             let regexp = RegExpBuilder::from(&test_cases)
1811                 .with_conversion_of_repetitions()
1812                 .with_conversion_of_non_digits()
1813                 .with_conversion_of_non_words()
1814                 .build();
1815             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1816             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1817         }
1818     }
1819 }
1820 
1821 mod non_space_non_word_conversion {
1822     use super::*;
1823 
1824     mod no_repetition {
1825         use super::*;
1826 
1827         #[rstest(test_cases, expected_output,
1828             case(
1829                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1830                 "^\\S\\W\\W\\W\\W\\W\\W\\W\\S\\S\\W\\S\\S\\S\\W\\S\\W\\S\\S\\S\\W\\S\\S\\S\\S\\W\\S\\S\\S\\W\\W\\W\\W$"
1831             )
1832         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1833         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1834             let regexp = RegExpBuilder::from(&test_cases)
1835                 .with_conversion_of_non_whitespace()
1836                 .with_conversion_of_non_words()
1837                 .build();
1838             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1839             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1840         }
1841     }
1842 
1843     mod repetition {
1844         use super::*;
1845 
1846         #[rstest(test_cases, expected_output,
1847             case(
1848                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1849                 "^\\S\\W{7}\\S(?:\\S\\W\\S{3}\\W){2}\\S{4}\\W\\S{3}\\W{4}$"
1850             )
1851         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1852         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1853             let regexp = RegExpBuilder::from(&test_cases)
1854                 .with_conversion_of_repetitions()
1855                 .with_conversion_of_non_whitespace()
1856                 .with_conversion_of_non_words()
1857                 .build();
1858             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1859             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1860         }
1861     }
1862 }
1863 
1864 mod non_digit_non_space_non_word_conversion {
1865     use super::*;
1866 
1867     mod no_repetition {
1868         use super::*;
1869 
1870         #[rstest(test_cases, expected_output,
1871             case(
1872                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1873                 "^\\D\\D\\D\\D\\D\\D\\D\\D\\S\\S\\D\\D\\D\\D\\D\\S\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1874             )
1875         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1876         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1877             let regexp = RegExpBuilder::from(&test_cases)
1878                 .with_conversion_of_non_digits()
1879                 .with_conversion_of_non_whitespace()
1880                 .with_conversion_of_non_words()
1881                 .build();
1882             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1883             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1884         }
1885     }
1886 
1887     mod repetition {
1888         use super::*;
1889 
1890         #[rstest(test_cases, expected_output,
1891             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}\\S{2}\\D{5}\\S\\D{17}$")
1892         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1893         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1894             let regexp = RegExpBuilder::from(&test_cases)
1895                 .with_conversion_of_repetitions()
1896                 .with_conversion_of_non_digits()
1897                 .with_conversion_of_non_whitespace()
1898                 .with_conversion_of_non_words()
1899                 .build();
1900             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1901             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1902         }
1903     }
1904 }
1905 
1906 mod digit_non_digit_conversion {
1907     use super::*;
1908 
1909     mod no_repetition {
1910         use super::*;
1911 
1912         #[rstest(test_cases, expected_output,
1913             case(
1914                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1915                 "^\\D\\D\\D\\D\\D\\D\\D\\D\\d\\d\\D\\D\\D\\D\\D\\d\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D\\D$"
1916             )
1917         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1918         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1919             let regexp = RegExpBuilder::from(&test_cases)
1920                 .with_conversion_of_digits()
1921                 .with_conversion_of_non_digits()
1922                 .build();
1923             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1924             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1925         }
1926     }
1927 
1928     mod repetition {
1929         use super::*;
1930 
1931         #[rstest(test_cases, expected_output,
1932             case(vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."], "^\\D{8}\\d{2}\\D{5}\\d\\D{17}$")
1933         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1934         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1935             let regexp = RegExpBuilder::from(&test_cases)
1936                 .with_conversion_of_repetitions()
1937                 .with_conversion_of_digits()
1938                 .with_conversion_of_non_digits()
1939                 .build();
1940             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1941             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1942         }
1943     }
1944 }
1945 
1946 mod space_non_space_conversion {
1947     use super::*;
1948 
1949     mod no_repetition {
1950         use super::*;
1951 
1952         #[rstest(test_cases, expected_output,
1953             case(
1954                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1955                 "^\\S\\s\\s\\s\\S\\S\\S\\s\\S\\S\\s\\S\\S\\S\\s\\S\\s\\S\\S\\S\\s\\S\\S\\S\\S\\s\\S\\S\\S\\s\\S\\S\\S$"
1956             )
1957         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1958         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1959             let regexp = RegExpBuilder::from(&test_cases)
1960                 .with_conversion_of_whitespace()
1961                 .with_conversion_of_non_whitespace()
1962                 .build();
1963             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1964             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1965         }
1966     }
1967 
1968     mod repetition {
1969         use super::*;
1970 
1971         #[rstest(test_cases, expected_output,
1972             case(
1973                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1974                 "^\\S\\s{3}\\S(?:\\S{2}\\s){2}\\S{3}\\s(?:\\S(?:\\s\\S{3}){2}){2}$"
1975             )
1976         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)1977         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
1978             let regexp = RegExpBuilder::from(&test_cases)
1979                 .with_conversion_of_repetitions()
1980                 .with_conversion_of_whitespace()
1981                 .with_conversion_of_non_whitespace()
1982                 .build();
1983             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
1984             assert_that_regexp_matches_test_cases(expected_output, test_cases);
1985         }
1986     }
1987 }
1988 
1989 mod word_non_word_conversion {
1990     use super::*;
1991 
1992     mod no_repetition {
1993         use super::*;
1994 
1995         #[rstest(test_cases, expected_output,
1996             case(
1997                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
1998                 "^\\w\\W\\W\\W\\W\\W\\W\\W\\w\\w\\W\\w\\w\\w\\W\\w\\W\\w\\w\\w\\W\\w\\w\\w\\w\\W\\w\\w\\w\\W\\W\\W\\W$"
1999             )
2000         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)2001         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
2002             let regexp = RegExpBuilder::from(&test_cases)
2003                 .with_conversion_of_words()
2004                 .with_conversion_of_non_words()
2005                 .build();
2006             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2007             assert_that_regexp_matches_test_cases(expected_output, test_cases);
2008         }
2009     }
2010 
2011     mod repetition {
2012         use super::*;
2013 
2014         #[rstest(test_cases, expected_output,
2015             case(
2016                 vec!["I   ♥♥♥ 36 and ٣ and y̆y̆ and ����."],
2017                 "^\\w\\W{7}\\w(?:\\w\\W\\w{3}\\W){2}\\w{4}\\W\\w{3}\\W{4}$"
2018             )
2019         )]
succeeds(test_cases: Vec<&str>, expected_output: &str)2020         fn succeeds(test_cases: Vec<&str>, expected_output: &str) {
2021             let regexp = RegExpBuilder::from(&test_cases)
2022                 .with_conversion_of_repetitions()
2023                 .with_conversion_of_words()
2024                 .with_conversion_of_non_words()
2025                 .build();
2026             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2027             assert_that_regexp_matches_test_cases(expected_output, test_cases);
2028         }
2029     }
2030 }
2031 
2032 mod anchor_conversion {
2033     use super::*;
2034 
2035     mod no_verbose {
2036         use super::*;
2037 
2038         #[rstest(test_cases, expected_output,
2039             case(vec!["My ♥♥♥ and ���� is yours."], "My ♥♥♥ and ���� is yours\\.$"),
2040         )]
succeeds_with_no_start_anchor_option(test_cases: Vec<&str>, expected_output: &str)2041         fn succeeds_with_no_start_anchor_option(test_cases: Vec<&str>, expected_output: &str) {
2042             let regexp = RegExpBuilder::from(&test_cases)
2043                 .without_start_anchor()
2044                 .build();
2045             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2046         }
2047 
2048         #[rstest(test_cases, expected_output,
2049             case(vec!["My ♥♥♥ and ���� is yours."], "^My ♥♥♥ and ���� is yours\\."),
2050         )]
succeeds_with_no_end_anchor_option(test_cases: Vec<&str>, expected_output: &str)2051         fn succeeds_with_no_end_anchor_option(test_cases: Vec<&str>, expected_output: &str) {
2052             let regexp = RegExpBuilder::from(&test_cases)
2053                 .without_end_anchor()
2054                 .build();
2055             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2056         }
2057 
2058         #[rstest(test_cases, expected_output,
2059             case(vec!["My ♥♥♥ and ���� is yours."], "My ♥♥♥ and ���� is yours\\."),
2060         )]
succeeds_with_no_match_line_option(test_cases: Vec<&str>, expected_output: &str)2061         fn succeeds_with_no_match_line_option(test_cases: Vec<&str>, expected_output: &str) {
2062             let regexp = RegExpBuilder::from(&test_cases).without_anchors().build();
2063             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2064         }
2065     }
2066 
2067     mod verbose {
2068         use super::*;
2069 
2070         #[rstest(test_cases, expected_output,
2071             case(vec!["My ♥♥♥ and ���� is yours."], indoc!(
2072                 r#"
2073                 (?x)
2074                   My\ ♥♥♥\ and\ ����\ is\ yours\.
2075                 $"#
2076             ))
2077         )]
succeeds_with_verbose_mode_and_no_start_anchor_option( test_cases: Vec<&str>, expected_output: &str, )2078         fn succeeds_with_verbose_mode_and_no_start_anchor_option(
2079             test_cases: Vec<&str>,
2080             expected_output: &str,
2081         ) {
2082             let regexp = RegExpBuilder::from(&test_cases)
2083                 .with_verbose_mode()
2084                 .without_start_anchor()
2085                 .build();
2086             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2087         }
2088 
2089         #[rstest(test_cases, expected_output,
2090             case(vec!["My ♥♥♥ and ���� is yours."], indoc!(
2091                 r#"
2092                 (?x)
2093                 ^
2094                   My\ ♥♥♥\ and\ ����\ is\ yours\."#
2095             ))
2096         )]
succeeds_with_verbose_mode_and_no_end_anchor_option( test_cases: Vec<&str>, expected_output: &str, )2097         fn succeeds_with_verbose_mode_and_no_end_anchor_option(
2098             test_cases: Vec<&str>,
2099             expected_output: &str,
2100         ) {
2101             let regexp = RegExpBuilder::from(&test_cases)
2102                 .with_verbose_mode()
2103                 .without_end_anchor()
2104                 .build();
2105             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2106         }
2107 
2108         #[rstest(test_cases, expected_output,
2109             case(vec!["My ♥♥♥ and ���� is yours."], indoc!(
2110                 r#"
2111                 (?x)
2112                   My\ ♥♥♥\ and\ ����\ is\ yours\."#
2113             ))
2114         )]
succeeds_with_verbose_mode_and_no_anchors_option( test_cases: Vec<&str>, expected_output: &str, )2115         fn succeeds_with_verbose_mode_and_no_anchors_option(
2116             test_cases: Vec<&str>,
2117             expected_output: &str,
2118         ) {
2119             let regexp = RegExpBuilder::from(&test_cases)
2120                 .with_verbose_mode()
2121                 .without_anchors()
2122                 .build();
2123             assert_that_regexp_is_correct(regexp, expected_output, &test_cases);
2124         }
2125     }
2126 }
2127 
assert_that_regexp_is_correct(regexp: String, expected_output: &str, test_cases: &[&str])2128 fn assert_that_regexp_is_correct(regexp: String, expected_output: &str, test_cases: &[&str]) {
2129     assert_eq!(
2130         regexp, expected_output,
2131         "\n\ninput: {:?}\nexpected: {}\nactual: {}\n\n",
2132         test_cases, expected_output, regexp
2133     );
2134 }
2135 
assert_that_regexp_matches_test_cases(expected_output: &str, test_cases: Vec<&str>)2136 fn assert_that_regexp_matches_test_cases(expected_output: &str, test_cases: Vec<&str>) {
2137     let re = Regex::new(expected_output).unwrap();
2138     for test_case in test_cases {
2139         assert_eq!(
2140             re.find_iter(test_case).count(),
2141             1,
2142             "\n\n\"{}\" does not match regex {}\n\n",
2143             test_case,
2144             expected_output
2145         );
2146     }
2147 }
2148