github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/xds/matcher/string_matcher_test.go (about) 1 /* 2 * 3 * Copyright 2021 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package matcher 20 21 import ( 22 "regexp" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 v3matcherpb "github.com/hxx258456/ccgo/go-control-plane/envoy/type/matcher/v3" 27 ) 28 29 func TestStringMatcherFromProto(t *testing.T) { 30 tests := []struct { 31 desc string 32 inputProto *v3matcherpb.StringMatcher 33 wantMatcher StringMatcher 34 wantErr bool 35 }{ 36 { 37 desc: "nil proto", 38 wantErr: true, 39 }, 40 { 41 desc: "empty prefix", 42 inputProto: &v3matcherpb.StringMatcher{ 43 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: ""}, 44 }, 45 wantErr: true, 46 }, 47 { 48 desc: "empty suffix", 49 inputProto: &v3matcherpb.StringMatcher{ 50 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: ""}, 51 }, 52 wantErr: true, 53 }, 54 { 55 desc: "empty contains", 56 inputProto: &v3matcherpb.StringMatcher{ 57 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: ""}, 58 }, 59 wantErr: true, 60 }, 61 { 62 desc: "invalid regex", 63 inputProto: &v3matcherpb.StringMatcher{ 64 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{ 65 SafeRegex: &v3matcherpb.RegexMatcher{Regex: "??"}, 66 }, 67 }, 68 wantErr: true, 69 }, 70 { 71 desc: "happy case exact", 72 inputProto: &v3matcherpb.StringMatcher{ 73 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}, 74 }, 75 wantMatcher: StringMatcher{exactMatch: newStringP("exact")}, 76 }, 77 { 78 desc: "happy case exact ignore case", 79 inputProto: &v3matcherpb.StringMatcher{ 80 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "EXACT"}, 81 IgnoreCase: true, 82 }, 83 wantMatcher: StringMatcher{ 84 exactMatch: newStringP("exact"), 85 ignoreCase: true, 86 }, 87 }, 88 { 89 desc: "happy case prefix", 90 inputProto: &v3matcherpb.StringMatcher{ 91 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}, 92 }, 93 wantMatcher: StringMatcher{prefixMatch: newStringP("prefix")}, 94 }, 95 { 96 desc: "happy case prefix ignore case", 97 inputProto: &v3matcherpb.StringMatcher{ 98 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "PREFIX"}, 99 IgnoreCase: true, 100 }, 101 wantMatcher: StringMatcher{ 102 prefixMatch: newStringP("prefix"), 103 ignoreCase: true, 104 }, 105 }, 106 { 107 desc: "happy case suffix", 108 inputProto: &v3matcherpb.StringMatcher{ 109 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}, 110 }, 111 wantMatcher: StringMatcher{suffixMatch: newStringP("suffix")}, 112 }, 113 { 114 desc: "happy case suffix ignore case", 115 inputProto: &v3matcherpb.StringMatcher{ 116 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "SUFFIX"}, 117 IgnoreCase: true, 118 }, 119 wantMatcher: StringMatcher{ 120 suffixMatch: newStringP("suffix"), 121 ignoreCase: true, 122 }, 123 }, 124 { 125 desc: "happy case regex", 126 inputProto: &v3matcherpb.StringMatcher{ 127 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{ 128 SafeRegex: &v3matcherpb.RegexMatcher{Regex: "good?regex?"}, 129 }, 130 }, 131 wantMatcher: StringMatcher{regexMatch: regexp.MustCompile("good?regex?")}, 132 }, 133 { 134 desc: "happy case contains", 135 inputProto: &v3matcherpb.StringMatcher{ 136 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}, 137 }, 138 wantMatcher: StringMatcher{containsMatch: newStringP("contains")}, 139 }, 140 { 141 desc: "happy case contains ignore case", 142 inputProto: &v3matcherpb.StringMatcher{ 143 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "CONTAINS"}, 144 IgnoreCase: true, 145 }, 146 wantMatcher: StringMatcher{ 147 containsMatch: newStringP("contains"), 148 ignoreCase: true, 149 }, 150 }, 151 } 152 153 for _, test := range tests { 154 t.Run(test.desc, func(t *testing.T) { 155 gotMatcher, err := StringMatcherFromProto(test.inputProto) 156 if (err != nil) != test.wantErr { 157 t.Fatalf("StringMatcherFromProto(%+v) returned err: %v, wantErr: %v", test.inputProto, err, test.wantErr) 158 } 159 if diff := cmp.Diff(gotMatcher, test.wantMatcher, cmp.AllowUnexported(regexp.Regexp{})); diff != "" { 160 t.Fatalf("StringMatcherFromProto(%+v) returned unexpected diff (-got, +want):\n%s", test.inputProto, diff) 161 } 162 }) 163 } 164 } 165 166 func TestMatch(t *testing.T) { 167 var ( 168 exactMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}}) 169 prefixMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}}) 170 suffixMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}}) 171 regexMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: "good?regex?"}}}) 172 containsMatcher, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}}) 173 exactMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 174 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "exact"}, 175 IgnoreCase: true, 176 }) 177 prefixMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 178 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "prefix"}, 179 IgnoreCase: true, 180 }) 181 suffixMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 182 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "suffix"}, 183 IgnoreCase: true, 184 }) 185 containsMatcherIgnoreCase, _ = StringMatcherFromProto(&v3matcherpb.StringMatcher{ 186 MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "contains"}, 187 IgnoreCase: true, 188 }) 189 ) 190 191 tests := []struct { 192 desc string 193 matcher StringMatcher 194 input string 195 wantMatch bool 196 }{ 197 { 198 desc: "exact match success", 199 matcher: exactMatcher, 200 input: "exact", 201 wantMatch: true, 202 }, 203 { 204 desc: "exact match failure", 205 matcher: exactMatcher, 206 input: "not-exact", 207 }, 208 { 209 desc: "exact match success with ignore case", 210 matcher: exactMatcherIgnoreCase, 211 input: "EXACT", 212 wantMatch: true, 213 }, 214 { 215 desc: "exact match failure with ignore case", 216 matcher: exactMatcherIgnoreCase, 217 input: "not-exact", 218 }, 219 { 220 desc: "prefix match success", 221 matcher: prefixMatcher, 222 input: "prefixIsHere", 223 wantMatch: true, 224 }, 225 { 226 desc: "prefix match failure", 227 matcher: prefixMatcher, 228 input: "not-prefix", 229 }, 230 { 231 desc: "prefix match success with ignore case", 232 matcher: prefixMatcherIgnoreCase, 233 input: "PREFIXisHere", 234 wantMatch: true, 235 }, 236 { 237 desc: "prefix match failure with ignore case", 238 matcher: prefixMatcherIgnoreCase, 239 input: "not-PREFIX", 240 }, 241 { 242 desc: "suffix match success", 243 matcher: suffixMatcher, 244 input: "hereIsThesuffix", 245 wantMatch: true, 246 }, 247 { 248 desc: "suffix match failure", 249 matcher: suffixMatcher, 250 input: "suffix-is-not-here", 251 }, 252 { 253 desc: "suffix match success with ignore case", 254 matcher: suffixMatcherIgnoreCase, 255 input: "hereIsTheSuFFix", 256 wantMatch: true, 257 }, 258 { 259 desc: "suffix match failure with ignore case", 260 matcher: suffixMatcherIgnoreCase, 261 input: "SUFFIX-is-not-here", 262 }, 263 { 264 desc: "regex match success", 265 matcher: regexMatcher, 266 input: "goodregex", 267 wantMatch: true, 268 }, 269 { 270 desc: "regex match failure because only part match", 271 matcher: regexMatcher, 272 input: "goodregexa", 273 wantMatch: false, 274 }, 275 { 276 desc: "regex match failure", 277 matcher: regexMatcher, 278 input: "regex-is-not-here", 279 }, 280 { 281 desc: "contains match success", 282 matcher: containsMatcher, 283 input: "IScontainsHERE", 284 wantMatch: true, 285 }, 286 { 287 desc: "contains match failure", 288 matcher: containsMatcher, 289 input: "con-tains-is-not-here", 290 }, 291 { 292 desc: "contains match success with ignore case", 293 matcher: containsMatcherIgnoreCase, 294 input: "isCONTAINShere", 295 wantMatch: true, 296 }, 297 { 298 desc: "contains match failure with ignore case", 299 matcher: containsMatcherIgnoreCase, 300 input: "CON-TAINS-is-not-here", 301 }, 302 } 303 304 for _, test := range tests { 305 t.Run(test.desc, func(t *testing.T) { 306 if gotMatch := test.matcher.Match(test.input); gotMatch != test.wantMatch { 307 t.Errorf("StringMatcher.Match(%s) returned %v, want %v", test.input, gotMatch, test.wantMatch) 308 } 309 }) 310 } 311 } 312 313 func newStringP(s string) *string { 314 return &s 315 }