1
2
3
4
5 package regexp
6
7 import (
8 "os"
9 "strings"
10 "testing"
11 )
12
13 var good_re = []string{
14 ``,
15 `.`,
16 `^.$`,
17 `a`,
18 `a*`,
19 `a+`,
20 `a?`,
21 `a|b`,
22 `a*|b*`,
23 `(a*|b)(c*|d)`,
24 `[a-z]`,
25 `[a-abc-c\-\]\[]`,
26 `[a-z]+`,
27 `[]`,
28 `[abc]`,
29 `[^1234]`,
30 `[^\n]`,
31 `\!\\`,
32 }
33
34 type stringError struct {
35 re string
36 err os.Error
37 }
38
39 var bad_re = []stringError{
40 {`*`, ErrBareClosure},
41 {`+`, ErrBareClosure},
42 {`?`, ErrBareClosure},
43 {`(abc`, ErrUnmatchedLpar},
44 {`abc)`, ErrUnmatchedRpar},
45 {`x[a-z`, ErrUnmatchedLbkt},
46 {`abc]`, ErrUnmatchedRbkt},
47 {`[z-a]`, ErrBadRange},
48 {`abc\`, ErrExtraneousBackslash},
49 {`a**`, ErrBadClosure},
50 {`a*+`, ErrBadClosure},
51 {`a??`, ErrBadClosure},
52 {`\x`, ErrBadBackslash},
53 }
54
55 func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
56 re, err := Compile(expr)
57 if err != error {
58 t.Error("compiling `", expr, "`; unexpected error: ", err.String())
59 }
60 return re
61 }
62
63 func TestGoodCompile(t *testing.T) {
64 for i := 0; i < len(good_re); i++ {
65 compileTest(t, good_re[i], nil)
66 }
67 }
68
69 func TestBadCompile(t *testing.T) {
70 for i := 0; i < len(bad_re); i++ {
71 compileTest(t, bad_re[i].re, bad_re[i].err)
72 }
73 }
74
75 func matchTest(t *testing.T, test *FindTest) {
76 re := compileTest(t, test.pat, nil)
77 if re == nil {
78 return
79 }
80 m := re.MatchString(test.text)
81 if m != (len(test.matches) > 0) {
82 t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
83 }
84
85 m = re.Match([]byte(test.text))
86 if m != (len(test.matches) > 0) {
87 t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
88 }
89 }
90
91 func TestMatch(t *testing.T) {
92 for _, test := range findTests {
93 matchTest(t, &test)
94 }
95 }
96
97 func matchFunctionTest(t *testing.T, test *FindTest) {
98 m, err := MatchString(test.pat, test.text)
99 if err == nil {
100 return
101 }
102 if m != (len(test.matches) > 0) {
103 t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
104 }
105 }
106
107 func TestMatchFunction(t *testing.T) {
108 for _, test := range findTests {
109 matchFunctionTest(t, &test)
110 }
111 }
112
113 type ReplaceTest struct {
114 pattern, replacement, input, output string
115 }
116
117 var replaceTests = []ReplaceTest{
118
119 {"", "", "", ""},
120 {"", "x", "", "x"},
121 {"", "", "abc", "abc"},
122 {"", "x", "abc", "xaxbxcx"},
123
124
125 {"b", "", "", ""},
126 {"b", "x", "", ""},
127 {"b", "", "abc", "ac"},
128 {"b", "x", "abc", "axc"},
129 {"y", "", "", ""},
130 {"y", "x", "", ""},
131 {"y", "", "abc", "abc"},
132 {"y", "x", "abc", "abc"},
133
134
135
136 {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
137 {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
138
139
140 {"^[a-c]*", "x", "abcdabc", "xdabc"},
141 {"[a-c]*$", "x", "abcdabc", "abcdx"},
142 {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
143 {"^[a-c]*", "x", "abc", "x"},
144 {"[a-c]*$", "x", "abc", "x"},
145 {"^[a-c]*$", "x", "abc", "x"},
146 {"^[a-c]*", "x", "dabce", "xdabce"},
147 {"[a-c]*$", "x", "dabce", "dabcex"},
148 {"^[a-c]*$", "x", "dabce", "dabce"},
149 {"^[a-c]*", "x", "", "x"},
150 {"[a-c]*$", "x", "", "x"},
151 {"^[a-c]*$", "x", "", "x"},
152
153 {"^[a-c]+", "x", "abcdabc", "xdabc"},
154 {"[a-c]+$", "x", "abcdabc", "abcdx"},
155 {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
156 {"^[a-c]+", "x", "abc", "x"},
157 {"[a-c]+$", "x", "abc", "x"},
158 {"^[a-c]+$", "x", "abc", "x"},
159 {"^[a-c]+", "x", "dabce", "dabce"},
160 {"[a-c]+$", "x", "dabce", "dabce"},
161 {"^[a-c]+$", "x", "dabce", "dabce"},
162 {"^[a-c]+", "x", "", ""},
163 {"[a-c]+$", "x", "", ""},
164 {"^[a-c]+$", "x", "", ""},
165
166
167 {"abc", "def", "abcdefg", "defdefg"},
168 {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
169 {"abc", "", "abcdabc", "d"},
170 {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
171 {"abc", "d", "", ""},
172 {"abc", "d", "abc", "d"},
173 {".+", "x", "abc", "x"},
174 {"[a-c]*", "x", "def", "xdxexfx"},
175 {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
176 {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
177 }
178
179 type ReplaceFuncTest struct {
180 pattern string
181 replacement func(string) string
182 input, output string
183 }
184
185 var replaceFuncTests = []ReplaceFuncTest{
186 {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
187 {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
188 {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
189 }
190
191 func TestReplaceAll(t *testing.T) {
192 for _, tc := range replaceTests {
193 re, err := Compile(tc.pattern)
194 if err != nil {
195 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
196 continue
197 }
198 actual := re.ReplaceAllString(tc.input, tc.replacement)
199 if actual != tc.output {
200 t.Errorf("%q.Replace(%q,%q) = %q; want %q",
201 tc.pattern, tc.input, tc.replacement, actual, tc.output)
202 }
203
204 actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
205 if actual != tc.output {
206 t.Errorf("%q.Replace(%q,%q) = %q; want %q",
207 tc.pattern, tc.input, tc.replacement, actual, tc.output)
208 }
209 }
210 }
211
212 func TestReplaceAllFunc(t *testing.T) {
213 for _, tc := range replaceFuncTests {
214 re, err := Compile(tc.pattern)
215 if err != nil {
216 t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
217 continue
218 }
219 actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
220 if actual != tc.output {
221 t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
222 tc.pattern, tc.input, tc.replacement, actual, tc.output)
223 }
224
225 actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
226 if actual != tc.output {
227 t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
228 tc.pattern, tc.input, tc.replacement, actual, tc.output)
229 }
230 }
231 }
232
233 type MetaTest struct {
234 pattern, output, literal string
235 isLiteral bool
236 }
237
238 var metaTests = []MetaTest{
239 {``, ``, ``, true},
240 {`foo`, `foo`, `foo`, true},
241 {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true},
242 {`foo.\$`, `foo\.\\\$`, `foo`, false},
243 {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`, `!@#`, false},
244 }
245
246 func TestQuoteMeta(t *testing.T) {
247 for _, tc := range metaTests {
248
249 quoted := QuoteMeta(tc.pattern)
250 if quoted != tc.output {
251 t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
252 tc.pattern, quoted, tc.output)
253 continue
254 }
255
256
257
258 if tc.pattern != "" {
259 re, err := Compile(quoted)
260 if err != nil {
261 t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
262 continue
263 }
264 src := "abc" + tc.pattern + "def"
265 repl := "xyz"
266 replaced := re.ReplaceAllString(src, repl)
267 expected := "abcxyzdef"
268 if replaced != expected {
269 t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
270 tc.pattern, src, repl, replaced, expected)
271 }
272 }
273 }
274 }
275
276 func TestLiteralPrefix(t *testing.T) {
277 for _, tc := range metaTests {
278
279 re := MustCompile(tc.pattern)
280 str, complete := re.LiteralPrefix()
281 if complete != tc.isLiteral {
282 t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
283 }
284 if str != tc.literal {
285 t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
286 }
287 }
288 }
289
290 type numSubexpCase struct {
291 input string
292 expected int
293 }
294
295 var numSubexpCases = []numSubexpCase{
296 {``, 0},
297 {`.*`, 0},
298 {`abba`, 0},
299 {`ab(b)a`, 1},
300 {`ab(.*)a`, 1},
301 {`(.*)ab(.*)a`, 2},
302 {`(.*)(ab)(.*)a`, 3},
303 {`(.*)((a)b)(.*)a`, 4},
304 {`(.*)(\(ab)(.*)a`, 3},
305 {`(.*)(\(a\)b)(.*)a`, 3},
306 }
307
308 func TestNumSubexp(t *testing.T) {
309 for _, c := range numSubexpCases {
310 re := MustCompile(c.input)
311 n := re.NumSubexp()
312 if n != c.expected {
313 t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected)
314 }
315 }
316 }
317
318 func BenchmarkLiteral(b *testing.B) {
319 x := strings.Repeat("x", 50) + "y"
320 b.StopTimer()
321 re := MustCompile("y")
322 b.StartTimer()
323 for i := 0; i < b.N; i++ {
324 if !re.MatchString(x) {
325 println("no match!")
326 break
327 }
328 }
329 }
330
331 func BenchmarkNotLiteral(b *testing.B) {
332 x := strings.Repeat("x", 50) + "y"
333 b.StopTimer()
334 re := MustCompile(".y")
335 b.StartTimer()
336 for i := 0; i < b.N; i++ {
337 if !re.MatchString(x) {
338 println("no match!")
339 break
340 }
341 }
342 }
343
344 func BenchmarkMatchClass(b *testing.B) {
345 b.StopTimer()
346 x := strings.Repeat("xxxx", 20) + "w"
347 re := MustCompile("[abcdw]")
348 b.StartTimer()
349 for i := 0; i < b.N; i++ {
350 if !re.MatchString(x) {
351 println("no match!")
352 break
353 }
354 }
355 }
356
357 func BenchmarkMatchClass_InRange(b *testing.B) {
358 b.StopTimer()
359
360
361 x := strings.Repeat("bbbb", 20) + "c"
362 re := MustCompile("[ac]")
363 b.StartTimer()
364 for i := 0; i < b.N; i++ {
365 if !re.MatchString(x) {
366 println("no match!")
367 break
368 }
369 }
370 }
371
372 func BenchmarkReplaceAll(b *testing.B) {
373 x := "abcdefghijklmnopqrstuvwxyz"
374 b.StopTimer()
375 re := MustCompile("[cjrw]")
376 b.StartTimer()
377 for i := 0; i < b.N; i++ {
378 re.ReplaceAllString(x, "")
379 }
380 }
381
382 func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
383 b.StopTimer()
384 x := []byte("abcdefghijklmnopqrstuvwxyz")
385 re := MustCompile("^zbc(d|e)")
386 b.StartTimer()
387 for i := 0; i < b.N; i++ {
388 re.Match(x)
389 }
390 }
391
392 func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
393 b.StopTimer()
394 x := []byte("abcdefghijklmnopqrstuvwxyz")
395 for i := 0; i < 15; i++ {
396 x = append(x, x...)
397 }
398 re := MustCompile("^zbc(d|e)")
399 b.StartTimer()
400 for i := 0; i < b.N; i++ {
401 re.Match(x)
402 }
403 }
404
405 func BenchmarkAnchoredShortMatch(b *testing.B) {
406 b.StopTimer()
407 x := []byte("abcdefghijklmnopqrstuvwxyz")
408 re := MustCompile("^.bc(d|e)")
409 b.StartTimer()
410 for i := 0; i < b.N; i++ {
411 re.Match(x)
412 }
413 }
414
415 func BenchmarkAnchoredLongMatch(b *testing.B) {
416 b.StopTimer()
417 x := []byte("abcdefghijklmnopqrstuvwxyz")
418 for i := 0; i < 15; i++ {
419 x = append(x, x...)
420 }
421 re := MustCompile("^.bc(d|e)")
422 b.StartTimer()
423 for i := 0; i < b.N; i++ {
424 re.Match(x)
425 }
426 }