Home | History | Annotate | Download | only in regexp
      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.
      4 
      5 package regexp
      6 
      7 import (
      8 	"reflect"
      9 	"regexp/syntax"
     10 	"strings"
     11 	"testing"
     12 )
     13 
     14 var good_re = []string{
     15 	``,
     16 	`.`,
     17 	`^.$`,
     18 	`a`,
     19 	`a*`,
     20 	`a+`,
     21 	`a?`,
     22 	`a|b`,
     23 	`a*|b*`,
     24 	`(a*|b)(c*|d)`,
     25 	`[a-z]`,
     26 	`[a-abc-c\-\]\[]`,
     27 	`[a-z]+`,
     28 	`[abc]`,
     29 	`[^1234]`,
     30 	`[^\n]`,
     31 	`\!\\`,
     32 }
     33 
     34 type stringError struct {
     35 	re  string
     36 	err string
     37 }
     38 
     39 var bad_re = []stringError{
     40 	{`*`, "missing argument to repetition operator: `*`"},
     41 	{`+`, "missing argument to repetition operator: `+`"},
     42 	{`?`, "missing argument to repetition operator: `?`"},
     43 	{`(abc`, "missing closing ): `(abc`"},
     44 	{`abc)`, "unexpected ): `abc)`"},
     45 	{`x[a-z`, "missing closing ]: `[a-z`"},
     46 	{`[z-a]`, "invalid character class range: `z-a`"},
     47 	{`abc\`, "trailing backslash at end of expression"},
     48 	{`a**`, "invalid nested repetition operator: `**`"},
     49 	{`a*+`, "invalid nested repetition operator: `*+`"},
     50 	{`\x`, "invalid escape sequence: `\\x`"},
     51 }
     52 
     53 func compileTest(t *testing.T, expr string, error string) *Regexp {
     54 	re, err := Compile(expr)
     55 	if error == "" && err != nil {
     56 		t.Error("compiling `", expr, "`; unexpected error: ", err.Error())
     57 	}
     58 	if error != "" && err == nil {
     59 		t.Error("compiling `", expr, "`; missing error")
     60 	} else if error != "" && !strings.Contains(err.Error(), error) {
     61 		t.Error("compiling `", expr, "`; wrong error: ", err.Error(), "; want ", error)
     62 	}
     63 	return re
     64 }
     65 
     66 func TestGoodCompile(t *testing.T) {
     67 	for i := 0; i < len(good_re); i++ {
     68 		compileTest(t, good_re[i], "")
     69 	}
     70 }
     71 
     72 func TestBadCompile(t *testing.T) {
     73 	for i := 0; i < len(bad_re); i++ {
     74 		compileTest(t, bad_re[i].re, bad_re[i].err)
     75 	}
     76 }
     77 
     78 func matchTest(t *testing.T, test *FindTest) {
     79 	re := compileTest(t, test.pat, "")
     80 	if re == nil {
     81 		return
     82 	}
     83 	m := re.MatchString(test.text)
     84 	if m != (len(test.matches) > 0) {
     85 		t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0)
     86 	}
     87 	// now try bytes
     88 	m = re.Match([]byte(test.text))
     89 	if m != (len(test.matches) > 0) {
     90 		t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
     91 	}
     92 }
     93 
     94 func TestMatch(t *testing.T) {
     95 	for _, test := range findTests {
     96 		matchTest(t, &test)
     97 	}
     98 }
     99 
    100 func matchFunctionTest(t *testing.T, test *FindTest) {
    101 	m, err := MatchString(test.pat, test.text)
    102 	if err == nil {
    103 		return
    104 	}
    105 	if m != (len(test.matches) > 0) {
    106 		t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0)
    107 	}
    108 }
    109 
    110 func TestMatchFunction(t *testing.T) {
    111 	for _, test := range findTests {
    112 		matchFunctionTest(t, &test)
    113 	}
    114 }
    115 
    116 type ReplaceTest struct {
    117 	pattern, replacement, input, output string
    118 }
    119 
    120 var replaceTests = []ReplaceTest{
    121 	// Test empty input and/or replacement, with pattern that matches the empty string.
    122 	{"", "", "", ""},
    123 	{"", "x", "", "x"},
    124 	{"", "", "abc", "abc"},
    125 	{"", "x", "abc", "xaxbxcx"},
    126 
    127 	// Test empty input and/or replacement, with pattern that does not match the empty string.
    128 	{"b", "", "", ""},
    129 	{"b", "x", "", ""},
    130 	{"b", "", "abc", "ac"},
    131 	{"b", "x", "abc", "axc"},
    132 	{"y", "", "", ""},
    133 	{"y", "x", "", ""},
    134 	{"y", "", "abc", "abc"},
    135 	{"y", "x", "abc", "abc"},
    136 
    137 	// Multibyte characters -- verify that we don't try to match in the middle
    138 	// of a character.
    139 	{"[a-c]*", "x", "\u65e5", "x\u65e5x"},
    140 	{"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
    141 
    142 	// Start and end of a string.
    143 	{"^[a-c]*", "x", "abcdabc", "xdabc"},
    144 	{"[a-c]*$", "x", "abcdabc", "abcdx"},
    145 	{"^[a-c]*$", "x", "abcdabc", "abcdabc"},
    146 	{"^[a-c]*", "x", "abc", "x"},
    147 	{"[a-c]*$", "x", "abc", "x"},
    148 	{"^[a-c]*$", "x", "abc", "x"},
    149 	{"^[a-c]*", "x", "dabce", "xdabce"},
    150 	{"[a-c]*$", "x", "dabce", "dabcex"},
    151 	{"^[a-c]*$", "x", "dabce", "dabce"},
    152 	{"^[a-c]*", "x", "", "x"},
    153 	{"[a-c]*$", "x", "", "x"},
    154 	{"^[a-c]*$", "x", "", "x"},
    155 
    156 	{"^[a-c]+", "x", "abcdabc", "xdabc"},
    157 	{"[a-c]+$", "x", "abcdabc", "abcdx"},
    158 	{"^[a-c]+$", "x", "abcdabc", "abcdabc"},
    159 	{"^[a-c]+", "x", "abc", "x"},
    160 	{"[a-c]+$", "x", "abc", "x"},
    161 	{"^[a-c]+$", "x", "abc", "x"},
    162 	{"^[a-c]+", "x", "dabce", "dabce"},
    163 	{"[a-c]+$", "x", "dabce", "dabce"},
    164 	{"^[a-c]+$", "x", "dabce", "dabce"},
    165 	{"^[a-c]+", "x", "", ""},
    166 	{"[a-c]+$", "x", "", ""},
    167 	{"^[a-c]+$", "x", "", ""},
    168 
    169 	// Other cases.
    170 	{"abc", "def", "abcdefg", "defdefg"},
    171 	{"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
    172 	{"abc", "", "abcdabc", "d"},
    173 	{"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
    174 	{"abc", "d", "", ""},
    175 	{"abc", "d", "abc", "d"},
    176 	{".+", "x", "abc", "x"},
    177 	{"[a-c]*", "x", "def", "xdxexfx"},
    178 	{"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
    179 	{"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
    180 
    181 	// Substitutions
    182 	{"a+", "($0)", "banana", "b(a)n(a)n(a)"},
    183 	{"a+", "(${0})", "banana", "b(a)n(a)n(a)"},
    184 	{"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"},
    185 	{"a+", "(${0})$0", "banana", "b(a)an(a)an(a)a"},
    186 	{"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, world"},
    187 	{"hello, (.+)", "goodbye, $1x", "hello, world", "goodbye, "},
    188 	{"hello, (.+)", "goodbye, ${1}x", "hello, world", "goodbye, worldx"},
    189 	{"hello, (.+)", "<$0><$1><$2><$3>", "hello, world", "<hello, world><world><><>"},
    190 	{"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, world!"},
    191 	{"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, world"},
    192 	{"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "hihihi"},
    193 	{"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "byebyebye"},
    194 	{"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", ""},
    195 	{"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "hiyz"},
    196 	{"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $x"},
    197 	{"a+", "${oops", "aaa", "${oops"},
    198 	{"a+", "$$", "aaa", "$"},
    199 	{"a+", "$", "aaa", "$"},
    200 
    201 	// Substitution when subexpression isn't found
    202 	{"(x)?", "$1", "123", "123"},
    203 	{"abc", "$1", "123", "123"},
    204 }
    205 
    206 var replaceLiteralTests = []ReplaceTest{
    207 	// Substitutions
    208 	{"a+", "($0)", "banana", "b($0)n($0)n($0)"},
    209 	{"a+", "(${0})", "banana", "b(${0})n(${0})n(${0})"},
    210 	{"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"},
    211 	{"a+", "(${0})$0", "banana", "b(${0})$0n(${0})$0n(${0})$0"},
    212 	{"hello, (.+)", "goodbye, ${1}", "hello, world", "goodbye, ${1}"},
    213 	{"hello, (?P<noun>.+)", "goodbye, $noun!", "hello, world", "goodbye, $noun!"},
    214 	{"hello, (?P<noun>.+)", "goodbye, ${noun}", "hello, world", "goodbye, ${noun}"},
    215 	{"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "hi", "$x$x$x"},
    216 	{"(?P<x>hi)|(?P<x>bye)", "$x$x$x", "bye", "$x$x$x"},
    217 	{"(?P<x>hi)|(?P<x>bye)", "$xyz", "hi", "$xyz"},
    218 	{"(?P<x>hi)|(?P<x>bye)", "${x}yz", "hi", "${x}yz"},
    219 	{"(?P<x>hi)|(?P<x>bye)", "hello $$x", "hi", "hello $$x"},
    220 	{"a+", "${oops", "aaa", "${oops"},
    221 	{"a+", "$$", "aaa", "$$"},
    222 	{"a+", "$", "aaa", "$"},
    223 }
    224 
    225 type ReplaceFuncTest struct {
    226 	pattern       string
    227 	replacement   func(string) string
    228 	input, output string
    229 }
    230 
    231 var replaceFuncTests = []ReplaceFuncTest{
    232 	{"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
    233 	{"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
    234 	{"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
    235 }
    236 
    237 func TestReplaceAll(t *testing.T) {
    238 	for _, tc := range replaceTests {
    239 		re, err := Compile(tc.pattern)
    240 		if err != nil {
    241 			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
    242 			continue
    243 		}
    244 		actual := re.ReplaceAllString(tc.input, tc.replacement)
    245 		if actual != tc.output {
    246 			t.Errorf("%q.ReplaceAllString(%q,%q) = %q; want %q",
    247 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    248 		}
    249 		// now try bytes
    250 		actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement)))
    251 		if actual != tc.output {
    252 			t.Errorf("%q.ReplaceAll(%q,%q) = %q; want %q",
    253 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    254 		}
    255 	}
    256 }
    257 
    258 func TestReplaceAllLiteral(t *testing.T) {
    259 	// Run ReplaceAll tests that do not have $ expansions.
    260 	for _, tc := range replaceTests {
    261 		if strings.Contains(tc.replacement, "$") {
    262 			continue
    263 		}
    264 		re, err := Compile(tc.pattern)
    265 		if err != nil {
    266 			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
    267 			continue
    268 		}
    269 		actual := re.ReplaceAllLiteralString(tc.input, tc.replacement)
    270 		if actual != tc.output {
    271 			t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q",
    272 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    273 		}
    274 		// now try bytes
    275 		actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement)))
    276 		if actual != tc.output {
    277 			t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q",
    278 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    279 		}
    280 	}
    281 
    282 	// Run literal-specific tests.
    283 	for _, tc := range replaceLiteralTests {
    284 		re, err := Compile(tc.pattern)
    285 		if err != nil {
    286 			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
    287 			continue
    288 		}
    289 		actual := re.ReplaceAllLiteralString(tc.input, tc.replacement)
    290 		if actual != tc.output {
    291 			t.Errorf("%q.ReplaceAllLiteralString(%q,%q) = %q; want %q",
    292 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    293 		}
    294 		// now try bytes
    295 		actual = string(re.ReplaceAllLiteral([]byte(tc.input), []byte(tc.replacement)))
    296 		if actual != tc.output {
    297 			t.Errorf("%q.ReplaceAllLiteral(%q,%q) = %q; want %q",
    298 				tc.pattern, tc.input, tc.replacement, actual, tc.output)
    299 		}
    300 	}
    301 }
    302 
    303 func TestReplaceAllFunc(t *testing.T) {
    304 	for _, tc := range replaceFuncTests {
    305 		re, err := Compile(tc.pattern)
    306 		if err != nil {
    307 			t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err)
    308 			continue
    309 		}
    310 		actual := re.ReplaceAllStringFunc(tc.input, tc.replacement)
    311 		if actual != tc.output {
    312 			t.Errorf("%q.ReplaceFunc(%q,fn) = %q; want %q",
    313 				tc.pattern, tc.input, actual, tc.output)
    314 		}
    315 		// now try bytes
    316 		actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) }))
    317 		if actual != tc.output {
    318 			t.Errorf("%q.ReplaceFunc(%q,fn) = %q; want %q",
    319 				tc.pattern, tc.input, actual, tc.output)
    320 		}
    321 	}
    322 }
    323 
    324 type MetaTest struct {
    325 	pattern, output, literal string
    326 	isLiteral                bool
    327 }
    328 
    329 var metaTests = []MetaTest{
    330 	{``, ``, ``, true},
    331 	{`foo`, `foo`, `foo`, true},
    332 	{`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator
    333 	{`foo.\$`, `foo\.\\\$`, `foo`, false},     // has escaped operators and real operators
    334 	{`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false},
    335 }
    336 
    337 func TestQuoteMeta(t *testing.T) {
    338 	for _, tc := range metaTests {
    339 		// Verify that QuoteMeta returns the expected string.
    340 		quoted := QuoteMeta(tc.pattern)
    341 		if quoted != tc.output {
    342 			t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`",
    343 				tc.pattern, quoted, tc.output)
    344 			continue
    345 		}
    346 
    347 		// Verify that the quoted string is in fact treated as expected
    348 		// by Compile -- i.e. that it matches the original, unquoted string.
    349 		if tc.pattern != "" {
    350 			re, err := Compile(quoted)
    351 			if err != nil {
    352 				t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err)
    353 				continue
    354 			}
    355 			src := "abc" + tc.pattern + "def"
    356 			repl := "xyz"
    357 			replaced := re.ReplaceAllString(src, repl)
    358 			expected := "abcxyzdef"
    359 			if replaced != expected {
    360 				t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`",
    361 					tc.pattern, src, repl, replaced, expected)
    362 			}
    363 		}
    364 	}
    365 }
    366 
    367 func TestLiteralPrefix(t *testing.T) {
    368 	for _, tc := range metaTests {
    369 		// Literal method needs to scan the pattern.
    370 		re := MustCompile(tc.pattern)
    371 		str, complete := re.LiteralPrefix()
    372 		if complete != tc.isLiteral {
    373 			t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral)
    374 		}
    375 		if str != tc.literal {
    376 			t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
    377 		}
    378 	}
    379 }
    380 
    381 type subexpCase struct {
    382 	input string
    383 	num   int
    384 	names []string
    385 }
    386 
    387 var subexpCases = []subexpCase{
    388 	{``, 0, nil},
    389 	{`.*`, 0, nil},
    390 	{`abba`, 0, nil},
    391 	{`ab(b)a`, 1, []string{"", ""}},
    392 	{`ab(.*)a`, 1, []string{"", ""}},
    393 	{`(.*)ab(.*)a`, 2, []string{"", "", ""}},
    394 	{`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}},
    395 	{`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}},
    396 	{`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}},
    397 	{`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}},
    398 	{`(?P<foo>.*)(?P<bar>(a)b)(?P<foo>.*)a`, 4, []string{"", "foo", "bar", "", "foo"}},
    399 }
    400 
    401 func TestSubexp(t *testing.T) {
    402 	for _, c := range subexpCases {
    403 		re := MustCompile(c.input)
    404 		n := re.NumSubexp()
    405 		if n != c.num {
    406 			t.Errorf("%q: NumSubexp = %d, want %d", c.input, n, c.num)
    407 			continue
    408 		}
    409 		names := re.SubexpNames()
    410 		if len(names) != 1+n {
    411 			t.Errorf("%q: len(SubexpNames) = %d, want %d", c.input, len(names), n)
    412 			continue
    413 		}
    414 		if c.names != nil {
    415 			for i := 0; i < 1+n; i++ {
    416 				if names[i] != c.names[i] {
    417 					t.Errorf("%q: SubexpNames[%d] = %q, want %q", c.input, i, names[i], c.names[i])
    418 				}
    419 			}
    420 		}
    421 	}
    422 }
    423 
    424 var splitTests = []struct {
    425 	s   string
    426 	r   string
    427 	n   int
    428 	out []string
    429 }{
    430 	{"foo:and:bar", ":", -1, []string{"foo", "and", "bar"}},
    431 	{"foo:and:bar", ":", 1, []string{"foo:and:bar"}},
    432 	{"foo:and:bar", ":", 2, []string{"foo", "and:bar"}},
    433 	{"foo:and:bar", "foo", -1, []string{"", ":and:bar"}},
    434 	{"foo:and:bar", "bar", -1, []string{"foo:and:", ""}},
    435 	{"foo:and:bar", "baz", -1, []string{"foo:and:bar"}},
    436 	{"baabaab", "a", -1, []string{"b", "", "b", "", "b"}},
    437 	{"baabaab", "a*", -1, []string{"b", "b", "b"}},
    438 	{"baabaab", "ba*", -1, []string{"", "", "", ""}},
    439 	{"foobar", "f*b*", -1, []string{"", "o", "o", "a", "r"}},
    440 	{"foobar", "f+.*b+", -1, []string{"", "ar"}},
    441 	{"foobooboar", "o{2}", -1, []string{"f", "b", "boar"}},
    442 	{"a,b,c,d,e,f", ",", 3, []string{"a", "b", "c,d,e,f"}},
    443 	{"a,b,c,d,e,f", ",", 0, nil},
    444 	{",", ",", -1, []string{"", ""}},
    445 	{",,,", ",", -1, []string{"", "", "", ""}},
    446 	{"", ",", -1, []string{""}},
    447 	{"", ".*", -1, []string{""}},
    448 	{"", ".+", -1, []string{""}},
    449 	{"", "", -1, []string{}},
    450 	{"foobar", "", -1, []string{"f", "o", "o", "b", "a", "r"}},
    451 	{"abaabaccadaaae", "a*", 5, []string{"", "b", "b", "c", "cadaaae"}},
    452 	{":x:y:z:", ":", -1, []string{"", "x", "y", "z", ""}},
    453 }
    454 
    455 func TestSplit(t *testing.T) {
    456 	for i, test := range splitTests {
    457 		re, err := Compile(test.r)
    458 		if err != nil {
    459 			t.Errorf("#%d: %q: compile error: %s", i, test.r, err.Error())
    460 			continue
    461 		}
    462 
    463 		split := re.Split(test.s, test.n)
    464 		if !reflect.DeepEqual(split, test.out) {
    465 			t.Errorf("#%d: %q: got %q; want %q", i, test.r, split, test.out)
    466 		}
    467 
    468 		if QuoteMeta(test.r) == test.r {
    469 			strsplit := strings.SplitN(test.s, test.r, test.n)
    470 			if !reflect.DeepEqual(split, strsplit) {
    471 				t.Errorf("#%d: Split(%q, %q, %d): regexp vs strings mismatch\nregexp=%q\nstrings=%q", i, test.s, test.r, test.n, split, strsplit)
    472 			}
    473 		}
    474 	}
    475 }
    476 
    477 // Check that one-pass cutoff does trigger.
    478 func TestOnePassCutoff(t *testing.T) {
    479 	re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl)
    480 	if err != nil {
    481 		t.Fatalf("parse: %v", err)
    482 	}
    483 	p, err := syntax.Compile(re.Simplify())
    484 	if err != nil {
    485 		t.Fatalf("compile: %v", err)
    486 	}
    487 	if compileOnePass(p) != notOnePass {
    488 		t.Fatalf("makeOnePass succeeded; wanted notOnePass")
    489 	}
    490 }
    491 
    492 // Check that the same machine can be used with the standard matcher
    493 // and then the backtracker when there are no captures.
    494 func TestSwitchBacktrack(t *testing.T) {
    495 	re := MustCompile(`a|b`)
    496 	long := make([]byte, maxBacktrackVector+1)
    497 
    498 	// The following sequence of Match calls used to panic. See issue #10319.
    499 	re.Match(long)     // triggers standard matcher
    500 	re.Match(long[:1]) // triggers backtracker
    501 }
    502 
    503 func BenchmarkLiteral(b *testing.B) {
    504 	x := strings.Repeat("x", 50) + "y"
    505 	b.StopTimer()
    506 	re := MustCompile("y")
    507 	b.StartTimer()
    508 	for i := 0; i < b.N; i++ {
    509 		if !re.MatchString(x) {
    510 			b.Fatalf("no match!")
    511 		}
    512 	}
    513 }
    514 
    515 func BenchmarkNotLiteral(b *testing.B) {
    516 	x := strings.Repeat("x", 50) + "y"
    517 	b.StopTimer()
    518 	re := MustCompile(".y")
    519 	b.StartTimer()
    520 	for i := 0; i < b.N; i++ {
    521 		if !re.MatchString(x) {
    522 			b.Fatalf("no match!")
    523 		}
    524 	}
    525 }
    526 
    527 func BenchmarkMatchClass(b *testing.B) {
    528 	b.StopTimer()
    529 	x := strings.Repeat("xxxx", 20) + "w"
    530 	re := MustCompile("[abcdw]")
    531 	b.StartTimer()
    532 	for i := 0; i < b.N; i++ {
    533 		if !re.MatchString(x) {
    534 			b.Fatalf("no match!")
    535 		}
    536 	}
    537 }
    538 
    539 func BenchmarkMatchClass_InRange(b *testing.B) {
    540 	b.StopTimer()
    541 	// 'b' is between 'a' and 'c', so the charclass
    542 	// range checking is no help here.
    543 	x := strings.Repeat("bbbb", 20) + "c"
    544 	re := MustCompile("[ac]")
    545 	b.StartTimer()
    546 	for i := 0; i < b.N; i++ {
    547 		if !re.MatchString(x) {
    548 			b.Fatalf("no match!")
    549 		}
    550 	}
    551 }
    552 
    553 func BenchmarkReplaceAll(b *testing.B) {
    554 	x := "abcdefghijklmnopqrstuvwxyz"
    555 	b.StopTimer()
    556 	re := MustCompile("[cjrw]")
    557 	b.StartTimer()
    558 	for i := 0; i < b.N; i++ {
    559 		re.ReplaceAllString(x, "")
    560 	}
    561 }
    562 
    563 func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) {
    564 	b.StopTimer()
    565 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    566 	re := MustCompile("^zbc(d|e)")
    567 	b.StartTimer()
    568 	for i := 0; i < b.N; i++ {
    569 		re.Match(x)
    570 	}
    571 }
    572 
    573 func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) {
    574 	b.StopTimer()
    575 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    576 	for i := 0; i < 15; i++ {
    577 		x = append(x, x...)
    578 	}
    579 	re := MustCompile("^zbc(d|e)")
    580 	b.StartTimer()
    581 	for i := 0; i < b.N; i++ {
    582 		re.Match(x)
    583 	}
    584 }
    585 
    586 func BenchmarkAnchoredShortMatch(b *testing.B) {
    587 	b.StopTimer()
    588 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    589 	re := MustCompile("^.bc(d|e)")
    590 	b.StartTimer()
    591 	for i := 0; i < b.N; i++ {
    592 		re.Match(x)
    593 	}
    594 }
    595 
    596 func BenchmarkAnchoredLongMatch(b *testing.B) {
    597 	b.StopTimer()
    598 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    599 	for i := 0; i < 15; i++ {
    600 		x = append(x, x...)
    601 	}
    602 	re := MustCompile("^.bc(d|e)")
    603 	b.StartTimer()
    604 	for i := 0; i < b.N; i++ {
    605 		re.Match(x)
    606 	}
    607 }
    608 
    609 func BenchmarkOnePassShortA(b *testing.B) {
    610 	b.StopTimer()
    611 	x := []byte("abcddddddeeeededd")
    612 	re := MustCompile("^.bc(d|e)*$")
    613 	b.StartTimer()
    614 	for i := 0; i < b.N; i++ {
    615 		re.Match(x)
    616 	}
    617 }
    618 
    619 func BenchmarkNotOnePassShortA(b *testing.B) {
    620 	b.StopTimer()
    621 	x := []byte("abcddddddeeeededd")
    622 	re := MustCompile(".bc(d|e)*$")
    623 	b.StartTimer()
    624 	for i := 0; i < b.N; i++ {
    625 		re.Match(x)
    626 	}
    627 }
    628 
    629 func BenchmarkOnePassShortB(b *testing.B) {
    630 	b.StopTimer()
    631 	x := []byte("abcddddddeeeededd")
    632 	re := MustCompile("^.bc(?:d|e)*$")
    633 	b.StartTimer()
    634 	for i := 0; i < b.N; i++ {
    635 		re.Match(x)
    636 	}
    637 }
    638 
    639 func BenchmarkNotOnePassShortB(b *testing.B) {
    640 	b.StopTimer()
    641 	x := []byte("abcddddddeeeededd")
    642 	re := MustCompile(".bc(?:d|e)*$")
    643 	b.StartTimer()
    644 	for i := 0; i < b.N; i++ {
    645 		re.Match(x)
    646 	}
    647 }
    648 
    649 func BenchmarkOnePassLongPrefix(b *testing.B) {
    650 	b.StopTimer()
    651 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    652 	re := MustCompile("^abcdefghijklmnopqrstuvwxyz.*$")
    653 	b.StartTimer()
    654 	for i := 0; i < b.N; i++ {
    655 		re.Match(x)
    656 	}
    657 }
    658 
    659 func BenchmarkOnePassLongNotPrefix(b *testing.B) {
    660 	b.StopTimer()
    661 	x := []byte("abcdefghijklmnopqrstuvwxyz")
    662 	re := MustCompile("^.bcdefghijklmnopqrstuvwxyz.*$")
    663 	b.StartTimer()
    664 	for i := 0; i < b.N; i++ {
    665 		re.Match(x)
    666 	}
    667 }
    668