You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
4.7 KiB
200 lines
4.7 KiB
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package stringutil
|
|
|
|
import (
|
|
"testing"
|
|
|
|
. "github.com/pingcap/check"
|
|
"github.com/pingcap/tidb/util/testleak"
|
|
)
|
|
|
|
func TestT(t *testing.T) {
|
|
CustomVerboseFlag = true
|
|
TestingT(t)
|
|
}
|
|
|
|
var _ = Suite(&testStringUtilSuite{})
|
|
|
|
type testStringUtilSuite struct {
|
|
}
|
|
|
|
func (s *testStringUtilSuite) TestUnquote(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
table := []struct {
|
|
str string
|
|
expect string
|
|
ok bool
|
|
}{
|
|
{``, ``, false},
|
|
{`'`, ``, false},
|
|
{`'abc"`, ``, false},
|
|
{`abcdea`, ``, false},
|
|
{`'abc'def'`, ``, false},
|
|
{`"abc\"`, ``, false},
|
|
|
|
{`"abcdef"`, `abcdef`, true},
|
|
{`"abc'def"`, `abc'def`, true},
|
|
{`"\a汉字测试"`, `a汉字测试`, true},
|
|
{`"☺"`, `☺`, true},
|
|
{`"\xFF"`, `xFF`, true},
|
|
{`"\U00010111"`, `U00010111`, true},
|
|
{`"\U0001011111"`, `U0001011111`, true},
|
|
{`"\a\b\f\n\r\t\v\\\""`, "a\bf\n\r\tv\\\"", true},
|
|
{`"\Z\%\_"`, "\032" + `\%\_`, true},
|
|
{`"abc\0"`, "abc\000", true},
|
|
{`"abc\"abc"`, `abc"abc`, true},
|
|
|
|
{`'abcdef'`, `abcdef`, true},
|
|
{`'"'`, "\"", true},
|
|
{`'\a\b\f\n\r\t\v\\\''`, "a\bf\n\r\tv\\'", true},
|
|
{`' '`, ` `, true},
|
|
{"'\\a汉字'", "a汉字", true},
|
|
{"'\\a\x90'", "a\x90", true},
|
|
{"\"\\a\x18èàø»\x05\"", "a\x18èàø»\x05", true},
|
|
}
|
|
|
|
for _, t := range table {
|
|
x, err := Unquote(t.str)
|
|
c.Assert(x, Equals, t.expect)
|
|
comment := Commentf("source %v", t.str)
|
|
if t.ok {
|
|
c.Assert(err, IsNil, comment)
|
|
} else {
|
|
c.Assert(err, NotNil, comment)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *testStringUtilSuite) TestPatternMatch(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
tbl := []struct {
|
|
pattern string
|
|
input string
|
|
escape byte
|
|
match bool
|
|
}{
|
|
{``, `a`, '\\', false},
|
|
{`a`, `a`, '\\', true},
|
|
{`a`, `b`, '\\', false},
|
|
{`aA`, `aA`, '\\', true},
|
|
{`_`, `a`, '\\', true},
|
|
{`_`, `ab`, '\\', false},
|
|
{`__`, `b`, '\\', false},
|
|
{`%`, `abcd`, '\\', true},
|
|
{`%`, ``, '\\', true},
|
|
{`%b`, `AAA`, '\\', false},
|
|
{`%a%`, `BBB`, '\\', false},
|
|
{`a%`, `BBB`, '\\', false},
|
|
{`\%a`, `%a`, '\\', true},
|
|
{`\%a`, `aa`, '\\', false},
|
|
{`\_a`, `_a`, '\\', true},
|
|
{`\_a`, `aa`, '\\', false},
|
|
{`\\_a`, `\xa`, '\\', true},
|
|
{`\a\b`, `\a\b`, '\\', true},
|
|
{`%%_`, `abc`, '\\', true},
|
|
{`%_%_aA`, "aaaA", '\\', true},
|
|
{`+_a`, `_a`, '+', true},
|
|
{`+%a`, `%a`, '+', true},
|
|
{`\%a`, `%a`, '+', false},
|
|
{`++a`, `+a`, '+', true},
|
|
{`++_a`, `+xa`, '+', true},
|
|
// We may reopen these test when like function go back to case insensitive.
|
|
/*
|
|
{"_ab", "AAB", '\\', true},
|
|
{"%a%", "BAB", '\\', true},
|
|
{"%a", "AAA", '\\', true},
|
|
{"b%", "BBB", '\\', true},
|
|
*/
|
|
}
|
|
for _, v := range tbl {
|
|
patChars, patTypes := CompilePattern(v.pattern, v.escape)
|
|
match := DoMatch(v.input, patChars, patTypes)
|
|
c.Assert(match, Equals, v.match, Commentf("%v", v))
|
|
}
|
|
}
|
|
|
|
func (s *testStringUtilSuite) TestCompileLike2Regexp(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
tbl := []struct {
|
|
pattern string
|
|
regexp string
|
|
}{
|
|
{``, ``},
|
|
{`a`, `a`},
|
|
{`aA`, `aA`},
|
|
{`_`, `.`},
|
|
{`__`, `..`},
|
|
{`%`, `.*`},
|
|
{`%b`, `.*b`},
|
|
{`%a%`, `.*a.*`},
|
|
{`a%`, `a.*`},
|
|
{`\%a`, `%a`},
|
|
{`\_a`, `_a`},
|
|
{`\\_a`, `\.a`},
|
|
{`\a\b`, `\a\b`},
|
|
{`%%_`, `.*`},
|
|
{`%_%_aA`, ".*aA"},
|
|
}
|
|
for _, v := range tbl {
|
|
result := CompileLike2Regexp(v.pattern)
|
|
c.Assert(result, Equals, v.regexp, Commentf("%v", v))
|
|
}
|
|
}
|
|
|
|
func (s *testStringUtilSuite) TestIsExactMatch(c *C) {
|
|
defer testleak.AfterTest(c)()
|
|
tbl := []struct {
|
|
pattern string
|
|
escape byte
|
|
exactMatch bool
|
|
}{
|
|
{``, '\\', true},
|
|
{`_`, '\\', false},
|
|
{`%`, '\\', false},
|
|
{`a`, '\\', true},
|
|
{`a_`, '\\', false},
|
|
{`a%`, '\\', false},
|
|
{`a\_`, '\\', true},
|
|
{`a\%`, '\\', true},
|
|
{`a\\`, '\\', true},
|
|
{`a\\_`, '\\', false},
|
|
{`a+%`, '+', true},
|
|
{`a\%`, '+', false},
|
|
{`a++`, '+', true},
|
|
{`a++_`, '+', false},
|
|
}
|
|
for _, v := range tbl {
|
|
_, patTypes := CompilePattern(v.pattern, v.escape)
|
|
c.Assert(IsExactMatch(patTypes), Equals, v.exactMatch, Commentf("%v", v))
|
|
}
|
|
}
|
|
|
|
func BenchmarkMatchSpecial(b *testing.B) {
|
|
var (
|
|
pattern = `a%a%a%a%a%a%a%a%b`
|
|
target = `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
|
|
escape = byte('\\')
|
|
)
|
|
|
|
patChars, patTypes := CompilePattern(pattern, escape)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
match := DoMatch(target, patChars, patTypes)
|
|
if match {
|
|
b.Fatal("Unmatch expected.")
|
|
}
|
|
}
|
|
}
|
|
|