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  }