github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/stringutil/string_util_test.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package stringutil 15 16 import ( 17 "testing" 18 19 . "github.com/whtcorpsinc/check" 20 "github.com/whtcorpsinc/milevadb/soliton/testleak" 21 ) 22 23 func TestT(t *testing.T) { 24 CustomVerboseFlag = true 25 TestingT(t) 26 } 27 28 var _ = Suite(&testStringUtilSuite{}) 29 30 type testStringUtilSuite struct { 31 } 32 33 func (s *testStringUtilSuite) TestUnquote(c *C) { 34 defer testleak.AfterTest(c)() 35 causet := []struct { 36 str string 37 expect string 38 ok bool 39 }{ 40 {``, ``, false}, 41 {`'`, ``, false}, 42 {`'abc"`, ``, false}, 43 {`abcdea`, ``, false}, 44 {`'abc'def'`, ``, false}, 45 {`"abc\"`, ``, false}, 46 47 {`"abcdef"`, `abcdef`, true}, 48 {`"abc'def"`, `abc'def`, true}, 49 {`"\a汉字测试"`, `a汉字测试`, true}, 50 {`"☺"`, `☺`, true}, 51 {`"\xFF"`, `xFF`, true}, 52 {`"\U00010111"`, `U00010111`, true}, 53 {`"\U0001011111"`, `U0001011111`, true}, 54 {`"\a\b\f\n\r\t\v\\\""`, "a\bf\n\r\tv\\\"", true}, 55 {`"\Z\%\_"`, "\032" + `\%\_`, true}, 56 {`"abc\0"`, "abc\000", true}, 57 {`"abc\"abc"`, `abc"abc`, true}, 58 59 {`'abcdef'`, `abcdef`, true}, 60 {`'"'`, "\"", true}, 61 {`'\a\b\f\n\r\t\v\\\''`, "a\bf\n\r\tv\\'", true}, 62 {`' '`, ` `, true}, 63 {"'\\a汉字'", "a汉字", true}, 64 {"'\\a\x90'", "a\x90", true}, 65 {"\"\\a\x18èàø»\x05\"", "a\x18èàø»\x05", true}, 66 } 67 68 for _, t := range causet { 69 x, err := Unquote(t.str) 70 c.Assert(x, Equals, t.expect) 71 comment := Commentf("source %v", t.str) 72 if t.ok { 73 c.Assert(err, IsNil, comment) 74 } else { 75 c.Assert(err, NotNil, comment) 76 } 77 } 78 } 79 80 func (s *testStringUtilSuite) TestPatternMatch(c *C) { 81 defer testleak.AfterTest(c)() 82 tbl := []struct { 83 pattern string 84 input string 85 escape byte 86 match bool 87 }{ 88 {``, `a`, '\\', false}, 89 {`a`, `a`, '\\', true}, 90 {`a`, `b`, '\\', false}, 91 {`aA`, `aA`, '\\', true}, 92 {`_`, `a`, '\\', true}, 93 {`_`, `ab`, '\\', false}, 94 {`__`, `b`, '\\', false}, 95 {`%`, `abcd`, '\\', true}, 96 {`%`, ``, '\\', true}, 97 {`%b`, `AAA`, '\\', false}, 98 {`%a%`, `BBB`, '\\', false}, 99 {`a%`, `BBB`, '\\', false}, 100 {`\%a`, `%a`, '\\', true}, 101 {`\%a`, `aa`, '\\', false}, 102 {`\_a`, `_a`, '\\', true}, 103 {`\_a`, `aa`, '\\', false}, 104 {`\\_a`, `\xa`, '\\', true}, 105 {`\a\b`, `\a\b`, '\\', true}, 106 {`%%_`, `abc`, '\\', true}, 107 {`%_%_aA`, "aaaA", '\\', true}, 108 {`+_a`, `_a`, '+', true}, 109 {`+%a`, `%a`, '+', true}, 110 {`\%a`, `%a`, '+', false}, 111 {`++a`, `+a`, '+', true}, 112 {`++_a`, `+xa`, '+', true}, 113 // We may reopen these test when like function go back to case insensitive. 114 /* 115 {"_ab", "AAB", '\\', true}, 116 {"%a%", "BAB", '\\', true}, 117 {"%a", "AAA", '\\', true}, 118 {"b%", "BBB", '\\', true}, 119 */ 120 } 121 for _, v := range tbl { 122 patChars, patTypes := CompilePattern(v.pattern, v.escape) 123 match := DoMatch(v.input, patChars, patTypes) 124 c.Assert(match, Equals, v.match, Commentf("%v", v)) 125 } 126 } 127 128 func (s *testStringUtilSuite) TestCompileLike2Regexp(c *C) { 129 defer testleak.AfterTest(c)() 130 tbl := []struct { 131 pattern string 132 regexp string 133 }{ 134 {``, ``}, 135 {`a`, `a`}, 136 {`aA`, `aA`}, 137 {`_`, `.`}, 138 {`__`, `..`}, 139 {`%`, `.*`}, 140 {`%b`, `.*b`}, 141 {`%a%`, `.*a.*`}, 142 {`a%`, `a.*`}, 143 {`\%a`, `%a`}, 144 {`\_a`, `_a`}, 145 {`\\_a`, `\.a`}, 146 {`\a\b`, `\a\b`}, 147 {`%%_`, `..*`}, 148 {`%_%_aA`, "...*aA"}, 149 } 150 for _, v := range tbl { 151 result := CompileLike2Regexp(v.pattern) 152 c.Assert(result, Equals, v.regexp, Commentf("%v", v)) 153 } 154 } 155 156 func (s *testStringUtilSuite) TestIsExactMatch(c *C) { 157 defer testleak.AfterTest(c)() 158 tbl := []struct { 159 pattern string 160 escape byte 161 exactMatch bool 162 }{ 163 {``, '\\', true}, 164 {`_`, '\\', false}, 165 {`%`, '\\', false}, 166 {`a`, '\\', true}, 167 {`a_`, '\\', false}, 168 {`a%`, '\\', false}, 169 {`a\_`, '\\', true}, 170 {`a\%`, '\\', true}, 171 {`a\\`, '\\', true}, 172 {`a\\_`, '\\', false}, 173 {`a+%`, '+', true}, 174 {`a\%`, '+', false}, 175 {`a++`, '+', true}, 176 {`a++_`, '+', false}, 177 } 178 for _, v := range tbl { 179 _, patTypes := CompilePattern(v.pattern, v.escape) 180 c.Assert(IsExactMatch(patTypes), Equals, v.exactMatch, Commentf("%v", v)) 181 } 182 } 183 184 func (s *testStringUtilSuite) TestBuildStringFromLabels(c *C) { 185 defer testleak.AfterTest(c)() 186 testcases := []struct { 187 name string 188 labels map[string]string 189 expected string 190 }{ 191 { 192 name: "nil map", 193 labels: nil, 194 expected: "", 195 }, 196 { 197 name: "one label", 198 labels: map[string]string{ 199 "aaa": "bbb", 200 }, 201 expected: "aaa=bbb", 202 }, 203 { 204 name: "two labels", 205 labels: map[string]string{ 206 "aaa": "bbb", 207 "ccc": "ddd", 208 }, 209 expected: "aaa=bbb,ccc=ddd", 210 }, 211 } 212 for _, testcase := range testcases { 213 c.Log(testcase.name) 214 c.Assert(BuildStringFromLabels(testcase.labels), Equals, testcase.expected) 215 } 216 } 217 218 func BenchmarkDoMatch(b *testing.B) { 219 escape := byte('\\') 220 tbl := []struct { 221 pattern string 222 target string 223 }{ 224 {`a%_%_%_%_b`, `aababab`}, 225 {`%_%_a%_%_b`, `bbbaaabb`}, 226 {`a%_%_a%_%_b`, `aaaabbbbbbaaaaaaaaabbbbb`}, 227 } 228 229 for _, v := range tbl { 230 b.Run(v.pattern, func(b *testing.B) { 231 patChars, patTypes := CompilePattern(v.pattern, escape) 232 b.ResetTimer() 233 for i := 0; i < b.N; i++ { 234 match := DoMatch(v.target, patChars, patTypes) 235 if !match { 236 b.Fatal("Match expected.") 237 } 238 } 239 }) 240 } 241 } 242 243 func BenchmarkDoMatchNegative(b *testing.B) { 244 escape := byte('\\') 245 tbl := []struct { 246 pattern string 247 target string 248 }{ 249 {`a%a%a%a%a%a%a%a%b`, `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`}, 250 } 251 252 for _, v := range tbl { 253 b.Run(v.pattern, func(b *testing.B) { 254 patChars, patTypes := CompilePattern(v.pattern, escape) 255 b.ResetTimer() 256 for i := 0; i < b.N; i++ { 257 match := DoMatch(v.target, patChars, patTypes) 258 if match { 259 b.Fatal("Unmatch expected.") 260 } 261 } 262 }) 263 } 264 } 265 266 func BenchmarkBuildStringFromLabels(b *testing.B) { 267 cases := []struct { 268 name string 269 labels map[string]string 270 }{ 271 { 272 name: "normal case", 273 labels: map[string]string{ 274 "aaa": "bbb", 275 "foo": "bar", 276 }, 277 }, 278 } 279 280 for _, testcase := range cases { 281 b.Run(testcase.name, func(b *testing.B) { 282 b.ResetTimer() 283 BuildStringFromLabels(testcase.labels) 284 }) 285 } 286 }