github.com/galaxyobe/gen@v0.0.0-20220910125335-392fa8f0990f/cmd/deepcopy-gen/generators/deepcopy_test.go (about)

     1  /*
     2  Copyright 2016 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 generators
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	"k8s.io/gengo/types"
    24  )
    25  
    26  func Test_isRootedUnder(t *testing.T) {
    27  	testCases := []struct {
    28  		path   string
    29  		roots  []string
    30  		expect bool
    31  	}{
    32  		{
    33  			path:   "/foo/bar",
    34  			roots:  nil,
    35  			expect: false,
    36  		},
    37  		{
    38  			path:   "/foo/bar",
    39  			roots:  []string{},
    40  			expect: false,
    41  		},
    42  		{
    43  			path: "/foo/bar",
    44  			roots: []string{
    45  				"/bad",
    46  			},
    47  			expect: false,
    48  		},
    49  		{
    50  			path: "/foo/bar",
    51  			roots: []string{
    52  				"/foo",
    53  			},
    54  			expect: true,
    55  		},
    56  		{
    57  			path: "/foo/bar",
    58  			roots: []string{
    59  				"/bad",
    60  				"/foo",
    61  			},
    62  			expect: true,
    63  		},
    64  		{
    65  			path: "/foo/bar/qux/zorb",
    66  			roots: []string{
    67  				"/foo/bar/qux",
    68  			},
    69  			expect: true,
    70  		},
    71  		{
    72  			path: "/foo/bar",
    73  			roots: []string{
    74  				"/foo/bar",
    75  			},
    76  			expect: true,
    77  		},
    78  		{
    79  			path: "/foo/barn",
    80  			roots: []string{
    81  				"/foo/bar",
    82  			},
    83  			expect: false,
    84  		},
    85  		{
    86  			path: "/foo/bar",
    87  			roots: []string{
    88  				"/foo/barn",
    89  			},
    90  			expect: false,
    91  		},
    92  		{
    93  			path: "/foo/bar",
    94  			roots: []string{
    95  				"",
    96  			},
    97  			expect: true,
    98  		},
    99  	}
   100  
   101  	for i, tc := range testCases {
   102  		r := isRootedUnder(tc.path, tc.roots)
   103  		if r != tc.expect {
   104  			t.Errorf("case[%d]: expected %t, got %t for %q in %q", i, tc.expect, r, tc.path, tc.roots)
   105  		}
   106  	}
   107  }
   108  
   109  func Test_deepCopyMethod(t *testing.T) {
   110  	testCases := []struct {
   111  		typ    types.Type
   112  		expect bool
   113  		error  bool
   114  	}{
   115  		{
   116  			typ: types.Type{
   117  				Name: types.Name{Package: "pkgname", Name: "typename"},
   118  				Kind: types.Builtin,
   119  				// No DeepCopy method.
   120  				Methods: map[string]*types.Type{},
   121  			},
   122  			expect: false,
   123  		},
   124  		{
   125  			typ: types.Type{
   126  				Name: types.Name{Package: "pkgname", Name: "typename"},
   127  				Kind: types.Builtin,
   128  				Methods: map[string]*types.Type{
   129  					// No DeepCopy method.
   130  					"method": {
   131  						Name: types.Name{Package: "pkgname", Name: "func()"},
   132  						Kind: types.Func,
   133  						Signature: &types.Signature{
   134  							Receiver: &types.Type{
   135  								Kind: types.Pointer,
   136  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   137  							},
   138  							Parameters: []*types.Type{},
   139  							Results:    []*types.Type{},
   140  						},
   141  					},
   142  				},
   143  			},
   144  			expect: false,
   145  		},
   146  		{
   147  			typ: types.Type{
   148  				Name: types.Name{Package: "pkgname", Name: "typename"},
   149  				Kind: types.Builtin,
   150  				Methods: map[string]*types.Type{
   151  					// Wrong signature (no result).
   152  					"DeepCopy": {
   153  						Name: types.Name{Package: "pkgname", Name: "func()"},
   154  						Kind: types.Func,
   155  						Signature: &types.Signature{
   156  							Receiver: &types.Type{
   157  								Kind: types.Pointer,
   158  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   159  							},
   160  							Parameters: []*types.Type{},
   161  							Results:    []*types.Type{},
   162  						},
   163  					},
   164  				},
   165  			},
   166  			expect: false,
   167  			error:  true,
   168  		},
   169  		{
   170  			typ: types.Type{
   171  				Name: types.Name{Package: "pkgname", Name: "typename"},
   172  				Kind: types.Builtin,
   173  				Methods: map[string]*types.Type{
   174  					// Wrong signature (wrong result).
   175  					"DeepCopy": {
   176  						Name: types.Name{Package: "pkgname", Name: "func() int"},
   177  						Kind: types.Func,
   178  						Signature: &types.Signature{
   179  							Receiver: &types.Type{
   180  								Kind: types.Pointer,
   181  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   182  							},
   183  							Parameters: []*types.Type{},
   184  							Results: []*types.Type{
   185  								{
   186  									Name: types.Name{Name: "int"},
   187  									Kind: types.Builtin,
   188  								},
   189  							},
   190  						},
   191  					},
   192  				},
   193  			},
   194  			expect: false,
   195  			error:  true,
   196  		},
   197  		{
   198  			typ: types.Type{
   199  				Name: types.Name{Package: "pkgname", Name: "typename"},
   200  				Kind: types.Builtin,
   201  				Methods: map[string]*types.Type{
   202  					// Wrong signature with pointer receiver, but non-pointer result.
   203  					"DeepCopy": {
   204  						Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
   205  						Kind: types.Func,
   206  						Signature: &types.Signature{
   207  							Receiver: &types.Type{
   208  								Kind: types.Pointer,
   209  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   210  							},
   211  							Parameters: []*types.Type{},
   212  							Results: []*types.Type{
   213  								{
   214  									Name: types.Name{Package: "pkgname", Name: "typename"},
   215  									Kind: types.Builtin,
   216  								},
   217  							},
   218  						},
   219  					},
   220  				},
   221  			},
   222  			expect: false,
   223  			error:  true,
   224  		},
   225  		{
   226  			typ: types.Type{
   227  				Name: types.Name{Package: "pkgname", Name: "typename"},
   228  				Kind: types.Builtin,
   229  				Methods: map[string]*types.Type{
   230  					// Wrong signature with non-pointer receiver, but pointer result.
   231  					"DeepCopy": {
   232  						Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
   233  						Kind: types.Func,
   234  						Signature: &types.Signature{
   235  							Receiver:   &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   236  							Parameters: []*types.Type{},
   237  							Results: []*types.Type{
   238  								{
   239  									Kind: types.Pointer,
   240  									Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   241  								},
   242  							},
   243  						},
   244  					},
   245  				},
   246  			},
   247  			expect: false,
   248  			error:  true,
   249  		},
   250  		{
   251  			typ: types.Type{
   252  				Name: types.Name{Package: "pkgname", Name: "typename"},
   253  				Kind: types.Builtin,
   254  				Methods: map[string]*types.Type{
   255  					// Correct signature with non-pointer receiver.
   256  					"DeepCopy": {
   257  						Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
   258  						Kind: types.Func,
   259  						Signature: &types.Signature{
   260  							Receiver:   &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   261  							Parameters: []*types.Type{},
   262  							Results: []*types.Type{
   263  								{
   264  									Name: types.Name{Package: "pkgname", Name: "typename"},
   265  									Kind: types.Builtin,
   266  								},
   267  							},
   268  						},
   269  					},
   270  				},
   271  			},
   272  			expect: true,
   273  		},
   274  		{
   275  			typ: types.Type{
   276  				Name: types.Name{Package: "pkgname", Name: "typename"},
   277  				Kind: types.Builtin,
   278  				Methods: map[string]*types.Type{
   279  					// Correct signature with pointer receiver.
   280  					"DeepCopy": {
   281  						Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"},
   282  						Kind: types.Func,
   283  						Signature: &types.Signature{
   284  							Receiver: &types.Type{
   285  								Kind: types.Pointer,
   286  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   287  							},
   288  							Parameters: []*types.Type{},
   289  							Results: []*types.Type{
   290  								{
   291  									Kind: types.Pointer,
   292  									Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   293  								},
   294  							},
   295  						},
   296  					},
   297  				},
   298  			},
   299  			expect: true,
   300  		},
   301  		{
   302  			typ: types.Type{
   303  				Name: types.Name{Package: "pkgname", Name: "typename"},
   304  				Kind: types.Builtin,
   305  				Methods: map[string]*types.Type{
   306  					// Wrong signature (has params).
   307  					"DeepCopy": {
   308  						Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"},
   309  						Kind: types.Func,
   310  						Signature: &types.Signature{
   311  							Receiver: &types.Type{
   312  								Kind: types.Pointer,
   313  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   314  							},
   315  							Parameters: []*types.Type{
   316  								{
   317  									Name: types.Name{Name: "int"},
   318  									Kind: types.Builtin,
   319  								},
   320  							},
   321  							Results: []*types.Type{
   322  								{
   323  									Name: types.Name{Package: "pkgname", Name: "typename"},
   324  									Kind: types.Builtin,
   325  								},
   326  							},
   327  						},
   328  					},
   329  				},
   330  			},
   331  			expect: false,
   332  			error:  true,
   333  		},
   334  		{
   335  			typ: types.Type{
   336  				Name: types.Name{Package: "pkgname", Name: "typename"},
   337  				Kind: types.Builtin,
   338  				Methods: map[string]*types.Type{
   339  					// Wrong signature (extra results).
   340  					"DeepCopy": {
   341  						Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"},
   342  						Kind: types.Func,
   343  						Signature: &types.Signature{
   344  							Receiver: &types.Type{
   345  								Kind: types.Pointer,
   346  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   347  							},
   348  							Parameters: []*types.Type{},
   349  							Results: []*types.Type{
   350  								{
   351  									Name: types.Name{Package: "pkgname", Name: "typename"},
   352  									Kind: types.Builtin,
   353  								},
   354  								{
   355  									Name: types.Name{Name: "int"},
   356  									Kind: types.Builtin,
   357  								},
   358  							},
   359  						},
   360  					},
   361  				},
   362  			},
   363  			expect: false,
   364  			error:  true,
   365  		},
   366  	}
   367  
   368  	for i, tc := range testCases {
   369  		r, err := deepCopyMethod(&tc.typ)
   370  		if tc.error && err == nil {
   371  			t.Errorf("case[%d]: expected an error, got none", i)
   372  		} else if !tc.error && err != nil {
   373  			t.Errorf("case[%d]: expected no error, got: %v", i, err)
   374  		} else if !tc.error && (r != nil) != tc.expect {
   375  			t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r)
   376  		}
   377  	}
   378  }
   379  
   380  func Test_deepCopyIntoMethod(t *testing.T) {
   381  	testCases := []struct {
   382  		typ    types.Type
   383  		expect bool
   384  		error  bool
   385  	}{
   386  		{
   387  			typ: types.Type{
   388  				Name: types.Name{Package: "pkgname", Name: "typename"},
   389  				Kind: types.Builtin,
   390  				// No DeepCopyInto method.
   391  				Methods: map[string]*types.Type{},
   392  			},
   393  			expect: false,
   394  		},
   395  		{
   396  			typ: types.Type{
   397  				Name: types.Name{Package: "pkgname", Name: "typename"},
   398  				Kind: types.Builtin,
   399  				Methods: map[string]*types.Type{
   400  					// No DeepCopyInto method.
   401  					"method": {
   402  						Name: types.Name{Package: "pkgname", Name: "func()"},
   403  						Kind: types.Func,
   404  						Signature: &types.Signature{
   405  							Receiver: &types.Type{
   406  								Kind: types.Pointer,
   407  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   408  							},
   409  							Parameters: []*types.Type{},
   410  							Results:    []*types.Type{},
   411  						},
   412  					},
   413  				},
   414  			},
   415  			expect: false,
   416  		},
   417  		{
   418  			typ: types.Type{
   419  				Name: types.Name{Package: "pkgname", Name: "typename"},
   420  				Kind: types.Builtin,
   421  				Methods: map[string]*types.Type{
   422  					// Wrong signature (no parameter).
   423  					"DeepCopyInto": {
   424  						Name: types.Name{Package: "pkgname", Name: "func()"},
   425  						Kind: types.Func,
   426  						Signature: &types.Signature{
   427  							Receiver: &types.Type{
   428  								Kind: types.Pointer,
   429  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   430  							},
   431  							Parameters: []*types.Type{},
   432  							Results:    []*types.Type{},
   433  						},
   434  					},
   435  				},
   436  			},
   437  			expect: false,
   438  			error:  true,
   439  		},
   440  		{
   441  			typ: types.Type{
   442  				Name: types.Name{Package: "pkgname", Name: "typename"},
   443  				Kind: types.Builtin,
   444  				Methods: map[string]*types.Type{
   445  					// Wrong signature (unexpected result).
   446  					"DeepCopyInto": {
   447  						Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"},
   448  						Kind: types.Func,
   449  						Signature: &types.Signature{
   450  							Receiver: &types.Type{
   451  								Kind: types.Pointer,
   452  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   453  							},
   454  							Parameters: []*types.Type{
   455  								{
   456  									Kind: types.Pointer,
   457  									Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   458  								},
   459  							},
   460  							Results: []*types.Type{
   461  								{
   462  									Name: types.Name{Name: "int"},
   463  									Kind: types.Builtin,
   464  								},
   465  							},
   466  						},
   467  					},
   468  				},
   469  			},
   470  			expect: false,
   471  			error:  true,
   472  		},
   473  		{
   474  			typ: types.Type{
   475  				Name: types.Name{Package: "pkgname", Name: "typename"},
   476  				Kind: types.Builtin,
   477  				Methods: map[string]*types.Type{
   478  					// Wrong signature (non-pointer parameter, pointer receiver).
   479  					"DeepCopyInto": {
   480  						Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"},
   481  						Kind: types.Func,
   482  						Signature: &types.Signature{
   483  							Receiver: &types.Type{
   484  								Kind: types.Pointer,
   485  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   486  							},
   487  							Parameters: []*types.Type{
   488  								{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   489  							},
   490  							Results: []*types.Type{},
   491  						},
   492  					},
   493  				},
   494  			},
   495  			expect: false,
   496  			error:  true,
   497  		},
   498  		{
   499  			typ: types.Type{
   500  				Name: types.Name{Package: "pkgname", Name: "typename"},
   501  				Kind: types.Builtin,
   502  				Methods: map[string]*types.Type{
   503  					// Wrong signature (non-pointer parameter, non-pointer receiver).
   504  					"DeepCopyInto": {
   505  						Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"},
   506  						Kind: types.Func,
   507  						Signature: &types.Signature{
   508  							Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   509  							Parameters: []*types.Type{
   510  								{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   511  							},
   512  							Results: []*types.Type{},
   513  						},
   514  					},
   515  				},
   516  			},
   517  			expect: false,
   518  			error:  true,
   519  		},
   520  		{
   521  			typ: types.Type{
   522  				Name: types.Name{Package: "pkgname", Name: "typename"},
   523  				Kind: types.Builtin,
   524  				Methods: map[string]*types.Type{
   525  					// Correct signature with non-pointer receiver.
   526  					"DeepCopyInto": {
   527  						Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"},
   528  						Kind: types.Func,
   529  						Signature: &types.Signature{
   530  							Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   531  							Parameters: []*types.Type{
   532  								{
   533  									Kind: types.Pointer,
   534  									Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   535  								},
   536  							},
   537  							Results: []*types.Type{},
   538  						},
   539  					},
   540  				},
   541  			},
   542  			expect: true,
   543  		},
   544  		{
   545  			typ: types.Type{
   546  				Name: types.Name{Package: "pkgname", Name: "typename"},
   547  				Kind: types.Builtin,
   548  				Methods: map[string]*types.Type{
   549  					// Correct signature with pointer receiver.
   550  					"DeepCopyInto": {
   551  						Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"},
   552  						Kind: types.Func,
   553  						Signature: &types.Signature{
   554  							Receiver: &types.Type{
   555  								Kind: types.Pointer,
   556  								Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   557  							},
   558  							Parameters: []*types.Type{
   559  								{
   560  									Kind: types.Pointer,
   561  									Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}},
   562  								},
   563  							},
   564  							Results: []*types.Type{},
   565  						},
   566  					},
   567  				},
   568  			},
   569  			expect: true,
   570  		},
   571  	}
   572  
   573  	for i, tc := range testCases {
   574  		r, err := deepCopyIntoMethod(&tc.typ)
   575  		if tc.error && err == nil {
   576  			t.Errorf("case[%d]: expected an error, got none", i)
   577  		} else if !tc.error && err != nil {
   578  			t.Errorf("case[%d]: expected no error, got: %v", i, err)
   579  		} else if !tc.error && (r != nil) != tc.expect {
   580  			t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r)
   581  		}
   582  	}
   583  }
   584  
   585  func Test_extractTagParams(t *testing.T) {
   586  	testCases := []struct {
   587  		comments []string
   588  		expect   *enabledTagValue
   589  	}{
   590  		{
   591  			comments: []string{
   592  				"Human comment",
   593  			},
   594  			expect: nil,
   595  		},
   596  		{
   597  			comments: []string{
   598  				"Human comment",
   599  				"+gen:deepcopy",
   600  			},
   601  			expect: &enabledTagValue{
   602  				value:    "",
   603  				register: false,
   604  			},
   605  		},
   606  		{
   607  			comments: []string{
   608  				"Human comment",
   609  				"+gen:deepcopy=package",
   610  			},
   611  			expect: &enabledTagValue{
   612  				value:    "package",
   613  				register: false,
   614  			},
   615  		},
   616  		{
   617  			comments: []string{
   618  				"Human comment",
   619  				"+gen:deepcopy=package,register",
   620  			},
   621  			expect: &enabledTagValue{
   622  				value:    "package",
   623  				register: true,
   624  			},
   625  		},
   626  		{
   627  			comments: []string{
   628  				"Human comment",
   629  				"+gen:deepcopy=package,register=true",
   630  			},
   631  			expect: &enabledTagValue{
   632  				value:    "package",
   633  				register: true,
   634  			},
   635  		},
   636  		{
   637  			comments: []string{
   638  				"Human comment",
   639  				"+gen:deepcopy=package,register=false",
   640  			},
   641  			expect: &enabledTagValue{
   642  				value:    "package",
   643  				register: false,
   644  			},
   645  		},
   646  	}
   647  
   648  	for i, tc := range testCases {
   649  		r := extractEnabledTag(tc.comments)
   650  		if r == nil && tc.expect != nil {
   651  			t.Errorf("case[%d]: expected non-nil", i)
   652  		}
   653  		if r != nil && tc.expect == nil {
   654  			t.Errorf("case[%d]: expected nil, got %v", i, *r)
   655  		}
   656  		if r != nil && *r != *tc.expect {
   657  			t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r)
   658  		}
   659  	}
   660  }
   661  
   662  func Test_extractInterfacesTag(t *testing.T) {
   663  	testCases := []struct {
   664  		comments, secondComments []string
   665  		expect                   []string
   666  	}{
   667  		{
   668  			comments: []string{},
   669  			expect:   nil,
   670  		},
   671  		{
   672  			comments: []string{
   673  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   674  			},
   675  			expect: []string{
   676  				"k8s.io/kubernetes/runtime.Object",
   677  			},
   678  		},
   679  		{
   680  			comments: []string{
   681  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   682  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.List",
   683  			},
   684  			expect: []string{
   685  				"k8s.io/kubernetes/runtime.Object",
   686  				"k8s.io/kubernetes/runtime.List",
   687  			},
   688  		},
   689  		{
   690  			comments: []string{
   691  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   692  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   693  			},
   694  			expect: []string{
   695  				"k8s.io/kubernetes/runtime.Object",
   696  				"k8s.io/kubernetes/runtime.Object",
   697  			},
   698  		},
   699  		{
   700  			secondComments: []string{
   701  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   702  			},
   703  			expect: []string{
   704  				"k8s.io/kubernetes/runtime.Object",
   705  			},
   706  		},
   707  		{
   708  			comments: []string{
   709  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   710  			},
   711  			secondComments: []string{
   712  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.List",
   713  			},
   714  			expect: []string{
   715  				"k8s.io/kubernetes/runtime.List",
   716  				"k8s.io/kubernetes/runtime.Object",
   717  			},
   718  		},
   719  		{
   720  			comments: []string{
   721  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   722  			},
   723  			secondComments: []string{
   724  				"+gen:deepcopy:interfaces=k8s.io/kubernetes/runtime.Object",
   725  			},
   726  			expect: []string{
   727  				"k8s.io/kubernetes/runtime.Object",
   728  				"k8s.io/kubernetes/runtime.Object",
   729  			},
   730  		},
   731  	}
   732  
   733  	for i, tc := range testCases {
   734  		typ := &types.Type{
   735  			CommentLines:              tc.comments,
   736  			SecondClosestCommentLines: tc.secondComments,
   737  		}
   738  		r := extractInterfacesTag(typ)
   739  		if r == nil && tc.expect != nil {
   740  			t.Errorf("case[%d]: expected non-nil", i)
   741  		}
   742  		if r != nil && tc.expect == nil {
   743  			t.Errorf("case[%d]: expected nil, got %v", i, r)
   744  		}
   745  		if r != nil && !reflect.DeepEqual(r, tc.expect) {
   746  			t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r)
   747  		}
   748  	}
   749  }