1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package generators 18 19import ( 20 "reflect" 21 "testing" 22 23 "k8s.io/gengo/types" 24) 25 26func 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 109func 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 380func 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 585func 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 "+k8s:deepcopy-gen", 600 }, 601 expect: &enabledTagValue{ 602 value: "", 603 register: false, 604 }, 605 }, 606 { 607 comments: []string{ 608 "Human comment", 609 "+k8s:deepcopy-gen=package", 610 }, 611 expect: &enabledTagValue{ 612 value: "package", 613 register: false, 614 }, 615 }, 616 { 617 comments: []string{ 618 "Human comment", 619 "+k8s:deepcopy-gen=package,register", 620 }, 621 expect: &enabledTagValue{ 622 value: "package", 623 register: true, 624 }, 625 }, 626 { 627 comments: []string{ 628 "Human comment", 629 "+k8s:deepcopy-gen=package,register=true", 630 }, 631 expect: &enabledTagValue{ 632 value: "package", 633 register: true, 634 }, 635 }, 636 { 637 comments: []string{ 638 "Human comment", 639 "+k8s:deepcopy-gen=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 662func 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 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 674 }, 675 expect: []string{ 676 "k8s.io/kubernetes/runtime.Object", 677 }, 678 }, 679 { 680 comments: []string{ 681 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 682 "+k8s:deepcopy-gen: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 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 692 "+k8s:deepcopy-gen: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 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 702 }, 703 expect: []string{ 704 "k8s.io/kubernetes/runtime.Object", 705 }, 706 }, 707 { 708 comments: []string{ 709 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 710 }, 711 secondComments: []string{ 712 "+k8s:deepcopy-gen: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 "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", 722 }, 723 secondComments: []string{ 724 "+k8s:deepcopy-gen: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} 750