Files
tidb/pkg/util/stringutil/string_util_test.go

290 lines
6.3 KiB
Go

// 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,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package stringutil
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestUnquote(t *testing.T) {
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 _, v := range table {
x, err := Unquote(v.str)
require.Equal(t, v.expect, x)
if v.ok {
require.Nilf(t, err, "source %v", v)
} else {
require.NotNilf(t, err, "source %v", v)
}
}
}
func TestPatternMatch(t *testing.T) {
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`, '\\', false},
{`\a\b`, `ab`, '\\', true},
{`%%_`, `abc`, '\\', true},
{`%_%_aA`, "aaaA", '\\', true},
{`+_a`, `_a`, '+', true},
{`+%a`, `%a`, '+', true},
{`\%a`, `%a`, '+', false},
{`++a`, `+a`, '+', true},
{`+a`, `a`, '+', true},
{`++_a`, `+xa`, '+', true},
{`___Հ`, `䇇Հ`, '\\', false},
}
for _, v := range tbl {
patChars, patTypes := CompilePattern(v.pattern, v.escape)
match := DoMatch(v.input, patChars, patTypes)
require.Equalf(t, v.match, match, "source %v", v)
}
}
func TestCompileLike2Regexp(t *testing.T) {
tbl := []struct {
pattern string
regexp string
}{
{``, ``},
{`a`, `a`},
{`aA`, `aA`},
{`_`, `.`},
{`__`, `..`},
{`%`, `.*`},
{`%b`, `.*b`},
{`%a%`, `.*a.*`},
{`a%`, `a.*`},
{`\%a`, `%a`},
{`\_a`, `_a`},
{`\\_a`, `\.a`},
{`\a\b`, `ab`},
{`%%_`, `..*`},
{`%_%_aA`, "...*aA"},
}
for _, v := range tbl {
result := CompileLike2Regexp(v.pattern)
require.Equalf(t, v.regexp, result, "source %v", v)
}
}
func TestIsExactMatch(t *testing.T) {
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)
require.Equalf(t, v.exactMatch, IsExactMatch(patTypes), "source %v", v)
}
}
func TestBuildStringFromLabels(t *testing.T) {
tbl := []struct {
name string
labels map[string]string
expected string
}{
{
name: "nil map",
labels: nil,
expected: "",
},
{
name: "one label",
labels: map[string]string{
"aaa": "bbb",
},
expected: "aaa=bbb",
},
{
name: "two labels",
labels: map[string]string{
"aaa": "bbb",
"ccc": "ddd",
},
expected: "aaa=bbb,ccc=ddd",
},
}
for _, v := range tbl {
require.Equalf(t, v.expected, BuildStringFromLabels(v.labels), "source %v", v)
}
}
func TestEscapeGlobQuestionMark(t *testing.T) {
cases := [][2]string{
{"123", "123"},
{"12*3", "12*3"},
{"12?", `12\?`},
{`[1-2]`, `[1-2]`},
}
for _, pair := range cases {
require.Equal(t, pair[1], EscapeGlobQuestionMark(pair[0]))
}
}
func TestMemoizeStr(t *testing.T) {
cnt := 0
slowStringFn := func() string {
cnt++
return "slow"
}
stringer := MemoizeStr(slowStringFn)
require.Equal(t, "slow", stringer.String())
require.Equal(t, "slow", stringer.String())
require.Equal(t, 1, cnt)
}
func BenchmarkDoMatch(b *testing.B) {
escape := byte('\\')
tbl := []struct {
pattern string
target string
}{
{`a%_%_%_%_b`, `aababab`},
{`%_%_a%_%_b`, `bbbaaabb`},
{`a%_%_a%_%_b`, `aaaabbbbbbaaaaaaaaabbbbb`},
}
for _, v := range tbl {
b.Run(v.pattern, func(b *testing.B) {
patChars, patTypes := CompilePattern(v.pattern, escape)
b.ResetTimer()
for i := 0; i < b.N; i++ {
match := DoMatch(v.target, patChars, patTypes)
if !match {
b.Fatal("Match expected.")
}
}
})
}
}
func BenchmarkDoMatchNegative(b *testing.B) {
escape := byte('\\')
tbl := []struct {
pattern string
target string
}{
{`a%a%a%a%a%a%a%a%b`, `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`},
}
for _, v := range tbl {
b.Run(v.pattern, func(b *testing.B) {
patChars, patTypes := CompilePattern(v.pattern, escape)
b.ResetTimer()
for i := 0; i < b.N; i++ {
match := DoMatch(v.target, patChars, patTypes)
if match {
b.Fatal("Unmatch expected.")
}
}
})
}
}
func BenchmarkBuildStringFromLabels(b *testing.B) {
cases := []struct {
labels map[string]string
name string
}{
{
name: "normal case",
labels: map[string]string{
"aaa": "bbb",
"foo": "bar",
},
},
}
for _, testcase := range cases {
b.Run(testcase.name, func(b *testing.B) {
b.ResetTimer()
BuildStringFromLabels(testcase.labels)
})
}
}