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  }