blob: 83b249e3cef686d7666098e5501c4958f6571d01 [file] [log] [blame]
Rob Pike6610d792010-08-12 14:41:52 +10001// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package regexp
6
7import (
8 "fmt"
Rob Pike7db904c2011-02-03 13:58:40 -08009 "strings"
Rob Pike6610d792010-08-12 14:41:52 +100010 "testing"
11)
12
13// For each pattern/text pair, what is the expected output of each function?
14// We can derive the textual results from the indexed results, the non-submatch
15// results from the submatched results, the single results from the 'all' results,
16// and the byte results from the string results. Therefore the table includes
17// only the FindAllStringSubmatchIndex result.
18type FindTest struct {
19 pat string
20 text string
21 matches [][]int
22}
23
24func (t FindTest) String() string {
25 return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
26}
27
28var findTests = []FindTest{
Robert Griesemer34788912010-10-22 10:06:33 -070029 {``, ``, build(1, 0, 0)},
30 {`^abcdefg`, "abcdefg", build(1, 0, 7)},
31 {`a+`, "baaab", build(1, 1, 4)},
32 {"abcd..", "abcdef", build(1, 0, 6)},
33 {`a`, "a", build(1, 0, 1)},
34 {`x`, "y", nil},
35 {`b`, "abc", build(1, 1, 2)},
36 {`.`, "a", build(1, 0, 1)},
37 {`.*`, "abcdef", build(1, 0, 6)},
38 {`^`, "abcde", build(1, 0, 0)},
39 {`$`, "abcde", build(1, 5, 5)},
40 {`^abcd$`, "abcd", build(1, 0, 4)},
41 {`^bcd'`, "abcdef", nil},
42 {`^abcd$`, "abcde", nil},
43 {`a+`, "baaab", build(1, 1, 4)},
44 {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
45 {`[a-z]+`, "abcd", build(1, 0, 4)},
46 {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
47 {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
48 {`[^\n]+`, "abcd\n", build(1, 0, 4)},
49 {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
50 {`日本語+`, "日本語", build(1, 0, 9)},
51 {`日本語+`, "日本語語語語", build(1, 0, 18)},
52 {`()`, "", build(1, 0, 0, 0, 0)},
53 {`(a)`, "a", build(1, 0, 1, 0, 1)},
54 {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
55 {`(.*)`, "", build(1, 0, 0, 0, 0)},
56 {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
57 {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
58 {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
59 {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
60 {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
61 {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
62 {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
Rob Pike6610d792010-08-12 14:41:52 +100063
Robert Griesemer34788912010-10-22 10:06:33 -070064 {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
65 {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
66 {`[.]`, ".", build(1, 0, 1)},
67 {`/$`, "/abc/", build(1, 4, 5)},
68 {`/$`, "/abc", nil},
Rob Pike6610d792010-08-12 14:41:52 +100069
70 // multiple matches
Robert Griesemer34788912010-10-22 10:06:33 -070071 {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
72 {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
73 {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
74 {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
75 {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
Rob Pike6610d792010-08-12 14:41:52 +100076
77 // fixed bugs
Robert Griesemer34788912010-10-22 10:06:33 -070078 {`ab$`, "cab", build(1, 1, 3)},
79 {`axxb$`, "axxcb", nil},
80 {`data`, "daXY data", build(1, 5, 9)},
81 {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
Rob Pike15cb7ed2011-01-03 11:35:34 -080082 {`zx+`, "zzx", build(1, 1, 3)},
Rob Pike6610d792010-08-12 14:41:52 +100083
84 // can backslash-escape any punctuation
Robert Griesemer34788912010-10-22 10:06:33 -070085 {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
Rob Pike6610d792010-08-12 14:41:52 +100086 `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
Robert Griesemer34788912010-10-22 10:06:33 -070087 {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
Rob Pike6610d792010-08-12 14:41:52 +100088 `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
Robert Griesemer34788912010-10-22 10:06:33 -070089 {"\\`", "`", build(1, 0, 1)},
90 {"[\\`]+", "`", build(1, 0, 1)},
Rob Pike69fe3dd2010-08-16 15:17:34 -070091
92 // long set of matches (longer than startSize)
Robert Griesemer34788912010-10-22 10:06:33 -070093 {
Rob Pike69fe3dd2010-08-16 15:17:34 -070094 ".",
95 "qwertyuiopasdfghjklzxcvbnm1234567890",
96 build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
97 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
98 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
99 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
100 },
Rob Pike6610d792010-08-12 14:41:52 +1000101}
102
103// build is a helper to construct a [][]int by extracting n sequences from x.
104// This represents n matches with len(x)/n submatches each.
105func build(n int, x ...int) [][]int {
106 ret := make([][]int, n)
107 runLength := len(x) / n
108 j := 0
109 for i := range ret {
110 ret[i] = make([]int, runLength)
111 copy(ret[i], x[j:])
112 j += runLength
113 if j > len(x) {
114 panic("invalid build entry")
115 }
116 }
117 return ret
118}
119
120// First the simple cases.
121
122func TestFind(t *testing.T) {
123 for _, test := range findTests {
Rob Pike5bd40942010-12-16 16:55:26 -0800124 re := MustCompile(test.pat)
Rob Pikea9e7c932010-12-17 10:23:46 -0800125 if re.String() != test.pat {
126 t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
Rob Pike5bd40942010-12-16 16:55:26 -0800127 }
128 result := re.Find([]byte(test.text))
Rob Pike6610d792010-08-12 14:41:52 +1000129 switch {
130 case len(test.matches) == 0 && len(result) == 0:
131 // ok
132 case test.matches == nil && result != nil:
133 t.Errorf("expected no match; got one: %s", test)
134 case test.matches != nil && result == nil:
135 t.Errorf("expected match; got none: %s", test)
136 case test.matches != nil && result != nil:
137 expect := test.text[test.matches[0][0]:test.matches[0][1]]
138 if expect != string(result) {
139 t.Errorf("expected %q got %q: %s", expect, result, test)
140 }
141 }
142 }
143}
144
145func TestFindString(t *testing.T) {
146 for _, test := range findTests {
147 result := MustCompile(test.pat).FindString(test.text)
148 switch {
149 case len(test.matches) == 0 && len(result) == 0:
150 // ok
151 case test.matches == nil && result != "":
152 t.Errorf("expected no match; got one: %s", test)
153 case test.matches != nil && result == "":
154 // Tricky because an empty result has two meanings: no match or empty match.
155 if test.matches[0][0] != test.matches[0][1] {
156 t.Errorf("expected match; got none: %s", test)
157 }
158 case test.matches != nil && result != "":
159 expect := test.text[test.matches[0][0]:test.matches[0][1]]
160 if expect != result {
161 t.Errorf("expected %q got %q: %s", expect, result, test)
162 }
163 }
164 }
165}
166
167func testFindIndex(test *FindTest, result []int, t *testing.T) {
168 switch {
169 case len(test.matches) == 0 && len(result) == 0:
170 // ok
171 case test.matches == nil && result != nil:
172 t.Errorf("expected no match; got one: %s", test)
173 case test.matches != nil && result == nil:
174 t.Errorf("expected match; got none: %s", test)
175 case test.matches != nil && result != nil:
176 expect := test.matches[0]
177 if expect[0] != result[0] || expect[1] != result[1] {
178 t.Errorf("expected %v got %v: %s", expect, result, test)
179 }
180 }
181}
182
183func TestFindIndex(t *testing.T) {
184 for _, test := range findTests {
185 testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
186 }
187}
188
189func TestFindStringIndex(t *testing.T) {
190 for _, test := range findTests {
191 testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
192 }
193}
194
Rob Pike7db904c2011-02-03 13:58:40 -0800195func TestFindReaderIndex(t *testing.T) {
196 for _, test := range findTests {
197 testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t)
198 }
199}
200
Rob Pike6610d792010-08-12 14:41:52 +1000201// Now come the simple All cases.
202
203func TestFindAll(t *testing.T) {
204 for _, test := range findTests {
205 result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
206 switch {
207 case test.matches == nil && result == nil:
208 // ok
209 case test.matches == nil && result != nil:
210 t.Errorf("expected no match; got one: %s", test)
211 case test.matches != nil && result == nil:
212 t.Errorf("expected match; got none: %s", test)
213 case test.matches != nil && result != nil:
214 if len(test.matches) != len(result) {
215 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
216 continue
217 }
218 for k, e := range test.matches {
219 expect := test.text[e[0]:e[1]]
220 if expect != string(result[k]) {
221 t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
222 }
223 }
224 }
225 }
226}
227
228func TestFindAllString(t *testing.T) {
229 for _, test := range findTests {
230 result := MustCompile(test.pat).FindAllString(test.text, -1)
231 switch {
232 case test.matches == nil && result == nil:
233 // ok
234 case test.matches == nil && result != nil:
235 t.Errorf("expected no match; got one: %s", test)
236 case test.matches != nil && result == nil:
237 t.Errorf("expected match; got none: %s", test)
238 case test.matches != nil && result != nil:
239 if len(test.matches) != len(result) {
240 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
241 continue
242 }
243 for k, e := range test.matches {
244 expect := test.text[e[0]:e[1]]
245 if expect != result[k] {
246 t.Errorf("expected %q got %q: %s", expect, result, test)
247 }
248 }
249 }
250 }
251}
252
253func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
254 switch {
255 case test.matches == nil && result == nil:
256 // ok
257 case test.matches == nil && result != nil:
258 t.Errorf("expected no match; got one: %s", test)
259 case test.matches != nil && result == nil:
260 t.Errorf("expected match; got none: %s", test)
261 case test.matches != nil && result != nil:
262 if len(test.matches) != len(result) {
263 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
264 return
265 }
266 for k, e := range test.matches {
267 if e[0] != result[k][0] || e[1] != result[k][1] {
268 t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
269 }
270 }
271 }
272}
273
274func TestFindAllIndex(t *testing.T) {
275 for _, test := range findTests {
276 testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
277 }
278}
279
280func TestFindAllStringIndex(t *testing.T) {
281 for _, test := range findTests {
282 testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
283 }
284}
285
286// Now come the Submatch cases.
287
288func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
289 if len(submatches) != len(result)*2 {
290 t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
291 return
292 }
293 for k := 0; k < len(submatches); k += 2 {
294 if submatches[k] == -1 {
295 if result[k/2] != nil {
296 t.Errorf("match %d: expected nil got %q: %s", n, result, test)
297 }
298 continue
299 }
300 expect := test.text[submatches[k]:submatches[k+1]]
301 if expect != string(result[k/2]) {
302 t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
303 return
304 }
305 }
306}
307
308func TestFindSubmatch(t *testing.T) {
309 for _, test := range findTests {
310 result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
311 switch {
312 case test.matches == nil && result == nil:
313 // ok
314 case test.matches == nil && result != nil:
315 t.Errorf("expected no match; got one: %s", test)
316 case test.matches != nil && result == nil:
317 t.Errorf("expected match; got none: %s", test)
318 case test.matches != nil && result != nil:
319 testSubmatchBytes(&test, 0, test.matches[0], result, t)
320 }
321 }
322}
323
324func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
325 if len(submatches) != len(result)*2 {
326 t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
327 return
328 }
329 for k := 0; k < len(submatches); k += 2 {
330 if submatches[k] == -1 {
331 if result[k/2] != "" {
332 t.Errorf("match %d: expected nil got %q: %s", n, result, test)
333 }
334 continue
335 }
336 expect := test.text[submatches[k]:submatches[k+1]]
337 if expect != result[k/2] {
338 t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
339 return
340 }
341 }
342}
343
344func TestFindStringSubmatch(t *testing.T) {
345 for _, test := range findTests {
346 result := MustCompile(test.pat).FindStringSubmatch(test.text)
347 switch {
348 case test.matches == nil && result == nil:
349 // ok
350 case test.matches == nil && result != nil:
351 t.Errorf("expected no match; got one: %s", test)
352 case test.matches != nil && result == nil:
353 t.Errorf("expected match; got none: %s", test)
354 case test.matches != nil && result != nil:
355 testSubmatchString(&test, 0, test.matches[0], result, t)
356 }
357 }
358}
359
360func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
361 if len(expect) != len(result) {
362 t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
363 return
364 }
365 for k, e := range expect {
366 if e != result[k] {
367 t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
368 }
369 }
370}
371
372func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
373 switch {
374 case test.matches == nil && result == nil:
375 // ok
376 case test.matches == nil && result != nil:
377 t.Errorf("expected no match; got one: %s", test)
378 case test.matches != nil && result == nil:
379 t.Errorf("expected match; got none: %s", test)
380 case test.matches != nil && result != nil:
381 testSubmatchIndices(test, 0, test.matches[0], result, t)
382 }
383}
384
385func TestFindSubmatchIndex(t *testing.T) {
386 for _, test := range findTests {
387 testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
388 }
389}
390
Rob Pike8a2d7062011-02-01 17:48:42 -0800391func TestFindStringSubmatchIndex(t *testing.T) {
Rob Pike6610d792010-08-12 14:41:52 +1000392 for _, test := range findTests {
393 testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
394 }
395}
396
Rob Pike7db904c2011-02-03 13:58:40 -0800397func TestFindReaderSubmatchIndex(t *testing.T) {
398 for _, test := range findTests {
399 testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t)
400 }
401}
402
Rob Pike6610d792010-08-12 14:41:52 +1000403// Now come the monster AllSubmatch cases.
404
405func TestFindAllSubmatch(t *testing.T) {
406 for _, test := range findTests {
407 result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
408 switch {
409 case test.matches == nil && result == nil:
410 // ok
411 case test.matches == nil && result != nil:
412 t.Errorf("expected no match; got one: %s", test)
413 case test.matches != nil && result == nil:
414 t.Errorf("expected match; got none: %s", test)
415 case len(test.matches) != len(result):
416 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
417 case test.matches != nil && result != nil:
418 for k, match := range test.matches {
419 testSubmatchBytes(&test, k, match, result[k], t)
420 }
421 }
422 }
423}
424
425func TestFindAllStringSubmatch(t *testing.T) {
426 for _, test := range findTests {
427 result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
428 switch {
429 case test.matches == nil && result == nil:
430 // ok
431 case test.matches == nil && result != nil:
432 t.Errorf("expected no match; got one: %s", test)
433 case test.matches != nil && result == nil:
434 t.Errorf("expected match; got none: %s", test)
435 case len(test.matches) != len(result):
436 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
437 case test.matches != nil && result != nil:
438 for k, match := range test.matches {
439 testSubmatchString(&test, k, match, result[k], t)
440 }
441 }
442 }
443}
444
445func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
446 switch {
447 case test.matches == nil && result == nil:
448 // ok
449 case test.matches == nil && result != nil:
450 t.Errorf("expected no match; got one: %s", test)
451 case test.matches != nil && result == nil:
452 t.Errorf("expected match; got none: %s", test)
453 case len(test.matches) != len(result):
454 t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
455 case test.matches != nil && result != nil:
456 for k, match := range test.matches {
457 testSubmatchIndices(test, k, match, result[k], t)
458 }
459 }
460}
461
462func TestFindAllSubmatchIndex(t *testing.T) {
463 for _, test := range findTests {
464 testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
465 }
466}
467
Rob Pike8a2d7062011-02-01 17:48:42 -0800468func TestFindAllStringSubmatchIndex(t *testing.T) {
Rob Pike6610d792010-08-12 14:41:52 +1000469 for _, test := range findTests {
470 testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
471 }
472}