Newer
Older
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
"strings";
``,
`.`,
`^.$`,
`a`,
`a*`,
`a+`,
`a?`,
`a|b`,
`a*|b*`,
`(a*|b)(c*|d)`,
`[a-z]`,
`[a-abc-c\-\]\[]`,
`[a-z]+`,
`[]`,
`[abc]`,
`[^1234]`,
Rob Pike
committed
// TODO: nice to do this with a map
Rob Pike
committed
err os.Error;
Rob Pike
committed
stringError{ `*`, ErrBareClosure },
stringError{ `(abc`, ErrUnmatchedLpar },
stringError{ `abc)`, ErrUnmatchedRpar },
stringError{ `x[a-z`, ErrUnmatchedLbkt },
stringError{ `abc]`, ErrUnmatchedRbkt },
stringError{ `[z-a]`, ErrBadRange },
stringError{ `abc\`, ErrExtraneousBackslash },
stringError{ `a**`, ErrBadClosure },
stringError{ `a*+`, ErrBadClosure },
stringError{ `a??`, ErrBadClosure },
stringError{ `*`, ErrBareClosure },
stringError{ `\x`, ErrBadBackslash },
var matches = []tester {
tester{ ``, "", vec{0,0} },
tester{ `a`, "a", vec{0,1} },
tester{ `x`, "y", vec{} },
tester{ `b`, "abc", vec{1,2} },
tester{ `.`, "a", vec{0,1} },
tester{ `.*`, "abcdef", vec{0,6} },
tester{ `^abcd$`, "abcd", vec{0,4} },
tester{ `^bcd'`, "abcdef", vec{} },
tester{ `^abcd$`, "abcde", vec{} },
tester{ `a+`, "baaab", vec{1,4} },
tester{ `a*`, "baaab", vec{0,0} },
tester{ `[a-z]+`, "abcd", vec{0,4} },
tester{ `[^a-z]+`, "ab1234cd", vec{2,6} },
tester{ `[a\-\]z]+`, "az]-bcz", vec{0,4} },
tester{ `[^\n]+`, "abcd\n", vec{0,4} },
tester{ `[日本語]+`, "日本語日本語", vec{0,18} },
tester{ `()`, "", vec{0,0, 0,0} },
tester{ `(a)`, "a", vec{0,1, 0,1} },
tester{ `(.)(.)`, "日a", vec{0,4, 0,3, 3,4} },
tester{ `(.*)`, "", vec{0,0, 0,0} },
tester{ `(.*)`, "abcd", vec{0,4, 0,4} },
tester{ `(..)(..)`, "abcd", vec{0,4, 0,2, 2,4} },
tester{ `(([^xyz]*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 3,4} },
tester{ `((a|b|c)*(d))`, "abcd", vec{0,4, 0,4, 2,3, 3,4} },
tester{ `(((a|b|c)*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 2,3, 3,4} },
tester{ `a*(|(b))c*`, "aacc", vec{0,4, 2,2, -1,-1} },
}
Rob Pike
committed
func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
re, err := Compile(expr);
t.Error("compiling `", expr, "`; unexpected error: ", err.String());
func printVec(t *testing.T, m []int) {
func printStrings(t *testing.T, m []string) {
Rob Pike
committed
l := len(m);
if l == 0 {
t.Log("\t<no match>");
} else {
for i := 0; i < l; i = i+2 {
t.Logf("\t%q", m[i])
}
}
}
func printBytes(t *testing.T, b [][]byte) {
l := len(b);
if l == 0 {
t.Log("\t<no match>");
} else {
for i := 0; i < l; i = i+2 {
t.Logf("\t%q", b[i])
}
}
}
func equal(m1, m2 []int) bool {
return false
}
for i := 0; i < l; i++ {
if m1[i] != m2[i] {
return false
}
}
return true
}
func equalStrings(m1, m2 []string) bool {
Rob Pike
committed
l := len(m1);
if l != len(m2) {
return false
}
for i := 0; i < l; i++ {
if m1[i] != m2[i] {
return false
}
}
return true
}
func equalBytes(m1 [][]byte, m2 []string) bool {
l := len(m1);
if l != len(m2) {
return false
}
for i := 0; i < l; i++ {
if string(m1[i]) != m2[i] {
return false
}
}
return true
}
func executeTest(t *testing.T, expr string, str string, match []int) {
re := compileTest(t, expr, nil);
m := re.ExecuteString(str);
if !equal(m, match) {
t.Error("ExecuteString failure on `", expr, "` matching `", str, "`:");
printVec(t, m);
t.Log("should be:");
printVec(t, match);
}
// now try bytes
m = re.Execute(strings.Bytes(str));
if !equal(m, match) {
Rob Pike
committed
t.Error("Execute failure on `", expr, "` matching `", str, "`:");
printVec(t, m);
printVec(t, match);
compileTest(t, good_re[i], nil);
compileTest(t, bad_re[i].re, bad_re[i].err)
Rob Pike
committed
for i := 0; i < len(matches); i++ {
test := &matches[i];
executeTest(t, test.re, test.text, test.match)
Rob Pike
committed
}
}
func matchTest(t *testing.T, expr string, str string, match []int) {
re := compileTest(t, expr, nil);
Rob Pike
committed
if re == nil {
return
}
m := re.MatchString(str);
if m != (len(match) > 0) {
t.Error("MatchString failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0);
}
// now try bytes
m = re.Match(strings.Bytes(str));
Rob Pike
committed
if m != (len(match) > 0) {
t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0);
}
}
matchTest(t, test.re, test.text, test.match)
Rob Pike
committed
func matchStringsTest(t *testing.T, expr string, str string, match []int) {
re := compileTest(t, expr, nil);
Rob Pike
committed
if re == nil {
return
}
Rob Pike
committed
for i := 0; i < len(match); i++ {
strs[i/2] = str[match[i] : match[i+1]]
}
m := re.MatchStrings(str);
if !equalStrings(m, strs) {
Rob Pike
committed
t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:");
printStrings(t, m);
Rob Pike
committed
t.Log("should be:");
printStrings(t, strs);
Rob Pike
committed
}
// now try bytes
s := re.MatchSlices(strings.Bytes(str));
if !equalBytes(s, strs) {
t.Error("MatchSlices failure on `", expr, "` matching `", str, "`:");
printBytes(t, s);
t.Log("should be:");
printStrings(t, strs);
}
Rob Pike
committed
}
Rob Pike
committed
for i := 0; i < len(matches); i++ {
test := &matches[i];
matchTest(t, test.re, test.text, test.match)
Rob Pike
committed
}
}
func matchFunctionTest(t *testing.T, expr string, str string, match []int) {
m, err := MatchString(expr, str);
Rob Pike
committed
if err == nil {
return
}
if m != (len(match) > 0) {
t.Error("function Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0);
}
}
Rob Pike
committed
for i := 0; i < len(matches); i++ {
test := &matches[i];
matchFunctionTest(t, test.re, test.text, test.match)
Rob Pike
committed
}
}
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
type ReplaceTest struct {
pattern, replacement, input, output string;
}
var replaceTests = []ReplaceTest {
// Test empty input and/or replacement, with pattern that matches the empty string.
ReplaceTest{"", "", "", ""},
ReplaceTest{"", "x", "", "x"},
ReplaceTest{"", "", "abc", "abc"},
ReplaceTest{"", "x", "abc", "xaxbxcx"},
// Test empty input and/or replacement, with pattern that does not match the empty string.
ReplaceTest{"b", "", "", ""},
ReplaceTest{"b", "x", "", ""},
ReplaceTest{"b", "", "abc", "ac"},
ReplaceTest{"b", "x", "abc", "axc"},
ReplaceTest{"y", "", "", ""},
ReplaceTest{"y", "x", "", ""},
ReplaceTest{"y", "", "abc", "abc"},
ReplaceTest{"y", "x", "abc", "abc"},
// Multibyte characters -- verify that we don't try to match in the middle
// of a character.
ReplaceTest{"[a-c]*", "x", "\u65e5", "x\u65e5x"},
ReplaceTest{"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
// Start and end of a string.
ReplaceTest{"^[a-c]*", "x", "abcdabc", "xdabc"},
ReplaceTest{"[a-c]*$", "x", "abcdabc", "abcdx"},
ReplaceTest{"^[a-c]*$", "x", "abcdabc", "abcdabc"},
ReplaceTest{"^[a-c]*", "x", "abc", "x"},
ReplaceTest{"[a-c]*$", "x", "abc", "x"},
ReplaceTest{"^[a-c]*$", "x", "abc", "x"},
ReplaceTest{"^[a-c]*", "x", "dabce", "xdabce"},
ReplaceTest{"[a-c]*$", "x", "dabce", "dabcex"},
ReplaceTest{"^[a-c]*$", "x", "dabce", "dabce"},
ReplaceTest{"^[a-c]*", "x", "", "x"},
ReplaceTest{"[a-c]*$", "x", "", "x"},
ReplaceTest{"^[a-c]*$", "x", "", "x"},
ReplaceTest{"^[a-c]+", "x", "abcdabc", "xdabc"},
ReplaceTest{"[a-c]+$", "x", "abcdabc", "abcdx"},
ReplaceTest{"^[a-c]+$", "x", "abcdabc", "abcdabc"},
ReplaceTest{"^[a-c]+", "x", "abc", "x"},
ReplaceTest{"[a-c]+$", "x", "abc", "x"},
ReplaceTest{"^[a-c]+$", "x", "abc", "x"},
ReplaceTest{"^[a-c]+", "x", "dabce", "dabce"},
ReplaceTest{"[a-c]+$", "x", "dabce", "dabce"},
ReplaceTest{"^[a-c]+$", "x", "dabce", "dabce"},
ReplaceTest{"^[a-c]+", "x", "", ""},
ReplaceTest{"[a-c]+$", "x", "", ""},
ReplaceTest{"^[a-c]+$", "x", "", ""},
// Other cases.
ReplaceTest{"abc", "def", "abcdefg", "defdefg"},
ReplaceTest{"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
ReplaceTest{"abc", "", "abcdabc", "d"},
ReplaceTest{"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
ReplaceTest{"abc", "d", "", ""},
ReplaceTest{"abc", "d", "abc", "d"},
ReplaceTest{".+", "x", "abc", "x"},
ReplaceTest{"[a-c]*", "x", "def", "xdxexfx"},
ReplaceTest{"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
ReplaceTest{"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
}
func TestReplaceAll(t *testing.T) {
re, err := Compile(tc.pattern);
if err != nil {
t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err);
continue;
}
actual := re.ReplaceAllString(tc.input, tc.replacement);
if actual != tc.output {
t.Errorf("%q.Replace(%q,%q) = %q; want %q",
tc.pattern, tc.input, tc.replacement, actual, tc.output);
}
// now try bytes
actual = string(re.ReplaceAll(strings.Bytes(tc.input), strings.Bytes(tc.replacement)));
if actual != tc.output {
t.Errorf("%q.Replace(%q,%q) = %q; want %q",
tc.pattern, tc.input, tc.replacement, actual, tc.output);
}
}
}
type QuoteMetaTest struct {
pattern, output string;
}
var quoteMetaTests = []QuoteMetaTest {
QuoteMetaTest{``, ``},
QuoteMetaTest{`foo`, `foo`},
QuoteMetaTest{`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`},
}
func TestQuoteMeta(t *testing.T) {
// Verify that QuoteMeta returns the expected string.
quoted := QuoteMeta(tc.pattern);
if quoted != tc.output {
t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
tc.pattern, quoted, tc.output);
continue;
}
// Verify that the quoted string is in fact treated as expected
// by Compile -- i.e. that it matches the original, unquoted string.
if tc.pattern != "" {
re, err := Compile(quoted);
if err != nil {
t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err);
continue;
}
src := "abc" + tc.pattern + "def";
repl := "xyz";
replaced := re.ReplaceAllString(src, repl);
expected := "abcxyzdef";
if replaced != expected {
t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
tc.pattern, src, repl, replaced, expected);
}
}
}
}
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
type matchCase struct {
matchfunc string;
input string;
n int;
regexp string;
expected []string;
}
var matchCases = []matchCase {
matchCase{"match", " aa b", 0, "[^ ]+", []string { "aa", "b" }},
matchCase{"match", " aa b", 0, "[^ ]*", []string { "", "aa", "b" }},
matchCase{"match", "a b c", 0, "[^ ]*", []string { "a", "b", "c" }},
matchCase{"match", "a:a: a:", 0, "^.:", []string { "a:" }},
matchCase{"match", "", 0, "[^ ]*", []string { "" }},
matchCase{"match", "", 0, "", []string { "" }},
matchCase{"match", "a", 0, "", []string { "", "" }},
matchCase{"match", "ab", 0, "^", []string { "", }},
matchCase{"match", "ab", 0, "$", []string { "", }},
matchCase{"match", "ab", 0, "X*", []string { "", "", "" }},
matchCase{"match", "aX", 0, "X*", []string { "", "X" }},
matchCase{"match", "XabX", 0, "X*", []string { "X", "", "X" }},
matchCase{"matchit", "", 0, ".", []string {}},
matchCase{"matchit", "abc", 2, ".", []string { "a", "b" }},
matchCase{"matchit", "abc", 0, ".", []string { "a", "b", "c" }},
}
func printStringSlice(t *testing.T, s []string) {
l := len(s);
if l == 0 {
t.Log("\t<empty>");
} else {
for i := 0; i < l; i++ {
t.Logf("\t%q", s[i])
}
}
}
func TestAllMatches(t *testing.T) {
ch := make(chan matchCase);
go func() {
ch <- c;
stringCase := matchCase{
"string" + c.matchfunc,
c.input,
c.n,
c.regexp,
c.expected };
ch <- stringCase;
}
close(ch);
}();
for c := range ch {
var result []string;
switch c.matchfunc {
case "matchit":
result = make([]string, len(c.input) + 1);
i := 0;
b := strings.Bytes(c.input);
for match := range re.AllMatchesIter(b, c.n) {
result[i] = string(match);
i++;
}
result = result[0:i];
case "stringmatchit":
result = make([]string, len(c.input) + 1);
i := 0;
for match := range re.AllMatchesStringIter(c.input, c.n) {
result[i] = match;
i++;
}
result = result[0:i];
case "match":
result = make([]string, len(c.input) + 1);
b := strings.Bytes(c.input);
i := 0;
result[i] = string(match);
i++;
}
result = result[0:i];
case "stringmatch":
result = re.AllMatchesString(c.input, c.n);
}
if !equalStrings(result, c.expected) {
t.Errorf("testing '%s'.%s('%s', %d), expected: ",
c.regexp, c.matchfunc, c.input, c.n);
printStringSlice(t, c.expected);
t.Log("got: ");
printStringSlice(t, result);
t.Log("\n");
}
}
}