1 package regexp2
2
3 import (
4 "fmt"
5 "reflect"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/dlclark/regexp2/syntax"
11 )
12
13 func TestBacktrack_CatastrophicTimeout(t *testing.T) {
14 r, err := Compile("(.+)*\\?", 0)
15 if err != nil {
16 t.Fatal(err)
17 }
18 t.Logf("code dump: %v", r.code.Dump())
19 const subject = "Do you think you found the problem string!"
20
21 const earlyAllowance = 10 * time.Millisecond
22 var lateAllowance = clockPeriod + 500*time.Millisecond
23
24 for _, timeout := range []time.Duration{
25 -1 * time.Millisecond,
26 0 * time.Millisecond,
27 1 * time.Millisecond,
28 10 * time.Millisecond,
29 100 * time.Millisecond,
30 500 * time.Millisecond,
31 1000 * time.Millisecond,
32 } {
33 t.Run(fmt.Sprint(timeout), func(t *testing.T) {
34 r.MatchTimeout = timeout
35 start := time.Now()
36 m, err := r.FindStringMatch(subject)
37 elapsed := time.Since(start)
38 if err == nil {
39 t.Errorf("expected timeout err")
40 }
41 if m != nil {
42 t.Errorf("Expected no match")
43 }
44 t.Logf("timeed out after %v", elapsed)
45 if elapsed < timeout-earlyAllowance {
46 t.Errorf("Match timed out too quickly (%v instead of expected %v)", elapsed, timeout-earlyAllowance)
47 }
48 if elapsed > timeout+lateAllowance {
49 t.Errorf("Match timed out too late (%v instead of expected %v)", elapsed, timeout+lateAllowance)
50 }
51 })
52 }
53 }
54
55 func TestSetPrefix(t *testing.T) {
56 r := MustCompile(`^\s*-TEST`, 0)
57 if r.code.FcPrefix == nil {
58 t.Fatalf("Expected prefix set [-\\s] but was nil")
59 }
60 if r.code.FcPrefix.PrefixSet.String() != "[-\\s]" {
61 t.Fatalf("Expected prefix set [\\s-] but was %v", r.code.FcPrefix.PrefixSet.String())
62 }
63 }
64
65 func TestSetInCode(t *testing.T) {
66 r := MustCompile(`(?<body>\s*(?<name>.+))`, 0)
67 t.Logf("code dump: %v", r.code.Dump())
68 if want, got := 1, len(r.code.Sets); want != got {
69 t.Fatalf("r.code.Sets wanted %v, got %v", want, got)
70 }
71 if want, got := "[\\s]", r.code.Sets[0].String(); want != got {
72 t.Fatalf("first set wanted %v, got %v", want, got)
73 }
74 }
75
76 func TestRegexp_Basic(t *testing.T) {
77 r, err := Compile("test(?<named>ing)?", 0)
78
79
80 if err != nil {
81 t.Errorf("unexpected compile err: %v", err)
82 }
83 m, err := r.FindStringMatch("this is a testing stuff")
84 if err != nil {
85 t.Errorf("unexpected match err: %v", err)
86 }
87 if m == nil {
88 t.Error("Nil match, expected success")
89 } else {
90
91 }
92 }
93
94
95 func TestCapture_Basic(t *testing.T) {
96 r := MustCompile(`.*\B(SUCCESS)\B.*`, 0)
97 m, err := r.FindStringMatch("adfadsfSUCCESSadsfadsf")
98 if err != nil {
99 t.Fatalf("Unexpected match error: %v", err)
100 }
101
102 if m == nil {
103 t.Fatalf("Should have matched")
104 }
105 if want, got := "adfadsfSUCCESSadsfadsf", m.String(); want != got {
106 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
107 }
108 if want, got := 0, m.Index; want != got {
109 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
110 }
111 if want, got := 22, m.Length; want != got {
112 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
113 }
114 if want, got := 1, len(m.Captures); want != got {
115 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
116 }
117
118 if want, got := m.String(), m.Captures[0].String(); want != got {
119 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
120 }
121 if want, got := 0, m.Captures[0].Index; want != got {
122 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
123 }
124 if want, got := 22, m.Captures[0].Length; want != got {
125 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
126 }
127
128 g := m.Groups()
129 if want, got := 2, len(g); want != got {
130 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
131 }
132
133 if want, got := m.String(), g[0].String(); want != got {
134 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
135 }
136 if want, got := 1, len(g[0].Captures); want != got {
137 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
138 }
139
140 if want, got := m.Captures[0].String(), g[0].Captures[0].String(); want != got {
141 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
142 }
143
144
145 if want, got := 7, g[1].Index; want != got {
146 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
147 }
148 if want, got := 7, g[1].Length; want != got {
149 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
150 }
151 if want, got := "SUCCESS", g[1].String(); want != got {
152 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
153 }
154 }
155
156 func TestEscapeUnescape_Basic(t *testing.T) {
157 s1 := "#$^*+(){}<>\\|. "
158 s2 := Escape(s1)
159 s3, err := Unescape(s2)
160 if err != nil {
161 t.Fatalf("Unexpected error during unescape: %v", err)
162 }
163
164
165 if want, got := `\#\$\^\*\+\(\)\{\}<>\\\|\.\ `, s2; want != got {
166 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
167 }
168
169
170 if want, got := s1, s3; want != got {
171 t.Fatalf("Wanted '%v'\nGot '%v'", want, got)
172 }
173
174 }
175
176 func TestGroups_Basic(t *testing.T) {
177 type d struct {
178 p string
179 s string
180 name []string
181 num []int
182 strs []string
183 }
184 data := []d{
185 d{"(?<first_name>\\S+)\\s(?<last_name>\\S+)",
186 "Ryan Byington",
187 []string{"0", "first_name", "last_name"},
188 []int{0, 1, 2},
189 []string{"Ryan Byington", "Ryan", "Byington"}},
190 d{"((?<One>abc)\\d+)?(?<Two>xyz)(.*)",
191 "abc208923xyzanqnakl",
192 []string{"0", "1", "2", "One", "Two"},
193 []int{0, 1, 2, 3, 4},
194 []string{"abc208923xyzanqnakl", "abc208923", "anqnakl", "abc", "xyz"}},
195 d{"((?<256>abc)\\d+)?(?<16>xyz)(.*)",
196 "0272saasdabc8978xyz][]12_+-",
197 []string{"0", "1", "2", "16", "256"},
198 []int{0, 1, 2, 16, 256},
199 []string{"abc8978xyz][]12_+-", "abc8978", "][]12_+-", "xyz", "abc"}},
200 d{"((?<4>abc)(?<digits>\\d+))?(?<2>xyz)(?<everything_else>.*)",
201 "0272saasdabc8978xyz][]12_+-",
202 []string{"0", "1", "2", "digits", "4", "everything_else"},
203 []int{0, 1, 2, 3, 4, 5},
204 []string{"abc8978xyz][]12_+-", "abc8978", "xyz", "8978", "abc", "][]12_+-"}},
205 d{"(?<first_name>\\S+)\\s(?<first_name>\\S+)",
206 "Ryan Byington",
207 []string{"0", "first_name"},
208 []int{0, 1},
209 []string{"Ryan Byington", "Byington"}},
210 d{"(?<15>\\S+)\\s(?<15>\\S+)",
211 "Ryan Byington",
212 []string{"0", "15"},
213 []int{0, 15},
214 []string{"Ryan Byington", "Byington"}},
215
216 d{"(?'first_name'\\S+)\\s(?'last_name'\\S+)",
217 "Ryan Byington",
218 []string{"0", "first_name", "last_name"},
219 []int{0, 1, 2},
220 []string{"Ryan Byington", "Ryan", "Byington"}},
221 d{"((?'One'abc)\\d+)?(?'Two'xyz)(.*)",
222 "abc208923xyzanqnakl",
223 []string{"0", "1", "2", "One", "Two"},
224 []int{0, 1, 2, 3, 4},
225 []string{"abc208923xyzanqnakl", "abc208923", "anqnakl", "abc", "xyz"}},
226 d{"((?'256'abc)\\d+)?(?'16'xyz)(.*)",
227 "0272saasdabc8978xyz][]12_+-",
228 []string{"0", "1", "2", "16", "256"},
229 []int{0, 1, 2, 16, 256},
230 []string{"abc8978xyz][]12_+-", "abc8978", "][]12_+-", "xyz", "abc"}},
231 d{"((?'4'abc)(?'digits'\\d+))?(?'2'xyz)(?'everything_else'.*)",
232 "0272saasdabc8978xyz][]12_+-",
233 []string{"0", "1", "2", "digits", "4", "everything_else"},
234 []int{0, 1, 2, 3, 4, 5},
235 []string{"abc8978xyz][]12_+-", "abc8978", "xyz", "8978", "abc", "][]12_+-"}},
236 d{"(?'first_name'\\S+)\\s(?'first_name'\\S+)",
237 "Ryan Byington",
238 []string{"0", "first_name"},
239 []int{0, 1},
240 []string{"Ryan Byington", "Byington"}},
241 d{"(?'15'\\S+)\\s(?'15'\\S+)",
242 "Ryan Byington",
243 []string{"0", "15"},
244 []int{0, 15},
245 []string{"Ryan Byington", "Byington"}},
246 }
247
248 fatalf := func(re *Regexp, v d, format string, args ...interface{}) {
249 args = append(args, v, re.code.Dump())
250
251 t.Fatalf(format+" using test data: %#v\ndump:%v", args...)
252 }
253
254 validateGroupNamesNumbers := func(re *Regexp, v d) {
255 if len(v.name) != len(v.num) {
256 fatalf(re, v, "Invalid data, group name count and number count must match")
257 }
258
259 groupNames := re.GetGroupNames()
260 if !reflect.DeepEqual(groupNames, v.name) {
261 fatalf(re, v, "group names expected: %v, actual: %v", v.name, groupNames)
262 }
263 groupNums := re.GetGroupNumbers()
264 if !reflect.DeepEqual(groupNums, v.num) {
265 fatalf(re, v, "group numbers expected: %v, actual: %v", v.num, groupNums)
266 }
267
268 for i := range groupNums {
269 if want, got := groupNums[i], re.GroupNumberFromName(groupNames[i]); want != got {
270 fatalf(re, v, "group num from name Wanted '%v'\nGot '%v'", want, got)
271 }
272 if want, got := groupNames[i], re.GroupNameFromNumber(groupNums[i]); want != got {
273 fatalf(re, v, "group name from num Wanted '%v'\nGot '%v'", want, got)
274 }
275 }
276 }
277
278 for _, v := range data {
279
280 re := MustCompile(v.p, 0)
281
282
283 validateGroupNamesNumbers(re, v)
284
285 m, err := re.FindStringMatch(v.s)
286 if err != nil {
287 fatalf(re, v, "Unexpected error in match: %v", err)
288 }
289 if m == nil {
290 fatalf(re, v, "Match is nil")
291 }
292 if want, got := len(v.strs), m.GroupCount(); want != got {
293 fatalf(re, v, "GroupCount() Wanted '%v'\nGot '%v'", want, got)
294 }
295 g := m.Groups()
296 if want, got := len(v.strs), len(g); want != got {
297 fatalf(re, v, "len(m.Groups()) Wanted '%v'\nGot '%v'", want, got)
298 }
299
300 for i := range v.name {
301 grp1 := m.GroupByName(v.name[i])
302 grp2 := m.GroupByNumber(v.num[i])
303
304 if grp1 != grp2 {
305 fatalf(re, v, "Expected GroupByName and GroupByNumber to return same result for %v, %v", v.name[i], v.num[i])
306 }
307 if want, got := v.strs[i], grp1.String(); want != got {
308 fatalf(re, v, "Value[%v] Wanted '%v'\nGot '%v'", i, want, got)
309 }
310 }
311
312
313 validateGroupNamesNumbers(re, v)
314 }
315 }
316
317 func TestErr_GroupName(t *testing.T) {
318
319 if _, err := Compile("foo(?<0>bar)", 0); err == nil {
320 t.Fatalf("zero group, expected error during compile")
321 } else if want, got := "error parsing regexp: capture number cannot be zero in `foo(?<0>bar)`", err.Error(); want != got {
322 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
323 }
324 if _, err := Compile("foo(?'0'bar)", 0); err == nil {
325 t.Fatalf("zero group, expected error during compile")
326 } else if want, got := "error parsing regexp: capture number cannot be zero in `foo(?'0'bar)`", err.Error(); want != got {
327 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
328 }
329
330
331 if _, err := Compile("foo(?<1bar>)", 0); err == nil {
332 t.Fatalf("invalid group name, expected error during compile")
333 } else if want, got := "error parsing regexp: invalid group name: group names must begin with a word character and have a matching terminator in `foo(?<1bar>)`", err.Error(); want != got {
334 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
335 }
336 if _, err := Compile("foo(?'1bar')", 0); err == nil {
337 t.Fatalf("invalid group name, expected error during compile")
338 } else if want, got := "error parsing regexp: invalid group name: group names must begin with a word character and have a matching terminator in `foo(?'1bar')`", err.Error(); want != got {
339 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
340 }
341
342
343 if _, err := Compile("foo(?<bar)", 0); err == nil {
344 t.Fatalf("invalid group name, expected error during compile")
345 } else if want, got := "error parsing regexp: invalid group name: group names must begin with a word character and have a matching terminator in `foo(?<bar)`", err.Error(); want != got {
346 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
347 }
348 if _, err := Compile("foo(?'bar)", 0); err == nil {
349 t.Fatalf("invalid group name, expected error during compile")
350 } else if want, got := "error parsing regexp: invalid group name: group names must begin with a word character and have a matching terminator in `foo(?'bar)`", err.Error(); want != got {
351 t.Fatalf("invalid error text, want '%v', got '%v'", want, got)
352 }
353
354 }
355
356 func TestConstantUneffected(t *testing.T) {
357
358
359 re := MustCompile(`(\s|\*)test\s`, 0)
360 if want, got := 2, len(re.code.Sets); want != got {
361 t.Fatalf("wanted %v sets, got %v", want, got)
362 }
363 if want, got := "[\\*\\s]", re.code.Sets[0].String(); want != got {
364 t.Fatalf("wanted set 0 %v, got %v", want, got)
365 }
366 if want, got := "[\\s]", re.code.Sets[1].String(); want != got {
367 t.Fatalf("wanted set 1 %v, got %v", want, got)
368 }
369 }
370
371 func TestAlternationConstAndEscape(t *testing.T) {
372 re := MustCompile(`\:|\s`, 0)
373 if want, got := 1, len(re.code.Sets); want != got {
374 t.Fatalf("wanted %v sets, got %v", want, got)
375 }
376 if want, got := "[:\\s]", re.code.Sets[0].String(); want != got {
377 t.Fatalf("wanted set 0 %v, got %v", want, got)
378 }
379 }
380
381 func TestStartingCharsOptionalNegate(t *testing.T) {
382
383
384
385
386
387
388
389
390
391
392
393 re := MustCompile(`(^(\S{2} )?\S{2}(\d+|/) *\S{3}\S{3} ?\d{2,4}[A-Z] ?\d{2}[A-Z]{3}|(\S{2} )?\d{2,4})`, 0)
394 if re.code.FcPrefix != nil {
395 t.Fatalf("FcPrefix wanted nil, got %v", re.code.FcPrefix)
396 }
397 }
398
399 func TestParseNegativeDigit(t *testing.T) {
400 re := MustCompile(`\D`, 0)
401 if want, got := 1, len(re.code.Sets); want != got {
402 t.Fatalf("wanted %v sets, got %v", want, got)
403 }
404
405 if want, got := "[\\P{Nd}]", re.code.Sets[0].String(); want != got {
406 t.Fatalf("wanted set 0 %v, got %v", want, got)
407 }
408 }
409
410 func TestRunNegativeDigit(t *testing.T) {
411 re := MustCompile(`\D`, 0)
412 m, err := re.MatchString("this is a test")
413 if err != nil {
414 t.Fatalf("Unexpected error: %v", err)
415 }
416 if !m {
417 t.Fatalf("Expected match")
418 }
419 }
420
421 func TestCancellingClasses(t *testing.T) {
422
423 re := MustCompile(`[\w\W\s]`, 0)
424 if want, got := 1, len(re.code.Sets); want != got {
425 t.Fatalf("wanted %v sets, got %v", want, got)
426 }
427 if want, got := syntax.AnyClass().String(), re.code.Sets[0].String(); want != got {
428 t.Fatalf("wanted set 0 %v, got %v", want, got)
429 }
430 }
431
432 func TestConcatLoopCaptureSet(t *testing.T) {
433
434
435
436
437
438
439 re := MustCompile(`(A|B)*CD`, 0)
440 if want, got := 1, len(re.code.Sets); want != got {
441 t.Fatalf("wanted %v sets, got %v", want, got)
442 }
443 if want, got := "[AB]", re.code.Sets[0].String(); want != got {
444 t.Fatalf("wanted set 0 %v, got %v", want, got)
445 }
446 }
447
448 func TestFirstcharsIgnoreCase(t *testing.T) {
449
450
451
452 re := MustCompile(`((?i)AB(?-i)C|D)E`, 0)
453
454 if re.code.FcPrefix == nil {
455 t.Fatalf("wanted prefix, got nil")
456 }
457
458 if want, got := "[ad]", re.code.FcPrefix.PrefixSet.String(); want != got {
459 t.Fatalf("wanted prefix %v, got %v", want, got)
460 }
461 }
462
463 func TestRepeatingGroup(t *testing.T) {
464 re := MustCompile(`(data?)+`, 0)
465
466 m, err := re.FindStringMatch("datadat")
467 if err != nil {
468 t.Fatalf("Unexpected err: %v", err)
469 }
470
471 if m == nil {
472 t.Fatalf("Expected match")
473 }
474
475 g := m.GroupByNumber(1)
476 if g == nil {
477 t.Fatalf("Expected group")
478 }
479
480 if want, got := 2, len(g.Captures); want != got {
481 t.Fatalf("wanted cap count %v, got %v", want, got)
482 }
483
484 if want, got := g.Captures[1].String(), g.Capture.String(); want != got {
485 t.Fatalf("expected last capture of the group to be embedded")
486 }
487
488 if want, got := "data", g.Captures[0].String(); want != got {
489 t.Fatalf("expected cap 0 to be %v, got %v", want, got)
490 }
491 if want, got := "dat", g.Captures[1].String(); want != got {
492 t.Fatalf("expected cap 1 to be %v, got %v", want, got)
493 }
494
495 }
496
497 func TestFindNextMatch_Basic(t *testing.T) {
498 re := MustCompile(`(T|E)(?=h|E|S|$)`, 0)
499 m, err := re.FindStringMatch(`This is a TEST`)
500 if err != nil {
501 t.Fatalf("Unexpected err 0: %v", err)
502 }
503 if m == nil {
504 t.Fatalf("Expected match 0")
505 }
506 if want, got := 0, m.Index; want != got {
507 t.Fatalf("expected match 0 to start at %v, got %v", want, got)
508 }
509
510 m, err = re.FindNextMatch(m)
511 if err != nil {
512 t.Fatalf("Unexpected err 1: %v", err)
513 }
514 if m == nil {
515 t.Fatalf("Expected match 1")
516 }
517 if want, got := 10, m.Index; want != got {
518 t.Fatalf("expected match 1 to start at %v, got %v", want, got)
519 }
520
521 m, err = re.FindNextMatch(m)
522 if err != nil {
523 t.Fatalf("Unexpected err 2: %v", err)
524 }
525 if m == nil {
526 t.Fatalf("Expected match 2")
527 }
528 if want, got := 11, m.Index; want != got {
529 t.Fatalf("expected match 2 to start at %v, got %v", want, got)
530 }
531
532 m, err = re.FindNextMatch(m)
533 if err != nil {
534 t.Fatalf("Unexpected err 3: %v", err)
535 }
536 if m == nil {
537 t.Fatalf("Expected match 3")
538 }
539 if want, got := 13, m.Index; want != got {
540 t.Fatalf("expected match 3 to start at %v, got %v", want, got)
541 }
542 }
543
544 func TestUnicodeSupplementaryCharSetMatch(t *testing.T) {
545
546 re := MustCompile("[𠜎-𠝹]", 0)
547
548 if m, err := re.MatchString("\u2070"); err != nil {
549 t.Fatalf("Unexpected err: %v", err)
550 } else if m {
551 t.Fatalf("Unexpected match")
552 }
553
554 if m, err := re.MatchString("𠜱"); err != nil {
555 t.Fatalf("Unexpected err: %v", err)
556 } else if !m {
557 t.Fatalf("Expected match")
558 }
559 }
560
561 func TestUnicodeSupplementaryCharInRange(t *testing.T) {
562
563 re := MustCompile(".", 0)
564
565 if m, err := re.MatchString("\u2070"); err != nil {
566 t.Fatalf("Unexpected err: %v", err)
567 } else if !m {
568 t.Fatalf("Expected match")
569 }
570
571 if m, err := re.MatchString("𠜱"); err != nil {
572 t.Fatalf("Unexpected err: %v", err)
573 } else if !m {
574 t.Fatalf("Expected match")
575 }
576 }
577
578 func TestUnicodeScriptSets(t *testing.T) {
579 re := MustCompile(`\p{Katakana}+`, 0)
580 if m, err := re.MatchString("\u30A0\u30FF"); err != nil {
581 t.Fatalf("Unexpected err: %v", err)
582 } else if !m {
583 t.Fatalf("Expected match")
584 }
585 }
586
587 func TestHexadecimalCurlyBraces(t *testing.T) {
588 re := MustCompile(`\x20`, 0)
589 if m, err := re.MatchString(" "); err != nil {
590 t.Fatalf("Unexpected err: %v", err)
591 } else if !m {
592 t.Fatalf("Expected match")
593 }
594
595 re = MustCompile(`\x{C4}`, 0)
596 if m, err := re.MatchString("Ä"); err != nil {
597 t.Fatalf("Unexpected err: %v", err)
598 } else if !m {
599 t.Fatalf("Expected match")
600 }
601
602 re = MustCompile(`\x{0C5}`, 0)
603 if m, err := re.MatchString("Å"); err != nil {
604 t.Fatalf("Unexpected err: %v", err)
605 } else if !m {
606 t.Fatalf("Expected match")
607 }
608
609 re = MustCompile(`\x{00C6}`, 0)
610 if m, err := re.MatchString("Æ"); err != nil {
611 t.Fatalf("Unexpected err: %v", err)
612 } else if !m {
613 t.Fatalf("Expected match")
614 }
615
616 re = MustCompile(`\x{1FF}`, 0)
617 if m, err := re.MatchString("ǿ"); err != nil {
618 t.Fatalf("Unexpected err: %v", err)
619 } else if !m {
620 t.Fatalf("Expected match")
621 }
622
623 re = MustCompile(`\x{02FF}`, 0)
624 if m, err := re.MatchString("˿"); err != nil {
625 t.Fatalf("Unexpected err: %v", err)
626 } else if !m {
627 t.Fatalf("Expected match")
628 }
629
630 re = MustCompile(`\x{1392}`, 0)
631 if m, err := re.MatchString("᎒"); err != nil {
632 t.Fatalf("Unexpected err: %v", err)
633 } else if !m {
634 t.Fatalf("Expected match")
635 }
636
637 re = MustCompile(`\x{0010ffff}`, 0)
638 if m, err := re.MatchString(string(rune(0x10ffff))); err != nil {
639 t.Fatalf("Unexpected err: %v", err)
640 } else if !m {
641 t.Fatalf("Expected match")
642 }
643
644 if _, err := Compile(`\x2R`, 0); err == nil {
645 t.Fatal("Expected error")
646 }
647 if _, err := Compile(`\x0`, 0); err == nil {
648 t.Fatal("Expected error")
649 }
650 if _, err := Compile(`\x`, 0); err == nil {
651 t.Fatal("Expected error")
652 }
653 if _, err := Compile(`\x{`, 0); err == nil {
654 t.Fatal("Expected error")
655 }
656 if _, err := Compile(`\x{2`, 0); err == nil {
657 t.Fatal("Expected error")
658 }
659 if _, err := Compile(`\x{2R`, 0); err == nil {
660 t.Fatal("Expected error")
661 }
662 if _, err := Compile(`\x{2R}`, 0); err == nil {
663 t.Fatal("Expected error")
664 }
665 if _, err := Compile(`\x{}`, 0); err == nil {
666 t.Fatalf("Expected error")
667 }
668 if _, err := Compile(`\x{10000`, 0); err == nil {
669 t.Fatal("Expected error")
670 }
671 if _, err := Compile(`\x{1234`, 0); err == nil {
672 t.Fatal("Expected error")
673 }
674 if _, err := Compile(`\x{123456789}`, 0); err == nil {
675 t.Fatal("Expected error")
676 }
677
678 }
679
680 func TestEmptyCharClass(t *testing.T) {
681 if _, err := Compile("[]", 0); err == nil {
682 t.Fatal("Empty char class isn't valid outside of ECMAScript mode")
683 }
684 }
685
686 func TestECMAEmptyCharClass(t *testing.T) {
687 re := MustCompile("[]", ECMAScript)
688 if m, err := re.MatchString("a"); err != nil {
689 t.Fatal(err)
690 } else if m {
691 t.Fatal("Expected no match")
692 }
693 }
694
695 func TestDot(t *testing.T) {
696 re := MustCompile(".", 0)
697 if m, err := re.MatchString("\r"); err != nil {
698 t.Fatal(err)
699 } else if !m {
700 t.Fatal("Expected match")
701 }
702 }
703
704 func TestECMADot(t *testing.T) {
705 re := MustCompile(".", ECMAScript)
706 if m, err := re.MatchString("\r"); err != nil {
707 t.Fatal(err)
708 } else if m {
709 t.Fatal("Expected no match")
710 }
711 }
712
713 func TestDecimalLookahead(t *testing.T) {
714 re := MustCompile(`\1(A)`, 0)
715 m, err := re.FindStringMatch("AA")
716 if err != nil {
717 t.Fatal(err)
718 } else if m != nil {
719 t.Fatal("Expected no match")
720 }
721 }
722
723 func TestECMADecimalLookahead(t *testing.T) {
724 re := MustCompile(`\1(A)`, ECMAScript)
725 m, err := re.FindStringMatch("AA")
726 if err != nil {
727 t.Fatal(err)
728 }
729
730 if c := m.GroupCount(); c != 2 {
731 t.Fatalf("Group count !=2 (%d)", c)
732 }
733
734 if s := m.GroupByNumber(0).String(); s != "A" {
735 t.Fatalf("Group0 != 'A' ('%s')", s)
736 }
737
738 if s := m.GroupByNumber(1).String(); s != "A" {
739 t.Fatalf("Group1 != 'A' ('%s')", s)
740 }
741 }
742
743 func TestECMAOctal(t *testing.T) {
744 re := MustCompile(`\100`, ECMAScript)
745 if m, err := re.MatchString("@"); err != nil {
746 t.Fatal(err)
747 } else if !m {
748 t.Fatal("Expected match")
749 }
750
751 if m, err := re.MatchString("x"); err != nil {
752 t.Fatal(err)
753 } else if m {
754 t.Fatal("Expected no match")
755 }
756
757 re = MustCompile(`\377`, ECMAScript)
758 if m, err := re.MatchString("\u00ff"); err != nil {
759 t.Fatal(err)
760 } else if !m {
761 t.Fatal("Expected match")
762 }
763
764 re = MustCompile(`\400`, ECMAScript)
765 if m, err := re.MatchString(" 0"); err != nil {
766 t.Fatal(err)
767 } else if !m {
768 t.Fatal("Expected match")
769 }
770
771 }
772
773 func TestECMAInvalidEscape(t *testing.T) {
774 re := MustCompile(`\x0`, ECMAScript)
775 if m, err := re.MatchString("x0"); err != nil {
776 t.Fatal(err)
777 } else if !m {
778 t.Fatal("Expected match")
779 }
780
781 re = MustCompile(`\x0z`, ECMAScript)
782 if m, err := re.MatchString("x0z"); err != nil {
783 t.Fatal(err)
784 } else if !m {
785 t.Fatal("Expected match")
786 }
787 }
788
789 func TestECMANamedGroup(t *testing.T) {
790 re := MustCompile(`\k`, ECMAScript)
791 if m, err := re.MatchString("k"); err != nil {
792 t.Fatal(err)
793 } else if !m {
794 t.Fatal("Expected match")
795 }
796
797 re = MustCompile(`\k'test'`, ECMAScript)
798 if m, err := re.MatchString(`k'test'`); err != nil {
799 t.Fatal(err)
800 } else if !m {
801 t.Fatal("Expected match")
802 }
803
804 re = MustCompile(`\k<test>`, ECMAScript)
805 if m, err := re.MatchString(`k<test>`); err != nil {
806 t.Fatal(err)
807 } else if !m {
808 t.Fatal("Expected match")
809 }
810
811 _, err := Compile(`(?<title>\w+), yes \k'title'`, ECMAScript)
812 if err == nil {
813 t.Fatal("Expected error")
814 }
815
816 re = MustCompile(`(?<title>\w+), yes \k<title>`, ECMAScript)
817 if m, err := re.MatchString("sir, yes sir"); err != nil {
818 t.Fatal(err)
819 } else if !m {
820 t.Fatal("Expected match")
821 }
822
823 re = MustCompile(`\k<title>, yes (?<title>\w+)`, ECMAScript)
824 if m, err := re.MatchString(", yes sir"); err != nil {
825 t.Fatal(err)
826 } else if !m {
827 t.Fatal("Expected match")
828 }
829
830 _, err = Compile(`\k<(?<name>)>`, ECMAScript)
831 if err == nil {
832 t.Fatal("Expected error")
833 }
834
835 MustCompile(`\k<(<name>)>`, ECMAScript)
836
837 _, err = Compile(`\k<(<name>)>`, 0)
838 if err == nil {
839 t.Fatal("Expected error")
840 }
841
842 re = MustCompile(`\'|\<?`, 0)
843 if m, err := re.MatchString("'"); err != nil {
844 t.Fatal(err)
845 } else if !m {
846 t.Fatal("Expected match")
847 }
848 if m, err := re.MatchString("<"); err != nil {
849 t.Fatal(err)
850 } else if !m {
851 t.Fatal("Expected match")
852 }
853 }
854
855 func TestECMAInvalidEscapeCharClass(t *testing.T) {
856 re := MustCompile(`[\x0]`, ECMAScript)
857 if m, err := re.MatchString("x"); err != nil {
858 t.Fatal(err)
859 } else if !m {
860 t.Fatal("Expected match")
861 }
862
863 if m, err := re.MatchString("0"); err != nil {
864 t.Fatal(err)
865 } else if !m {
866 t.Fatal("Expected match")
867 }
868
869 if m, err := re.MatchString("z"); err != nil {
870 t.Fatal(err)
871 } else if m {
872 t.Fatal("Expected no match")
873 }
874 }
875
876 func TestECMAScriptXCurlyBraceEscape(t *testing.T) {
877 re := MustCompile(`\x{20}`, ECMAScript)
878 if m, err := re.MatchString(" "); err != nil {
879 t.Fatal(err)
880 } else if m {
881 t.Fatal("Expected no match")
882 }
883
884 if m, err := re.MatchString("xxxxxxxxxxxxxxxxxxxx"); err != nil {
885 t.Fatal(err)
886 } else if !m {
887 t.Fatal("Expected match")
888 }
889 }
890
891 func TestEcmaScriptUnicodeRange(t *testing.T) {
892 r, err := Compile(`([\u{001a}-\u{ffff}]+)`, ECMAScript|Unicode)
893 if err != nil {
894 panic(err)
895 }
896 m, err := r.FindStringMatch("qqqq")
897 if err != nil {
898 panic(err)
899 }
900 if m == nil {
901 t.Fatal("Expected non-nil, got nil")
902 }
903 }
904
905 func TestNegateRange(t *testing.T) {
906 re := MustCompile(`[\D]`, 0)
907 if m, err := re.MatchString("A"); err != nil {
908 t.Fatal(err)
909 } else if !m {
910 t.Fatal("Expected match")
911 }
912 }
913
914 func TestECMANegateRange(t *testing.T) {
915 re := MustCompile(`[\D]`, ECMAScript)
916 if m, err := re.MatchString("A"); err != nil {
917 t.Fatal(err)
918 } else if !m {
919 t.Fatal("Expected match")
920 }
921 }
922
923 func TestDollar(t *testing.T) {
924
925
926 re := MustCompile(`ac$`, 0)
927 if m, err := re.MatchString("ac\n"); err != nil {
928 t.Fatal(err)
929 } else if !m {
930 t.Fatal("Expected match")
931 }
932 }
933 func TestECMADollar(t *testing.T) {
934 re := MustCompile(`ac$`, ECMAScript)
935 if m, err := re.MatchString("ac\n"); err != nil {
936 t.Fatal(err)
937 } else if m {
938 t.Fatal("Expected no match")
939 }
940 }
941
942 func TestThreeByteUnicode_InputOnly(t *testing.T) {
943
944
945 re := MustCompile("高", 0)
946 if m, err := re.MatchString("📍Test高"); err != nil {
947 t.Fatal(err)
948 } else if !m {
949 t.Fatal("Expected match")
950 }
951 }
952
953 func TestMultibyteUnicode_MatchPartialPattern(t *testing.T) {
954 re := MustCompile("猟な", 0)
955 if m, err := re.MatchString("なあ🍺な"); err != nil {
956 t.Fatal(err)
957 } else if m {
958 t.Fatal("Expected no match")
959 }
960 }
961
962 func TestMultibyteUnicode_Match(t *testing.T) {
963 re := MustCompile("猟な", 0)
964 if m, err := re.MatchString("なあ🍺猟な"); err != nil {
965 t.Fatal(err)
966 } else if !m {
967 t.Fatal("Expected match")
968 }
969 }
970
971 func TestAlternationNamedOptions_Errors(t *testing.T) {
972
973 data := []string{
974 "(?(?e))", "(?(?a)", "(?(?", "(?(", "?(a:b)", "?(a)", "?(a|b)", "?((a)", "?((a)a", "?((a)a|", "?((a)a|b",
975 "(?(?i))", "(?(?I))", "(?(?m))", "(?(?M))", "(?(?s))", "(?(?S))", "(?(?x))", "(?(?X))", "(?(?n))", "(?(?N))", " (?(?n))",
976 }
977 for _, p := range data {
978 re, err := Compile(p, 0)
979 if err == nil {
980 t.Fatal("Expected error, got nil")
981 }
982 if re != nil {
983 t.Fatal("Expected unparsed regexp, got non-nil")
984 }
985
986 if !strings.HasPrefix(err.Error(), "error parsing regexp: ") {
987 t.Fatalf("Wanted parse error, got '%v'", err)
988 }
989 }
990 }
991
992 func TestAlternationNamedOptions_Success(t *testing.T) {
993 data := []struct {
994 pattern string
995 input string
996 expectSuccess bool
997 matchVal string
998 }{
999 {"(?(cat)|dog)", "cat", true, ""},
1000 {"(?(cat)|dog)", "catdog", true, ""},
1001 {"(?(cat)dog1|dog2)", "catdog1", false, ""},
1002 {"(?(cat)dog1|dog2)", "catdog2", true, "dog2"},
1003 {"(?(cat)dog1|dog2)", "catdog1dog2", true, "dog2"},
1004 {"(?(dog2))", "dog2", true, ""},
1005 {"(?(cat)|dog)", "oof", false, ""},
1006 {"(?(a:b))", "a", true, ""},
1007 {"(?(a:))", "a", true, ""},
1008 }
1009 for _, p := range data {
1010 re := MustCompile(p.pattern, 0)
1011 m, err := re.FindStringMatch(p.input)
1012
1013 if err != nil {
1014 t.Fatalf("Unexpected error during match: %v", err)
1015 }
1016 if want, got := p.expectSuccess, m != nil; want != got {
1017 t.Fatalf("Success mismatch for %v, wanted %v, got %v", p.pattern, want, got)
1018 }
1019 if m != nil {
1020 if want, got := p.matchVal, m.String(); want != got {
1021 t.Fatalf("Match val mismatch for %v, wanted %v, got %v", p.pattern, want, got)
1022 }
1023 }
1024 }
1025 }
1026
1027 func TestAlternationConstruct_Matches(t *testing.T) {
1028 re := MustCompile("(?(A)A123|C789)", 0)
1029 m, err := re.FindStringMatch("A123 B456 C789")
1030 if err != nil {
1031 t.Fatalf("Unexpected err: %v", err)
1032 }
1033 if m == nil {
1034 t.Fatal("Expected match, got nil")
1035 }
1036
1037 if want, got := "A123", m.String(); want != got {
1038 t.Fatalf("Wanted %v, got %v", want, got)
1039 }
1040
1041 m, err = re.FindNextMatch(m)
1042 if err != nil {
1043 t.Fatalf("Unexpected err in second match: %v", err)
1044 }
1045 if m == nil {
1046 t.Fatal("Expected second match, got nil")
1047 }
1048 if want, got := "C789", m.String(); want != got {
1049 t.Fatalf("Wanted %v, got %v", want, got)
1050 }
1051
1052 m, err = re.FindNextMatch(m)
1053 if err != nil {
1054 t.Fatalf("Unexpected err in third match: %v", err)
1055 }
1056 if m != nil {
1057 t.Fatal("Did not expect third match")
1058 }
1059 }
1060
1061 func TestStartAtEnd(t *testing.T) {
1062 re := MustCompile("(?:)", 0)
1063 m, err := re.FindStringMatchStartingAt("t", 1)
1064 if err != nil {
1065 t.Fatal(err)
1066 }
1067 if m == nil {
1068 t.Fatal("Expected match")
1069 }
1070 }
1071
1072 func TestParserFuzzCrashes(t *testing.T) {
1073 var crashes = []string{
1074 "(?'-", "(\\c0)", "(\\00(?())", "[\\p{0}", "(\x00?.*.()?(()?)?)*.x\xcb?&(\\s\x80)", "\\p{0}", "[0-[\\p{0}",
1075 }
1076
1077 for _, c := range crashes {
1078 t.Log(c)
1079 Compile(c, 0)
1080 }
1081 }
1082
1083 func TestParserFuzzHangs(t *testing.T) {
1084 var hangs = []string{
1085 "\r{865720113}z\xd5{\r{861o", "\r{915355}\r{9153}", "\r{525005}", "\x01{19765625}", "(\r{068828256})", "\r{677525005}",
1086 }
1087
1088 for _, c := range hangs {
1089 t.Log(c)
1090 Compile(c, 0)
1091 }
1092 }
1093
1094 func BenchmarkParserPrefixLongLen(b *testing.B) {
1095 re := MustCompile("\r{100001}T+", 0)
1096 inp := strings.Repeat("testing", 10000) + strings.Repeat("\r", 100000) + "TTTT"
1097
1098 b.ResetTimer()
1099 for i := 0; i < b.N; i++ {
1100 if m, err := re.MatchString(inp); err != nil {
1101 b.Fatalf("Unexpected err: %v", err)
1102 } else if m {
1103 b.Fatalf("Expected no match")
1104 }
1105 }
1106 }
1107
1108
1127
1128
1129
1130 func TestControlBracketFail(t *testing.T) {
1131 re := MustCompile(`(cat)(\c[*)(dog)`, 0)
1132 inp := "asdlkcat\u00FFdogiwod"
1133
1134 if m, _ := re.MatchString(inp); m {
1135 t.Fatal("expected no match")
1136 }
1137 }
1138
1139 func TestControlBracketGroups(t *testing.T) {
1140 re := MustCompile(`(cat)(\c[*)(dog)`, 0)
1141 inp := "asdlkcat\u001bdogiwod"
1142
1143 if want, got := 4, re.capsize; want != got {
1144 t.Fatalf("Capsize wrong, want %v, got %v", want, got)
1145 }
1146
1147 m, _ := re.FindStringMatch(inp)
1148 if m == nil {
1149 t.Fatal("expected match")
1150 }
1151
1152 g := m.Groups()
1153 want := []string{"cat\u001bdog", "cat", "\u001b", "dog"}
1154 for i := 0; i < len(g); i++ {
1155 if want[i] != g[i].String() {
1156 t.Fatalf("Bad group num %v, want %v, got %v", i, want[i], g[i].String())
1157 }
1158 }
1159 }
1160
1161 func TestBadGroupConstruct(t *testing.T) {
1162 bad := []string{"(?>-", "(?<", "(?<=", "(?<!", "(?>", "(?)", "(?<)", "(?')", "(?<-"}
1163
1164 for _, b := range bad {
1165 _, err := Compile(b, 0)
1166 if err == nil {
1167 t.Fatalf("Wanted error, but got no error for pattern: %v", b)
1168 }
1169 }
1170 }
1171
1172 func TestEmptyCaptureLargeRepeat(t *testing.T) {
1173
1174
1175
1176
1177
1178
1179
1180 r := MustCompile(`(?:){40}`, 0)
1181 m, err := r.FindStringMatch("1")
1182 if err != nil {
1183 t.Fatalf("Unexpected error: %v", err)
1184 }
1185 if want, got := 0, m.Index; want != got {
1186 t.Errorf("First Match Index wanted %v got %v", want, got)
1187 }
1188 if want, got := 0, m.Length; want != got {
1189 t.Errorf("First Match Length wanted %v got %v", want, got)
1190 }
1191
1192 m, _ = r.FindNextMatch(m)
1193 if want, got := 1, m.Index; want != got {
1194 t.Errorf("Second Match Index wanted %v got %v", want, got)
1195 }
1196 if want, got := 0, m.Length; want != got {
1197 t.Errorf("Second Match Length wanted %v got %v", want, got)
1198 }
1199
1200 m, _ = r.FindNextMatch(m)
1201 if m != nil {
1202 t.Fatal("Expected 2 matches, got more")
1203 }
1204 }
1205
1206 func TestFuzzBytes_NoCompile(t *testing.T) {
1207
1208
1209 var testCases = []struct {
1210 r []byte
1211 }{
1212 {
1213 r: []byte{0x28, 0x28, 0x29, 0x5c, 0x37, 0x28, 0x3f, 0x28, 0x29, 0x29},
1214 },
1215 {
1216 r: []byte{0x28, 0x5c, 0x32, 0x28, 0x3f, 0x28, 0x30, 0x29, 0x29},
1217 },
1218 {
1219 r: []byte{0x28, 0x3f, 0x28, 0x29, 0x29, 0x5c, 0x31, 0x30, 0x28, 0x3f, 0x28, 0x30, 0x29},
1220 },
1221 {
1222 r: []byte{0x28, 0x29, 0x28, 0x28, 0x29, 0x5c, 0x37, 0x28, 0x3f, 0x28, 0x29, 0x29},
1223 },
1224 }
1225
1226 for _, c := range testCases {
1227 r := string(c.r)
1228 t.Run(r, func(t *testing.T) {
1229 _, err := Compile(r, Multiline|ECMAScript|Debug)
1230
1231 if err == nil {
1232 t.Fatal("should fail compile, but didn't")
1233 }
1234 })
1235 }
1236
1237 }
1238
1239 func TestFuzzBytes_Match(t *testing.T) {
1240
1241 var testCases = []struct {
1242 r, s []byte
1243 }{
1244 {
1245 r: []byte{0x30, 0xbf, 0x30, 0x2a, 0x30, 0x30},
1246 s: []byte{0xf0, 0xb0, 0x80, 0x91, 0xf7},
1247 },
1248 {
1249 r: []byte{0x30, 0xaf, 0xf3, 0x30, 0x2a},
1250 s: []byte{0xf3, 0x80, 0x80, 0x87, 0x80, 0x89},
1251 },
1252 }
1253
1254 for _, c := range testCases {
1255 r := string(c.r)
1256 t.Run(r, func(t *testing.T) {
1257 re, err := Compile(r, 0)
1258
1259 if err != nil {
1260 t.Fatal("should compile, but didn't")
1261 }
1262
1263 re.MatchString(string(c.s))
1264 })
1265 }
1266 }
1267
1268 func TestConcatAccidentalPatternCharge(t *testing.T) {
1269
1270
1271
1272
1273
1274 r, err := Compile(`(?<=1234\.\*56).*(?=890)`, 0)
1275
1276 if err != nil {
1277 panic(err)
1278 }
1279
1280 m, err := r.FindStringMatch(`1234.*567890`)
1281 if err != nil {
1282 panic(err)
1283 }
1284 if m == nil {
1285 t.Fatal("Expected non-nil, got nil")
1286 }
1287 }
1288
1289 func TestGoodReverseOrderMessage(t *testing.T) {
1290 _, err := Compile(`[h-c]`, ECMAScript)
1291 if err == nil {
1292 t.Fatal("expected error")
1293 }
1294 expected := "error parsing regexp: [h-c] range in reverse order in `[h-c]`"
1295 if err.Error() != expected {
1296 t.Fatalf("expected %q got %q", expected, err.Error())
1297 }
1298 }
1299
1300 func TestParseShortSlashP(t *testing.T) {
1301 re := MustCompile(`[!\pL\pN]{1,}`, 0)
1302 m, err := re.FindStringMatch("this23! is a! test 1a 2b")
1303 if err != nil {
1304 t.Fatalf("Unexpected error: %v", err)
1305 }
1306 if m.String() != "this23!" {
1307 t.Fatalf("Expected match")
1308 }
1309 }
1310
1311 func TestParseShortSlashNegateP(t *testing.T) {
1312 re := MustCompile(`\PNa`, 0)
1313 m, err := re.FindStringMatch("this is a test 1a 2b")
1314 if err != nil {
1315 t.Fatalf("Unexpected error: %v", err)
1316 }
1317 if m.String() != " a" {
1318 t.Fatalf("Expected match")
1319 }
1320 }
1321
1322 func TestParseShortSlashPEnd(t *testing.T) {
1323 re := MustCompile(`\pN`, 0)
1324 m, err := re.FindStringMatch("this is a test 1a 2b")
1325 if err != nil {
1326 t.Fatalf("Unexpected error: %v", err)
1327 }
1328 if m.String() != "1" {
1329 t.Fatalf("Expected match")
1330 }
1331 }
1332
View as plain text