github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/refactor/rename/rename_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package rename 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/build" 11 "go/token" 12 "os" 13 "path/filepath" 14 "regexp" 15 "strings" 16 "testing" 17 18 "golang.org/x/tools/go/buildutil" 19 ) 20 21 // TODO(adonovan): test reported source positions, somehow. 22 23 func TestConflicts(t *testing.T) { 24 defer func(savedWriteFile func(string, []byte) error, savedReportError func(token.Position, string)) { 25 writeFile = savedWriteFile 26 reportError = savedReportError 27 }(writeFile, reportError) 28 writeFile = func(string, []byte) error { return nil } 29 30 var ctxt *build.Context 31 for _, test := range []struct { 32 ctxt *build.Context // nil => use previous 33 offset, from, to string // values of the -offset/-from and -to flags 34 want string // regexp to match conflict errors, or "OK" 35 }{ 36 // init() checks 37 { 38 ctxt: fakeContext(map[string][]string{ 39 "fmt": {`package fmt; type Stringer interface { String() }`}, 40 "main": {` 41 package main 42 43 import foo "fmt" 44 45 var v foo.Stringer 46 47 func f() { v.String(); f() } 48 `, 49 `package main; var w int`}, 50 }), 51 from: "main.v", to: "init", 52 want: `you cannot have a var at package level named "init"`, 53 }, 54 { 55 from: "main.f", to: "init", 56 want: `renaming this func "f" to "init" would make it a package initializer.*` + 57 `but references to it exist`, 58 }, 59 { 60 from: "/go/src/main/0.go::foo", to: "init", 61 want: `"init" is not a valid imported package name`, 62 }, 63 64 // Export checks 65 { 66 from: "fmt.Stringer", to: "stringer", 67 want: `renaming this type "Stringer" to "stringer" would make it unexported.*` + 68 `breaking references from packages such as "main"`, 69 }, 70 { 71 from: "(fmt.Stringer).String", to: "string", 72 want: `renaming this method "String" to "string" would make it unexported.*` + 73 `breaking references from packages such as "main"`, 74 }, 75 76 // Lexical scope checks 77 { 78 // file/package conflict, same file 79 from: "main.v", to: "foo", 80 want: `renaming this var "v" to "foo" would conflict.*` + 81 `with this imported package name`, 82 }, 83 { 84 // file/package conflict, same file 85 from: "main::foo", to: "v", 86 want: `renaming this imported package name "foo" to "v" would conflict.*` + 87 `with this package member var`, 88 }, 89 { 90 // file/package conflict, different files 91 from: "main.w", to: "foo", 92 want: `renaming this var "w" to "foo" would conflict.*` + 93 `with this imported package name`, 94 }, 95 { 96 // file/package conflict, different files 97 from: "main::foo", to: "w", 98 want: `renaming this imported package name "foo" to "w" would conflict.*` + 99 `with this package member var`, 100 }, 101 { 102 ctxt: main(` 103 package main 104 105 var x, z int 106 107 func f(y int) { 108 print(x) 109 print(y) 110 } 111 112 func g(w int) { 113 print(x) 114 x := 1 115 print(x) 116 }`), 117 from: "main.x", to: "y", 118 want: `renaming this var "x" to "y".*` + 119 `would cause this reference to become shadowed.*` + 120 `by this intervening var definition`, 121 }, 122 { 123 from: "main.g::x", to: "w", 124 want: `renaming this var "x" to "w".*` + 125 `conflicts with var in same block`, 126 }, 127 { 128 from: "main.f::y", to: "x", 129 want: `renaming this var "y" to "x".*` + 130 `would shadow this reference.*` + 131 `to the var declared here`, 132 }, 133 { 134 from: "main.g::w", to: "x", 135 want: `renaming this var "w" to "x".*` + 136 `conflicts with var in same block`, 137 }, 138 { 139 from: "main.z", to: "y", want: "OK", 140 }, 141 142 // Label checks 143 { 144 ctxt: main(` 145 package main 146 147 func f() { 148 foo: 149 goto foo 150 bar: 151 goto bar 152 func(x int) { 153 wiz: 154 goto wiz 155 }(0) 156 } 157 `), 158 from: "main.f::foo", to: "bar", 159 want: `renaming this label "foo" to "bar".*` + 160 `would conflict with this one`, 161 }, 162 { 163 from: "main.f::foo", to: "wiz", want: "OK", 164 }, 165 { 166 from: "main.f::wiz", to: "x", want: "OK", 167 }, 168 { 169 from: "main.f::x", to: "wiz", want: "OK", 170 }, 171 { 172 from: "main.f::wiz", to: "foo", want: "OK", 173 }, 174 175 // Struct fields 176 { 177 ctxt: main(` 178 package main 179 180 type U struct { u int } 181 type V struct { v int } 182 183 func (V) x() {} 184 185 type W (struct { 186 U 187 V 188 w int 189 }) 190 191 func f() { 192 var w W 193 print(w.u) // NB: there is no selection of w.v 194 var _ struct { yy, zz int } 195 } 196 `), 197 // field/field conflict in named struct declaration 198 from: "(main.W).U", to: "w", 199 want: `renaming this field "U" to "w".*` + 200 `would conflict with this field`, 201 }, 202 { 203 // rename type used as embedded field 204 // => rename field 205 // => field/field conflict 206 // This is an entailed renaming; 207 // it would be nice if we checked source positions. 208 from: "main.U", to: "w", 209 want: `renaming this field "U" to "w".*` + 210 `would conflict with this field`, 211 }, 212 { 213 // field/field conflict in unnamed struct declaration 214 from: "main.f::zz", to: "yy", 215 want: `renaming this field "zz" to "yy".*` + 216 `would conflict with this field`, 217 }, 218 219 // Now we test both directions of (u,v) (u,w) (v,w) (u,x) (v,x). 220 // Too bad we don't test position info... 221 { 222 // field/field ambiguity at same promotion level ('from' selection) 223 from: "(main.U).u", to: "v", 224 want: `renaming this field "u" to "v".*` + 225 `would make this reference ambiguous.*` + 226 `with this field`, 227 }, 228 { 229 // field/field ambiguity at same promotion level ('to' selection) 230 from: "(main.V).v", to: "u", 231 want: `renaming this field "v" to "u".*` + 232 `would make this reference ambiguous.*` + 233 `with this field`, 234 }, 235 { 236 // field/method conflict at different promotion level ('from' selection) 237 from: "(main.U).u", to: "w", 238 want: `renaming this field "u" to "w".*` + 239 `would change the referent of this selection.*` + 240 `of this field`, 241 }, 242 { 243 // field/field shadowing at different promotion levels ('to' selection) 244 from: "(main.W).w", to: "u", 245 want: `renaming this field "w" to "u".*` + 246 `would shadow this selection.*` + 247 `of the field declared here`, 248 }, 249 { 250 from: "(main.V).v", to: "w", 251 want: "OK", // since no selections are made ambiguous 252 }, 253 { 254 from: "(main.W).w", to: "v", 255 want: "OK", // since no selections are made ambiguous 256 }, 257 { 258 // field/method ambiguity at same promotion level ('from' selection) 259 from: "(main.U).u", to: "x", 260 want: `renaming this field "u" to "x".*` + 261 `would make this reference ambiguous.*` + 262 `with this method`, 263 }, 264 { 265 // field/field ambiguity at same promotion level ('to' selection) 266 from: "(main.V).x", to: "u", 267 want: `renaming this method "x" to "u".*` + 268 `would make this reference ambiguous.*` + 269 `with this field`, 270 }, 271 { 272 // field/method conflict at named struct declaration 273 from: "(main.V).v", to: "x", 274 want: `renaming this field "v" to "x".*` + 275 `would conflict with this method`, 276 }, 277 { 278 // field/method conflict at named struct declaration 279 from: "(main.V).x", to: "v", 280 want: `renaming this method "x" to "v".*` + 281 `would conflict with this field`, 282 }, 283 284 // Methods 285 { 286 ctxt: main(` 287 package main 288 type C int 289 func (C) f() 290 func (C) g() 291 type D int 292 func (*D) f() 293 func (*D) g() 294 type I interface { f(); g() } 295 type J interface { I; h() } 296 var _ I = new(D) 297 var _ interface {f()} = C(0) 298 `), 299 from: "(main.I).f", to: "g", 300 want: `renaming this interface method "f" to "g".*` + 301 `would conflict with this method`, 302 }, 303 { 304 from: `("main".I).f`, to: "h", // NB: exercises quoted import paths too 305 want: `renaming this interface method "f" to "h".*` + 306 `would conflict with this method.*` + 307 `in named interface type "J"`, 308 }, 309 { 310 // type J interface { h; h() } is not a conflict, amusingly. 311 from: "main.I", to: "h", 312 want: `OK`, 313 }, 314 { 315 from: "(main.J).h", to: "f", 316 want: `renaming this interface method "h" to "f".*` + 317 `would conflict with this method`, 318 }, 319 { 320 from: "(main.C).f", to: "e", 321 want: `renaming this method "f" to "e".*` + 322 `would make main.C no longer assignable to interface{f..}.*` + 323 `(rename interface{f..}.f if you intend to change both types)`, 324 }, 325 { 326 from: "(main.D).g", to: "e", 327 want: `renaming this method "g" to "e".*` + 328 `would make \*main.D no longer assignable to interface I.*` + 329 `(rename main.I.g if you intend to change both types)`, 330 }, 331 { 332 from: "(main.I).f", to: "e", 333 want: `OK`, 334 }, 335 // Indirect C/I method coupling via another concrete type D. 336 { 337 ctxt: main(` 338 package main 339 type I interface { f() } 340 type C int 341 func (C) f() 342 type D struct{C} 343 var _ I = D{} 344 `), 345 from: "(main.C).f", to: "F", 346 want: `renaming this method "f" to "F".*` + 347 `would make main.D no longer assignable to interface I.*` + 348 `(rename main.I.f if you intend to change both types)`, 349 }, 350 // Renaming causes promoted method to become shadowed; C no longer satisfies I. 351 { 352 ctxt: main(` 353 package main 354 type I interface { f() } 355 type C struct { I } 356 func (C) g() int 357 var _ I = C{} 358 `), 359 from: "main.I.f", to: "g", 360 want: `renaming this method "f" to "g".*` + 361 `would change the g method of main.C invoked via interface main.I.*` + 362 `from \(main.I\).g.*` + 363 `to \(main.C\).g`, 364 }, 365 // Renaming causes promoted method to become ambiguous; C no longer satisfies I. 366 { 367 ctxt: main(` 368 package main 369 type I interface{f()} 370 type C int 371 func (C) f() 372 type D int 373 func (D) g() 374 type E struct{C;D} 375 var _ I = E{} 376 `), 377 from: "main.I.f", to: "g", 378 want: `renaming this method "f" to "g".*` + 379 `would make the g method of main.E invoked via interface main.I ambiguous.*` + 380 `with \(main.D\).g`, 381 }, 382 } { 383 var conflicts []string 384 reportError = func(posn token.Position, message string) { 385 conflicts = append(conflicts, message) 386 } 387 if test.ctxt != nil { 388 ctxt = test.ctxt 389 } 390 err := Main(ctxt, test.offset, test.from, test.to) 391 var prefix string 392 if test.offset == "" { 393 prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to) 394 } else { 395 prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to) 396 } 397 if err == ConflictError { 398 got := strings.Join(conflicts, "\n") 399 if false { 400 t.Logf("%s: %s", prefix, got) 401 } 402 pattern := "(?s:" + test.want + ")" // enable multi-line matching 403 if !regexp.MustCompile(pattern).MatchString(got) { 404 t.Errorf("%s: conflict does not match pattern:\n"+ 405 "Conflict:\t%s\n"+ 406 "Pattern: %s", 407 prefix, got, test.want) 408 } 409 } else if err != nil { 410 t.Errorf("%s: unexpected error: %s", prefix, err) 411 } else if test.want != "OK" { 412 t.Errorf("%s: unexpected success, want conflicts matching:\n%s", 413 prefix, test.want) 414 } 415 } 416 } 417 418 func TestRewrites(t *testing.T) { 419 defer func(savedWriteFile func(string, []byte) error) { 420 writeFile = savedWriteFile 421 }(writeFile) 422 423 var ctxt *build.Context 424 for _, test := range []struct { 425 ctxt *build.Context // nil => use previous 426 offset, from, to string // values of the -from/-offset and -to flags 427 want map[string]string // contents of updated files 428 }{ 429 // Elimination of renaming import. 430 { 431 ctxt: fakeContext(map[string][]string{ 432 "foo": {`package foo; type T int`}, 433 "main": {`package main 434 435 import foo2 "foo" 436 437 var _ foo2.T 438 `}, 439 }), 440 from: "main::foo2", to: "foo", 441 want: map[string]string{ 442 "/go/src/main/0.go": `package main 443 444 import "foo" 445 446 var _ foo.T 447 `, 448 }, 449 }, 450 // Introduction of renaming import. 451 { 452 ctxt: fakeContext(map[string][]string{ 453 "foo": {`package foo; type T int`}, 454 "main": {`package main 455 456 import "foo" 457 458 var _ foo.T 459 `}, 460 }), 461 offset: "/go/src/main/0.go:#36", to: "foo2", // the "foo" in foo.T 462 want: map[string]string{ 463 "/go/src/main/0.go": `package main 464 465 import foo2 "foo" 466 467 var _ foo2.T 468 `, 469 }, 470 }, 471 // Renaming of package-level member. 472 { 473 from: "foo.T", to: "U", 474 want: map[string]string{ 475 "/go/src/main/0.go": `package main 476 477 import "foo" 478 479 var _ foo.U 480 `, 481 "/go/src/foo/0.go": `package foo 482 483 type U int 484 `, 485 }, 486 }, 487 // Label renamings. 488 { 489 ctxt: main(`package main 490 func f() { 491 loop: 492 loop := 0 493 go func() { 494 loop: 495 goto loop 496 }() 497 loop++ 498 goto loop 499 } 500 `), 501 offset: "/go/src/main/0.go:#25", to: "loop2", // def of outer label "loop" 502 want: map[string]string{ 503 "/go/src/main/0.go": `package main 504 505 func f() { 506 loop2: 507 loop := 0 508 go func() { 509 loop: 510 goto loop 511 }() 512 loop++ 513 goto loop2 514 } 515 `, 516 }, 517 }, 518 { 519 offset: "/go/src/main/0.go:#70", to: "loop2", // ref to inner label "loop" 520 want: map[string]string{ 521 "/go/src/main/0.go": `package main 522 523 func f() { 524 loop: 525 loop := 0 526 go func() { 527 loop2: 528 goto loop2 529 }() 530 loop++ 531 goto loop 532 } 533 `, 534 }, 535 }, 536 // Renaming of type used as embedded field. 537 { 538 ctxt: main(`package main 539 540 type T int 541 type U struct { T } 542 543 var _ = U{}.T 544 `), 545 from: "main.T", to: "T2", 546 want: map[string]string{ 547 "/go/src/main/0.go": `package main 548 549 type T2 int 550 type U struct{ T2 } 551 552 var _ = U{}.T2 553 `, 554 }, 555 }, 556 // Renaming of embedded field. 557 { 558 ctxt: main(`package main 559 560 type T int 561 type U struct { T } 562 563 var _ = U{}.T 564 `), 565 offset: "/go/src/main/0.go:#58", to: "T2", // T in "U{}.T" 566 want: map[string]string{ 567 "/go/src/main/0.go": `package main 568 569 type T2 int 570 type U struct{ T2 } 571 572 var _ = U{}.T2 573 `, 574 }, 575 }, 576 // Renaming of pointer embedded field. 577 { 578 ctxt: main(`package main 579 580 type T int 581 type U struct { *T } 582 583 var _ = U{}.T 584 `), 585 offset: "/go/src/main/0.go:#59", to: "T2", // T in "U{}.T" 586 want: map[string]string{ 587 "/go/src/main/0.go": `package main 588 589 type T2 int 590 type U struct{ *T2 } 591 592 var _ = U{}.T2 593 `, 594 }, 595 }, 596 597 // Lexical scope tests. 598 { 599 ctxt: main(`package main 600 601 var y int 602 603 func f() { 604 print(y) 605 y := "" 606 print(y) 607 } 608 `), 609 from: "main.y", to: "x", 610 want: map[string]string{ 611 "/go/src/main/0.go": `package main 612 613 var x int 614 615 func f() { 616 print(x) 617 y := "" 618 print(y) 619 } 620 `, 621 }, 622 }, 623 { 624 from: "main.f::y", to: "x", 625 want: map[string]string{ 626 "/go/src/main/0.go": `package main 627 628 var y int 629 630 func f() { 631 print(y) 632 x := "" 633 print(x) 634 } 635 `, 636 }, 637 }, 638 // Renaming of typeswitch vars (a corner case). 639 { 640 ctxt: main(`package main 641 642 func f(z interface{}) { 643 switch y := z.(type) { 644 case int: 645 print(y) 646 default: 647 print(y) 648 } 649 } 650 `), 651 offset: "/go/src/main/0.go:#46", to: "x", // def of y 652 want: map[string]string{ 653 "/go/src/main/0.go": `package main 654 655 func f(z interface{}) { 656 switch x := z.(type) { 657 case int: 658 print(x) 659 default: 660 print(x) 661 } 662 } 663 `}, 664 }, 665 { 666 offset: "/go/src/main/0.go:#81", to: "x", // ref of y in case int 667 want: map[string]string{ 668 "/go/src/main/0.go": `package main 669 670 func f(z interface{}) { 671 switch x := z.(type) { 672 case int: 673 print(x) 674 default: 675 print(x) 676 } 677 } 678 `}, 679 }, 680 { 681 offset: "/go/src/main/0.go:#102", to: "x", // ref of y in default case 682 want: map[string]string{ 683 "/go/src/main/0.go": `package main 684 685 func f(z interface{}) { 686 switch x := z.(type) { 687 case int: 688 print(x) 689 default: 690 print(x) 691 } 692 } 693 `}, 694 }, 695 696 // Renaming of embedded field that is a qualified reference. 697 // (Regression test for bug 8924.) 698 { 699 ctxt: fakeContext(map[string][]string{ 700 "foo": {`package foo; type T int`}, 701 "main": {`package main 702 703 import "foo" 704 705 type _ struct{ *foo.T } 706 `}, 707 }), 708 offset: "/go/src/main/0.go:#48", to: "U", // the "T" in *foo.T 709 want: map[string]string{ 710 "/go/src/foo/0.go": `package foo 711 712 type U int 713 `, 714 "/go/src/main/0.go": `package main 715 716 import "foo" 717 718 type _ struct{ *foo.U } 719 `, 720 }, 721 }, 722 723 // Renaming of embedded field that is a qualified reference with the '-from' flag. 724 // (Regression test for bug 12038.) 725 { 726 ctxt: fakeContext(map[string][]string{ 727 "foo": {`package foo; type T int`}, 728 "main": {`package main 729 730 import "foo" 731 732 type V struct{ *foo.T } 733 `}, 734 }), 735 from: "(main.V).T", to: "U", // the "T" in *foo.T 736 want: map[string]string{ 737 "/go/src/foo/0.go": `package foo 738 739 type U int 740 `, 741 "/go/src/main/0.go": `package main 742 743 import "foo" 744 745 type V struct{ *foo.U } 746 `, 747 }, 748 }, 749 { 750 ctxt: fakeContext(map[string][]string{ 751 "foo": {`package foo; type T int`}, 752 "main": {`package main 753 754 import "foo" 755 756 type V struct{ foo.T } 757 `}, 758 }), 759 from: "(main.V).T", to: "U", // the "T" in *foo.T 760 want: map[string]string{ 761 "/go/src/foo/0.go": `package foo 762 763 type U int 764 `, 765 "/go/src/main/0.go": `package main 766 767 import "foo" 768 769 type V struct{ foo.U } 770 `, 771 }, 772 }, 773 774 // Interface method renaming. 775 { 776 ctxt: fakeContext(map[string][]string{ 777 "main": {` 778 package main 779 type I interface { f() } 780 type J interface { f(); g() } 781 type A int 782 func (A) f() 783 type B int 784 func (B) f() 785 func (B) g() 786 type C int 787 func (C) f() 788 func (C) g() 789 var _, _ I = A(0), B(0) 790 var _, _ J = B(0), C(0) 791 `, 792 }, 793 }), 794 offset: "/go/src/main/0.go:#33", to: "F", // abstract method I.f 795 want: map[string]string{ 796 "/go/src/main/0.go": `package main 797 798 type I interface { 799 F() 800 } 801 type J interface { 802 F() 803 g() 804 } 805 type A int 806 807 func (A) F() 808 809 type B int 810 811 func (B) F() 812 func (B) g() 813 814 type C int 815 816 func (C) F() 817 func (C) g() 818 819 var _, _ I = A(0), B(0) 820 var _, _ J = B(0), C(0) 821 `, 822 }, 823 }, 824 { 825 offset: "/go/src/main/0.go:#58", to: "F", // abstract method J.f 826 want: map[string]string{ 827 "/go/src/main/0.go": `package main 828 829 type I interface { 830 F() 831 } 832 type J interface { 833 F() 834 g() 835 } 836 type A int 837 838 func (A) F() 839 840 type B int 841 842 func (B) F() 843 func (B) g() 844 845 type C int 846 847 func (C) F() 848 func (C) g() 849 850 var _, _ I = A(0), B(0) 851 var _, _ J = B(0), C(0) 852 `, 853 }, 854 }, 855 { 856 offset: "/go/src/main/0.go:#63", to: "G", // abstract method J.g 857 want: map[string]string{ 858 "/go/src/main/0.go": `package main 859 860 type I interface { 861 f() 862 } 863 type J interface { 864 f() 865 G() 866 } 867 type A int 868 869 func (A) f() 870 871 type B int 872 873 func (B) f() 874 func (B) G() 875 876 type C int 877 878 func (C) f() 879 func (C) G() 880 881 var _, _ I = A(0), B(0) 882 var _, _ J = B(0), C(0) 883 `, 884 }, 885 }, 886 // Indirect coupling of I.f to C.f from D->I assignment and anonymous field of D. 887 { 888 ctxt: fakeContext(map[string][]string{ 889 "main": {` 890 package main 891 type I interface { f() } 892 type C int 893 func (C) f() 894 type D struct{C} 895 var _ I = D{} 896 `, 897 }, 898 }), 899 offset: "/go/src/main/0.go:#33", to: "F", // abstract method I.f 900 want: map[string]string{ 901 "/go/src/main/0.go": `package main 902 903 type I interface { 904 F() 905 } 906 type C int 907 908 func (C) F() 909 910 type D struct{ C } 911 912 var _ I = D{} 913 `, 914 }, 915 }, 916 // Interface embedded in struct. No conflict if C need not satisfy I. 917 { 918 ctxt: fakeContext(map[string][]string{ 919 "main": {` 920 package main 921 type I interface {f()} 922 type C struct{I} 923 func (C) g() int 924 var _ int = C{}.g() 925 `, 926 }, 927 }), 928 offset: "/go/src/main/0.go:#32", to: "g", // abstract method I.f 929 want: map[string]string{ 930 "/go/src/main/0.go": `package main 931 932 type I interface { 933 g() 934 } 935 type C struct{ I } 936 937 func (C) g() int 938 939 var _ int = C{}.g() 940 `, 941 }, 942 }, 943 // A type assertion causes method coupling iff signatures match. 944 { 945 ctxt: fakeContext(map[string][]string{ 946 "main": {`package main 947 type I interface{f()} 948 type J interface{f()} 949 var _ = I(nil).(J) 950 `, 951 }, 952 }), 953 offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f 954 want: map[string]string{ 955 "/go/src/main/0.go": `package main 956 957 type I interface { 958 g() 959 } 960 type J interface { 961 g() 962 } 963 964 var _ = I(nil).(J) 965 `, 966 }, 967 }, 968 // Impossible type assertion: no method coupling. 969 { 970 ctxt: fakeContext(map[string][]string{ 971 "main": {`package main 972 type I interface{f()} 973 type J interface{f()int} 974 var _ = I(nil).(J) 975 `, 976 }, 977 }), 978 offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f 979 want: map[string]string{ 980 "/go/src/main/0.go": `package main 981 982 type I interface { 983 g() 984 } 985 type J interface { 986 f() int 987 } 988 989 var _ = I(nil).(J) 990 `, 991 }, 992 }, 993 // Impossible type assertion: no method coupling C.f<->J.f. 994 { 995 ctxt: fakeContext(map[string][]string{ 996 "main": {`package main 997 type I interface{f()} 998 type C int 999 func (C) f() 1000 type J interface{f()int} 1001 var _ = I(C(0)).(J) 1002 `, 1003 }, 1004 }), 1005 offset: "/go/src/main/0.go:#30", to: "g", // abstract method I.f 1006 want: map[string]string{ 1007 "/go/src/main/0.go": `package main 1008 1009 type I interface { 1010 g() 1011 } 1012 type C int 1013 1014 func (C) g() 1015 1016 type J interface { 1017 f() int 1018 } 1019 1020 var _ = I(C(0)).(J) 1021 `, 1022 }, 1023 }, 1024 } { 1025 if test.ctxt != nil { 1026 ctxt = test.ctxt 1027 } 1028 1029 got := make(map[string]string) 1030 writeFile = func(filename string, content []byte) error { 1031 got[filepath.ToSlash(filename)] = string(content) 1032 return nil 1033 } 1034 1035 err := Main(ctxt, test.offset, test.from, test.to) 1036 var prefix string 1037 if test.offset == "" { 1038 prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to) 1039 } else { 1040 prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to) 1041 } 1042 if err != nil { 1043 t.Errorf("%s: unexpected error: %s", prefix, err) 1044 continue 1045 } 1046 1047 for file, wantContent := range test.want { 1048 gotContent, ok := got[file] 1049 delete(got, file) 1050 if !ok { 1051 t.Errorf("%s: file %s not rewritten", prefix, file) 1052 continue 1053 } 1054 if gotContent != wantContent { 1055 t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+ 1056 "want <<<%s>>>", prefix, file, gotContent, wantContent) 1057 } 1058 } 1059 // got should now be empty 1060 for file := range got { 1061 t.Errorf("%s: unexpected rewrite of file %s", prefix, file) 1062 } 1063 } 1064 } 1065 1066 func TestDiff(t *testing.T) { 1067 defer func() { 1068 Diff = false 1069 stdout = os.Stdout 1070 }() 1071 Diff = true 1072 stdout = new(bytes.Buffer) 1073 1074 if err := Main(&build.Default, "", `"golang.org/x/tools/refactor/rename".justHereForTestingDiff`, "Foo"); err != nil { 1075 t.Fatal(err) 1076 } 1077 1078 // NB: there are tabs in the string literal! 1079 if !strings.Contains(stdout.(fmt.Stringer).String(), ` 1080 -func justHereForTestingDiff() { 1081 - justHereForTestingDiff() 1082 +func Foo() { 1083 + Foo() 1084 } 1085 `) { 1086 t.Errorf("unexpected diff:\n<<%s>>", stdout) 1087 } 1088 } 1089 1090 func justHereForTestingDiff() { 1091 justHereForTestingDiff() 1092 } 1093 1094 // --------------------------------------------------------------------- 1095 1096 // Simplifying wrapper around buildutil.FakeContext for packages whose 1097 // filenames are sequentially numbered (%d.go). pkgs maps a package 1098 // import path to its list of file contents. 1099 func fakeContext(pkgs map[string][]string) *build.Context { 1100 pkgs2 := make(map[string]map[string]string) 1101 for path, files := range pkgs { 1102 filemap := make(map[string]string) 1103 for i, contents := range files { 1104 filemap[fmt.Sprintf("%d.go", i)] = contents 1105 } 1106 pkgs2[path] = filemap 1107 } 1108 return buildutil.FakeContext(pkgs2) 1109 } 1110 1111 // helper for single-file main packages with no imports. 1112 func main(content string) *build.Context { 1113 return fakeContext(map[string][]string{"main": {content}}) 1114 }