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