278 lines
6.1 KiB
Go
278 lines
6.1 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 TestEscapeGlobExceptAsterisk(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], EscapeGlobExceptAsterisk(pair[0]))
|
|
}
|
|
}
|
|
|
|
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)
|
|
})
|
|
}
|
|
}
|