k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/generators/rules/names_match_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package rules 18 19 import ( 20 "reflect" 21 "testing" 22 23 "k8s.io/gengo/v2/types" 24 ) 25 26 func TestNamesMatch(t *testing.T) { 27 tcs := []struct { 28 // name of test case 29 name string 30 t *types.Type 31 32 // expected list of violation fields 33 expected []string 34 }{ 35 // The comments are in format of {goName, jsonName, match}, 36 // {"PodSpec", "podSpec", true}, 37 { 38 name: "simple", 39 t: &types.Type{ 40 Kind: types.Struct, 41 Members: []types.Member{ 42 { 43 Name: "PodSpec", 44 Tags: `json:"podSpec"`, 45 }, 46 }, 47 }, 48 expected: []string{}, 49 }, 50 // {"PodSpec", "podSpec", true}, 51 { 52 name: "multiple_json_tags", 53 t: &types.Type{ 54 Kind: types.Struct, 55 Members: []types.Member{ 56 { 57 Name: "PodSpec", 58 Tags: `json:"podSpec,omitempty"`, 59 }, 60 }, 61 }, 62 expected: []string{}, 63 }, 64 // {"PodSpec", "podSpec", true}, 65 { 66 name: "protobuf_tag", 67 t: &types.Type{ 68 Kind: types.Struct, 69 Members: []types.Member{ 70 { 71 Name: "PodSpec", 72 Tags: `json:"podSpec,omitempty" protobuf:"bytes,1,opt,name=podSpec"`, 73 }, 74 }, 75 }, 76 expected: []string{}, 77 }, 78 // {"", "podSpec", false}, 79 { 80 name: "empty", 81 t: &types.Type{ 82 Kind: types.Struct, 83 Members: []types.Member{ 84 { 85 Name: "", 86 Tags: `json:"podSpec"`, 87 }, 88 }, 89 }, 90 expected: []string{""}, 91 }, 92 // {"PodSpec", "PodSpec", false}, 93 { 94 name: "CamelCase_CamelCase", 95 t: &types.Type{ 96 Kind: types.Struct, 97 Members: []types.Member{ 98 { 99 Name: "PodSpec", 100 Tags: `json:"PodSpec"`, 101 }, 102 }, 103 }, 104 expected: []string{"PodSpec"}, 105 }, 106 // {"podSpec", "podSpec", false}, 107 { 108 name: "camelCase_camelCase", 109 t: &types.Type{ 110 Kind: types.Struct, 111 Members: []types.Member{ 112 { 113 Name: "podSpec", 114 Tags: `json:"podSpec"`, 115 }, 116 }, 117 }, 118 expected: []string{"podSpec"}, 119 }, 120 // {"PodSpec", "spec", false}, 121 { 122 name: "short_json_name", 123 t: &types.Type{ 124 Kind: types.Struct, 125 Members: []types.Member{ 126 { 127 Name: "PodSpec", 128 Tags: `json:"spec"`, 129 }, 130 }, 131 }, 132 expected: []string{"PodSpec"}, 133 }, 134 // {"Spec", "podSpec", false}, 135 { 136 name: "long_json_name", 137 t: &types.Type{ 138 Kind: types.Struct, 139 Members: []types.Member{ 140 { 141 Name: "Spec", 142 Tags: `json:"podSpec"`, 143 }, 144 }, 145 }, 146 expected: []string{"Spec"}, 147 }, 148 // {"JSONSpec", "jsonSpec", true}, 149 { 150 name: "acronym", 151 t: &types.Type{ 152 Kind: types.Struct, 153 Members: []types.Member{ 154 { 155 Name: "JSONSpec", 156 Tags: `json:"jsonSpec"`, 157 }, 158 }, 159 }, 160 expected: []string{}, 161 }, 162 // {"JSONSpec", "jsonspec", false}, 163 { 164 name: "acronym_invalid", 165 t: &types.Type{ 166 Kind: types.Struct, 167 Members: []types.Member{ 168 { 169 Name: "JSONSpec", 170 Tags: `json:"jsonspec"`, 171 }, 172 }, 173 }, 174 expected: []string{"JSONSpec"}, 175 }, 176 // {"HTTPJSONSpec", "httpJSONSpec", true}, 177 { 178 name: "multiple_acronym", 179 t: &types.Type{ 180 Kind: types.Struct, 181 Members: []types.Member{ 182 { 183 Name: "HTTPJSONSpec", 184 Tags: `json:"httpJSONSpec"`, 185 }, 186 }, 187 }, 188 expected: []string{}, 189 }, 190 // // NOTE: this validator cannot tell two sequential all-capital words from one word, 191 // // therefore the case below is also considered matched. 192 // {"HTTPJSONSpec", "httpjsonSpec", true}, 193 { 194 name: "multiple_acronym_as_one", 195 t: &types.Type{ 196 Kind: types.Struct, 197 Members: []types.Member{ 198 { 199 Name: "HTTPJSONSpec", 200 Tags: `json:"httpjsonSpec"`, 201 }, 202 }, 203 }, 204 expected: []string{}, 205 }, 206 // NOTE: JSON tags in jsonTagBlacklist should skip evaluation 207 { 208 name: "blacklist_tag_dash", 209 t: &types.Type{ 210 Kind: types.Struct, 211 Members: []types.Member{ 212 { 213 Name: "podSpec", 214 Tags: `json:"-"`, 215 }, 216 }, 217 }, 218 expected: []string{}, 219 }, 220 // {"PodSpec", "-", false}, 221 { 222 name: "invalid_json_name_dash", 223 t: &types.Type{ 224 Kind: types.Struct, 225 Members: []types.Member{ 226 { 227 Name: "PodSpec", 228 Tags: `json:"-,"`, 229 }, 230 }, 231 }, 232 expected: []string{"PodSpec"}, 233 }, 234 // NOTE: JSON names in jsonNameBlacklist should skip evaluation 235 // {"", "", true}, 236 { 237 name: "unspecified", 238 t: &types.Type{ 239 Kind: types.Struct, 240 Members: []types.Member{ 241 { 242 Name: "", 243 Tags: `json:""`, 244 }, 245 }, 246 }, 247 expected: []string{}, 248 }, 249 // {"podSpec", "", true}, 250 { 251 name: "blacklist_empty", 252 t: &types.Type{ 253 Kind: types.Struct, 254 Members: []types.Member{ 255 { 256 Name: "podSpec", 257 Tags: `json:""`, 258 }, 259 }, 260 }, 261 expected: []string{}, 262 }, 263 // {"podSpec", "metadata", true}, 264 { 265 name: "blacklist_metadata", 266 t: &types.Type{ 267 Kind: types.Struct, 268 Members: []types.Member{ 269 { 270 Name: "podSpec", 271 Tags: `json:"metadata"`, 272 }, 273 }, 274 }, 275 expected: []string{}, 276 }, 277 { 278 name: "non_struct", 279 t: &types.Type{ 280 Kind: types.Map, 281 }, 282 expected: []string{}, 283 }, 284 { 285 name: "no_json_tag", 286 t: &types.Type{ 287 Kind: types.Struct, 288 Members: []types.Member{ 289 { 290 Name: "PodSpec", 291 Tags: `podSpec`, 292 }, 293 }, 294 }, 295 expected: []string{"PodSpec"}, 296 }, 297 // NOTE: this is to expand test coverage 298 // {"S", "s", true}, 299 { 300 name: "single_character", 301 t: &types.Type{ 302 Kind: types.Struct, 303 Members: []types.Member{ 304 { 305 Name: "S", 306 Tags: `json:"s"`, 307 }, 308 }, 309 }, 310 expected: []string{}, 311 }, 312 // NOTE: names with disallowed substrings should fail evaluation 313 // {"Pod-Spec", "pod-Spec", false}, 314 { 315 name: "disallowed_substring_dash", 316 t: &types.Type{ 317 Kind: types.Struct, 318 Members: []types.Member{ 319 { 320 Name: "Pod-Spec", 321 Tags: `json:"pod-Spec"`, 322 }, 323 }, 324 }, 325 expected: []string{"Pod-Spec"}, 326 }, 327 // {"Pod_Spec", "pod_Spec", false}, 328 { 329 name: "disallowed_substring_underscore", 330 t: &types.Type{ 331 Kind: types.Struct, 332 Members: []types.Member{ 333 { 334 Name: "Pod_Spec", 335 Tags: `json:"pod_Spec"`, 336 }, 337 }, 338 }, 339 expected: []string{"Pod_Spec"}, 340 }, 341 } 342 343 n := &NamesMatch{} 344 for _, tc := range tcs { 345 if violations, _ := n.Validate(tc.t); !reflect.DeepEqual(violations, tc.expected) { 346 t.Errorf("unexpected validation result: test name %v, want: %v, got: %v", 347 tc.name, tc.expected, violations) 348 } 349 } 350 } 351 352 // TestRuleName tests the Name of API rule. This is to expand test coverage 353 func TestRuleName(t *testing.T) { 354 ruleName := "names_match" 355 n := &NamesMatch{} 356 if n.Name() != ruleName { 357 t.Errorf("unexpected API rule name: want: %v, got: %v", ruleName, n.Name()) 358 } 359 }