1 // Copyright 2009 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.
13 var good_re
= []string{
34 type stringError
struct {
39 var bad_re
= []stringError
{
40 {`*`, ErrBareClosure
},
41 {`(abc`, ErrUnmatchedLpar
},
42 {`abc)`, ErrUnmatchedRpar
},
43 {`x[a-z`, ErrUnmatchedLbkt
},
44 {`abc]`, ErrUnmatchedRbkt
},
45 {`[z-a]`, ErrBadRange
},
46 {`abc\`, ErrExtraneousBackslash
},
47 {`a**`, ErrBadClosure
},
48 {`a*+`, ErrBadClosure
},
49 {`a??`, ErrBadClosure
},
50 {`*`, ErrBareClosure
},
51 {`\x`, ErrBadBackslash
},
54 func compileTest(t
*testing
.T
, expr
string, error os
.Error
) *Regexp
{
55 re
, err
:= Compile(expr
)
57 t
.Error("compiling `", expr
, "`; unexpected error: ", err
.String())
62 func TestGoodCompile(t
*testing
.T
) {
63 for i
:= 0; i
< len(good_re
); i
++ {
64 compileTest(t
, good_re
[i
], nil)
68 func TestBadCompile(t
*testing
.T
) {
69 for i
:= 0; i
< len(bad_re
); i
++ {
70 compileTest(t
, bad_re
[i
].re
, bad_re
[i
].err
)
74 func matchTest(t
*testing
.T
, test
*FindTest
) {
75 re
:= compileTest(t
, test
.pat
, nil)
79 m
:= re
.MatchString(test
.text
)
80 if m
!= (len(test
.matches
) > 0) {
81 t
.Errorf("MatchString failure on %s: %t should be %t", test
, m
, len(test
.matches
) > 0)
84 m
= re
.Match([]byte(test
.text
))
85 if m
!= (len(test
.matches
) > 0) {
86 t
.Errorf("Match failure on %s: %t should be %t", test
, m
, len(test
.matches
) > 0)
90 func TestMatch(t
*testing
.T
) {
91 for _
, test
:= range findTests
{
96 func matchFunctionTest(t
*testing
.T
, test
*FindTest
) {
97 m
, err
:= MatchString(test
.pat
, test
.text
)
101 if m
!= (len(test
.matches
) > 0) {
102 t
.Errorf("Match failure on %s: %t should be %t", test
, m
, len(test
.matches
) > 0)
106 func TestMatchFunction(t
*testing
.T
) {
107 for _
, test
:= range findTests
{
108 matchFunctionTest(t
, &test
)
112 type ReplaceTest
struct {
113 pattern
, replacement
, input
, output
string
116 var replaceTests
= []ReplaceTest
{
117 // Test empty input and/or replacement, with pattern that matches the empty string.
120 {"", "", "abc", "abc"},
121 {"", "x", "abc", "xaxbxcx"},
123 // Test empty input and/or replacement, with pattern that does not match the empty string.
126 {"b", "", "abc", "ac"},
127 {"b", "x", "abc", "axc"},
130 {"y", "", "abc", "abc"},
131 {"y", "x", "abc", "abc"},
133 // Multibyte characters -- verify that we don't try to match in the middle
135 {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
136 {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
138 // Start and end of a string.
139 {"^[a-c]*", "x", "abcdabc", "xdabc"},
140 {"[a-c]*$", "x", "abcdabc", "abcdx"},
141 {"^[a-c]*$", "x", "abcdabc", "abcdabc"},
142 {"^[a-c]*", "x", "abc", "x"},
143 {"[a-c]*$", "x", "abc", "x"},
144 {"^[a-c]*$", "x", "abc", "x"},
145 {"^[a-c]*", "x", "dabce", "xdabce"},
146 {"[a-c]*$", "x", "dabce", "dabcex"},
147 {"^[a-c]*$", "x", "dabce", "dabce"},
148 {"^[a-c]*", "x", "", "x"},
149 {"[a-c]*$", "x", "", "x"},
150 {"^[a-c]*$", "x", "", "x"},
152 {"^[a-c]+", "x", "abcdabc", "xdabc"},
153 {"[a-c]+$", "x", "abcdabc", "abcdx"},
154 {"^[a-c]+$", "x", "abcdabc", "abcdabc"},
155 {"^[a-c]+", "x", "abc", "x"},
156 {"[a-c]+$", "x", "abc", "x"},
157 {"^[a-c]+$", "x", "abc", "x"},
158 {"^[a-c]+", "x", "dabce", "dabce"},
159 {"[a-c]+$", "x", "dabce", "dabce"},
160 {"^[a-c]+$", "x", "dabce", "dabce"},
161 {"^[a-c]+", "x", "", ""},
162 {"[a-c]+$", "x", "", ""},
163 {"^[a-c]+$", "x", "", ""},
166 {"abc", "def", "abcdefg", "defdefg"},
167 {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
168 {"abc", "", "abcdabc", "d"},
169 {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
170 {"abc", "d", "", ""},
171 {"abc", "d", "abc", "d"},
172 {".+", "x", "abc", "x"},
173 {"[a-c]*", "x", "def", "xdxexfx"},
174 {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
175 {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
178 type ReplaceFuncTest
struct {
180 replacement
func(string) string
184 var replaceFuncTests
= []ReplaceFuncTest
{
185 {"[a-c]", func(s
string) string { return "x" + s
+ "y" }, "defabcdef", "defxayxbyxcydef"},
186 {"[a-c]+", func(s
string) string { return "x" + s
+ "y" }, "defabcdef", "defxabcydef"},
187 {"[a-c]*", func(s
string) string { return "x" + s
+ "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
190 func TestReplaceAll(t
*testing
.T
) {
191 for _
, tc
:= range replaceTests
{
192 re
, err
:= Compile(tc
.pattern
)
194 t
.Errorf("Unexpected error compiling %q: %v", tc
.pattern
, err
)
197 actual
:= re
.ReplaceAllString(tc
.input
, tc
.replacement
)
198 if actual
!= tc
.output
{
199 t
.Errorf("%q.Replace(%q,%q) = %q; want %q",
200 tc
.pattern
, tc
.input
, tc
.replacement
, actual
, tc
.output
)
203 actual
= string(re
.ReplaceAll([]byte(tc
.input
), []byte(tc
.replacement
)))
204 if actual
!= tc
.output
{
205 t
.Errorf("%q.Replace(%q,%q) = %q; want %q",
206 tc
.pattern
, tc
.input
, tc
.replacement
, actual
, tc
.output
)
211 func TestReplaceAllFunc(t
*testing
.T
) {
212 for _
, tc
:= range replaceFuncTests
{
213 re
, err
:= Compile(tc
.pattern
)
215 t
.Errorf("Unexpected error compiling %q: %v", tc
.pattern
, err
)
218 actual
:= re
.ReplaceAllStringFunc(tc
.input
, tc
.replacement
)
219 if actual
!= tc
.output
{
220 t
.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
221 tc
.pattern
, tc
.input
, tc
.replacement
, actual
, tc
.output
)
224 actual
= string(re
.ReplaceAllFunc([]byte(tc
.input
), func(s
[]byte) []byte { return []byte(tc
.replacement(string(s
))) }))
225 if actual
!= tc
.output
{
226 t
.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q",
227 tc
.pattern
, tc
.input
, tc
.replacement
, actual
, tc
.output
)
232 type QuoteMetaTest
struct {
233 pattern
, output
string
236 var quoteMetaTests
= []QuoteMetaTest
{
239 {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`},
242 func TestQuoteMeta(t
*testing
.T
) {
243 for _
, tc
:= range quoteMetaTests
{
244 // Verify that QuoteMeta returns the expected string.
245 quoted
:= QuoteMeta(tc
.pattern
)
246 if quoted
!= tc
.output
{
247 t
.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
248 tc
.pattern
, quoted
, tc
.output
)
252 // Verify that the quoted string is in fact treated as expected
253 // by Compile -- i.e. that it matches the original, unquoted string.
254 if tc
.pattern
!= "" {
255 re
, err
:= Compile(quoted
)
257 t
.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc
.pattern
, err
)
260 src
:= "abc" + tc
.pattern
+ "def"
262 replaced
:= re
.ReplaceAllString(src
, repl
)
263 expected
:= "abcxyzdef"
264 if replaced
!= expected
{
265 t
.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
266 tc
.pattern
, src
, repl
, replaced
, expected
)
272 type numSubexpCase
struct {
277 var numSubexpCases
= []numSubexpCase
{
284 {`(.*)(ab)(.*)a`, 3},
285 {`(.*)((a)b)(.*)a`, 4},
286 {`(.*)(\(ab)(.*)a`, 3},
287 {`(.*)(\(a\)b)(.*)a`, 3},
290 func TestNumSubexp(t
*testing
.T
) {
291 for _
, c
:= range numSubexpCases
{
292 re
:= MustCompile(c
.input
)
295 t
.Errorf("NumSubexp for %q returned %d, expected %d", c
.input
, n
, c
.expected
)
300 func BenchmarkLiteral(b
*testing
.B
) {
301 x
:= strings
.Repeat("x", 50)
305 for i
:= 0; i
< b
.N
; i
++ {
306 if !re
.MatchString(x
) {
313 func BenchmarkNotLiteral(b
*testing
.B
) {
314 x
:= strings
.Repeat("x", 49)
316 re
:= MustCompile("^" + x
)
318 for i
:= 0; i
< b
.N
; i
++ {
319 if !re
.MatchString(x
) {
326 func BenchmarkMatchClass(b
*testing
.B
) {
328 x
:= strings
.Repeat("xxxx", 20) + "w"
329 re
:= MustCompile("[abcdw]")
331 for i
:= 0; i
< b
.N
; i
++ {
332 if !re
.MatchString(x
) {
339 func BenchmarkMatchClass_InRange(b
*testing
.B
) {
341 // 'b' is betwen 'a' and 'c', so the charclass
342 // range checking is no help here.
343 x
:= strings
.Repeat("bbbb", 20) + "c"
344 re
:= MustCompile("[ac]")
346 for i
:= 0; i
< b
.N
; i
++ {
347 if !re
.MatchString(x
) {
354 func BenchmarkReplaceAll(b
*testing
.B
) {
355 x
:= "abcdefghijklmnopqrstuvwxyz"
357 re
:= MustCompile("[cjrw]")
359 for i
:= 0; i
< b
.N
; i
++ {
360 re
.ReplaceAllString(x
, "")