1
2
3
4
5 package rename
6
7 import (
8 "bytes"
9 "fmt"
10 "go/build"
11 "go/token"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "regexp"
16 "runtime"
17 "strings"
18 "testing"
19
20 "golang.org/x/tools/go/buildutil"
21 "golang.org/x/tools/internal/aliases"
22 "golang.org/x/tools/internal/testenv"
23 )
24
25
26
27 func TestConflicts(t *testing.T) {
28 defer func(savedWriteFile func(string, []byte) error, savedReportError func(token.Position, string)) {
29 writeFile = savedWriteFile
30 reportError = savedReportError
31 }(writeFile, reportError)
32 writeFile = func(string, []byte) error { return nil }
33
34 var ctxt *build.Context
35 for _, test := range []struct {
36 ctxt *build.Context
37 offset, from, to string
38 want string
39 }{
40
41 {
42 ctxt: fakeContext(map[string][]string{
43 "fmt": {`package fmt; type Stringer interface { String() }`},
44 "main": {`
45 package main
46
47 import foo "fmt"
48
49 var v foo.Stringer
50
51 func f() { v.String(); f() }
52 `,
53 `package main; var w int`},
54 }),
55 from: "main.v", to: "init",
56 want: `you cannot have a var at package level named "init"`,
57 },
58 {
59 from: "main.f", to: "init",
60 want: `renaming this func "f" to "init" would make it a package initializer.*` +
61 `but references to it exist`,
62 },
63 {
64 from: "/go/src/main/0.go::foo", to: "init",
65 want: `"init" is not a valid imported package name`,
66 },
67
68
69 {
70 from: "fmt.Stringer", to: "stringer",
71 want: `renaming this type "Stringer" to "stringer" would make it unexported.*` +
72 `breaking references from packages such as "main"`,
73 },
74 {
75 from: "(fmt.Stringer).String", to: "string",
76 want: `renaming this method "String" to "string" would make it unexported.*` +
77 `breaking references from packages such as "main"`,
78 },
79
80
81 {
82
83 from: "main.v", to: "foo",
84 want: `renaming this var "v" to "foo" would conflict.*` +
85 `with this imported package name`,
86 },
87 {
88
89 from: "main::foo", to: "v",
90 want: `renaming this imported package name "foo" to "v" would conflict.*` +
91 `with this package member var`,
92 },
93 {
94
95 from: "main.w", to: "foo",
96 want: `renaming this var "w" to "foo" would conflict.*` +
97 `with this imported package name`,
98 },
99 {
100
101 from: "main::foo", to: "w",
102 want: `renaming this imported package name "foo" to "w" would conflict.*` +
103 `with this package member var`,
104 },
105 {
106 ctxt: main(`
107 package main
108
109 var x, z int
110
111 func f(y int) {
112 print(x)
113 print(y)
114 }
115
116 func g(w int) {
117 print(x)
118 x := 1
119 print(x)
120 }`),
121 from: "main.x", to: "y",
122 want: `renaming this var "x" to "y".*` +
123 `would cause this reference to become shadowed.*` +
124 `by this intervening var definition`,
125 },
126 {
127 from: "main.g::x", to: "w",
128 want: `renaming this var "x" to "w".*` +
129 `conflicts with var in same block`,
130 },
131 {
132 from: "main.f::y", to: "x",
133 want: `renaming this var "y" to "x".*` +
134 `would shadow this reference.*` +
135 `to the var declared here`,
136 },
137 {
138 from: "main.g::w", to: "x",
139 want: `renaming this var "w" to "x".*` +
140 `conflicts with var in same block`,
141 },
142 {
143 from: "main.z", to: "y", want: "OK",
144 },
145
146
147 {
148 ctxt: main(`
149 package main
150
151 func f() {
152 foo:
153 goto foo
154 bar:
155 goto bar
156 func(x int) {
157 wiz:
158 goto wiz
159 }(0)
160 }
161 `),
162 from: "main.f::foo", to: "bar",
163 want: `renaming this label "foo" to "bar".*` +
164 `would conflict with this one`,
165 },
166 {
167 from: "main.f::foo", to: "wiz", want: "OK",
168 },
169 {
170 from: "main.f::wiz", to: "x", want: "OK",
171 },
172 {
173 from: "main.f::x", to: "wiz", want: "OK",
174 },
175 {
176 from: "main.f::wiz", to: "foo", want: "OK",
177 },
178
179
180 {
181 ctxt: main(`
182 package main
183
184 type U struct { u int }
185 type V struct { v int }
186
187 func (V) x() {}
188
189 type W (struct {
190 U
191 V
192 w int
193 })
194
195 func f() {
196 var w W
197 print(w.u) // NB: there is no selection of w.v
198 var _ struct { yy, zz int }
199 }
200 `),
201
202 from: "(main.W).U", to: "w",
203 want: `renaming this field "U" to "w".*` +
204 `would conflict with this field`,
205 },
206 {
207
208
209
210
211
212 from: "main.U", to: "w",
213 want: `renaming this field "U" to "w".*` +
214 `would conflict with this field`,
215 },
216 {
217
218 from: "main.f::zz", to: "yy",
219 want: `renaming this field "zz" to "yy".*` +
220 `would conflict with this field`,
221 },
222
223
224
225 {
226
227 from: "(main.U).u", to: "v",
228 want: `renaming this field "u" to "v".*` +
229 `would make this reference ambiguous.*` +
230 `with this field`,
231 },
232 {
233
234 from: "(main.V).v", to: "u",
235 want: `renaming this field "v" to "u".*` +
236 `would make this reference ambiguous.*` +
237 `with this field`,
238 },
239 {
240
241 from: "(main.U).u", to: "w",
242 want: `renaming this field "u" to "w".*` +
243 `would change the referent of this selection.*` +
244 `of this field`,
245 },
246 {
247
248 from: "(main.W).w", to: "u",
249 want: `renaming this field "w" to "u".*` +
250 `would shadow this selection.*` +
251 `of the field declared here`,
252 },
253 {
254 from: "(main.V).v", to: "w",
255 want: "OK",
256 },
257 {
258 from: "(main.W).w", to: "v",
259 want: "OK",
260 },
261 {
262
263 from: "(main.U).u", to: "x",
264 want: `renaming this field "u" to "x".*` +
265 `would make this reference ambiguous.*` +
266 `with this method`,
267 },
268 {
269
270 from: "(main.V).x", to: "u",
271 want: `renaming this method "x" to "u".*` +
272 `would make this reference ambiguous.*` +
273 `with this field`,
274 },
275 {
276
277 from: "(main.V).v", to: "x",
278 want: `renaming this field "v" to "x".*` +
279 `would conflict with this method`,
280 },
281 {
282
283 from: "(main.V).x", to: "v",
284 want: `renaming this method "x" to "v".*` +
285 `would conflict with this field`,
286 },
287
288
289 {
290 ctxt: main(`
291 package main
292 type C int
293 func (C) f()
294 func (C) g()
295 type D int
296 func (*D) f()
297 func (*D) g()
298 type I interface { f(); g() }
299 type J interface { I; h() }
300 var _ I = new(D)
301 var _ interface {f()} = C(0)
302 `),
303 from: "(main.I).f", to: "g",
304 want: `renaming this interface method "f" to "g".*` +
305 `would conflict with this method`,
306 },
307 {
308 from: `("main".I).f`, to: "h",
309 want: `renaming this interface method "f" to "h".*` +
310 `would conflict with this method.*` +
311 `in named interface type "J"`,
312 },
313 {
314
315 from: "main.I", to: "h",
316 want: `OK`,
317 },
318 {
319 from: "(main.J).h", to: "f",
320 want: `renaming this interface method "h" to "f".*` +
321 `would conflict with this method`,
322 },
323 {
324 from: "(main.C).f", to: "e",
325 want: `renaming this method "f" to "e".*` +
326 `would make main.C no longer assignable to interface{f..}.*` +
327 `(rename interface{f..}.f if you intend to change both types)`,
328 },
329 {
330 from: "(main.D).g", to: "e",
331 want: `renaming this method "g" to "e".*` +
332 `would make \*main.D no longer assignable to interface I.*` +
333 `(rename main.I.g if you intend to change both types)`,
334 },
335 {
336 from: "(main.I).f", to: "e",
337 want: `OK`,
338 },
339
340 {
341 ctxt: main(`
342 package main
343 type I interface { f() }
344 type C int
345 func (C) f()
346 type D struct{C}
347 var _ I = D{}
348 `),
349 from: "(main.C).f", to: "F",
350 want: `renaming this method "f" to "F".*` +
351 `would make main.D no longer assignable to interface I.*` +
352 `(rename main.I.f if you intend to change both types)`,
353 },
354
355 {
356 ctxt: main(`
357 package main
358 type I interface { f() }
359 type C struct { I }
360 func (C) g() int
361 var _ I = C{}
362 `),
363 from: "main.I.f", to: "g",
364 want: `renaming this method "f" to "g".*` +
365 `would change the g method of main.C invoked via interface main.I.*` +
366 `from \(main.I\).g.*` +
367 `to \(main.C\).g`,
368 },
369
370 {
371 ctxt: main(`
372 package main
373 type I interface{f()}
374 type C int
375 func (C) f()
376 type D int
377 func (D) g()
378 type E struct{C;D}
379 var _ I = E{}
380 `),
381 from: "main.I.f", to: "g",
382 want: `renaming this method "f" to "g".*` +
383 `would make the g method of main.E invoked via interface main.I ambiguous.*` +
384 `with \(main.D\).g`,
385 },
386 } {
387 var conflicts []string
388 reportError = func(posn token.Position, message string) {
389 conflicts = append(conflicts, message)
390 }
391 if test.ctxt != nil {
392 ctxt = test.ctxt
393 }
394 err := Main(ctxt, test.offset, test.from, test.to)
395 var prefix string
396 if test.offset == "" {
397 prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
398 } else {
399 prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
400 }
401 if err == ConflictError {
402 got := strings.Join(conflicts, "\n")
403 if false {
404 t.Logf("%s: %s", prefix, got)
405 }
406 pattern := "(?s:" + test.want + ")"
407 if !regexp.MustCompile(pattern).MatchString(got) {
408 t.Errorf("%s: conflict does not match pattern:\n"+
409 "Conflict:\t%s\n"+
410 "Pattern: %s",
411 prefix, got, test.want)
412 }
413 } else if err != nil {
414 t.Errorf("%s: unexpected error: %s", prefix, err)
415 } else if test.want != "OK" {
416 t.Errorf("%s: unexpected success, want conflicts matching:\n%s",
417 prefix, test.want)
418 }
419 }
420 }
421
422 func TestInvalidIdentifiers(t *testing.T) {
423 ctxt := fakeContext(map[string][]string{
424 "main": {`
425 package main
426
427 func f() { }
428 `}})
429
430 for _, test := range []struct {
431 from, to string
432 want string
433 }{
434 {
435 from: "main.f", to: "_",
436 want: `-to "_": not a valid identifier`,
437 },
438 {
439 from: "main.f", to: "123",
440 want: `-to "123": not a valid identifier`,
441 },
442 {
443 from: "main.f", to: "for",
444 want: `-to "for": not a valid identifier`,
445 },
446 {
447 from: "switch", to: "v",
448 want: `-from "switch": invalid expression`,
449 },
450 } {
451 err := Main(ctxt, "", test.from, test.to)
452 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
453 if err == nil {
454 t.Errorf("%s: expected error %q", prefix, test.want)
455 } else if err.Error() != test.want {
456 t.Errorf("%s: unexpected error\nwant: %s\n got: %s", prefix, test.want, err.Error())
457 }
458 }
459 }
460
461 func TestRewrites(t *testing.T) {
462 defer func(savedWriteFile func(string, []byte) error) {
463 writeFile = savedWriteFile
464 }(writeFile)
465
466 var ctxt *build.Context
467 for _, test := range []struct {
468 ctxt *build.Context
469 offset, from, to string
470 want map[string]string
471 alias bool
472 }{
473
474 {
475 ctxt: fakeContext(map[string][]string{
476 "foo": {`package foo; type T int`},
477 "main": {`package main
478
479 import foo2 "foo"
480
481 var _ foo2.T
482 `},
483 }),
484 from: "main::foo2", to: "foo",
485 want: map[string]string{
486 "/go/src/main/0.go": `package main
487
488 import "foo"
489
490 var _ foo.T
491 `,
492 },
493 },
494
495 {
496 ctxt: fakeContext(map[string][]string{
497 "foo": {`package foo; type T int`},
498 "main": {`package main
499
500 import "foo"
501
502 var _ foo.T
503 `},
504 }),
505 offset: "/go/src/main/0.go:#36", to: "foo2",
506 want: map[string]string{
507 "/go/src/main/0.go": `package main
508
509 import foo2 "foo"
510
511 var _ foo2.T
512 `,
513 },
514 },
515
516 {
517 from: "foo.T", to: "U",
518 want: map[string]string{
519 "/go/src/main/0.go": `package main
520
521 import "foo"
522
523 var _ foo.U
524 `,
525 "/go/src/foo/0.go": `package foo
526
527 type U int
528 `,
529 },
530 },
531
532 {
533 ctxt: main(`package main
534
535 // Foo is a no-op.
536 // Calling Foo does nothing.
537 func Foo() {
538 }
539 `),
540 from: "main.Foo", to: "FooBar",
541 want: map[string]string{
542 "/go/src/main/0.go": `package main
543
544 // FooBar is a no-op.
545 // Calling FooBar does nothing.
546 func FooBar() {
547 }
548 `,
549 },
550 },
551
552 {
553 ctxt: main(`package main
554
555 type Foo struct{}
556
557 // Bar does nothing.
558 func (Foo) Bar() {
559 }
560 `),
561 from: "main.Foo.Bar", to: "Baz",
562 want: map[string]string{
563 "/go/src/main/0.go": `package main
564
565 type Foo struct{}
566
567 // Baz does nothing.
568 func (Foo) Baz() {
569 }
570 `,
571 },
572 },
573
574 {
575 ctxt: main(`package main
576
577 type (
578 // Test but not Testing.
579 Test struct{}
580 )
581 `),
582 from: "main.Test", to: "Type",
583 want: map[string]string{
584 "/go/src/main/0.go": `package main
585
586 type (
587 // Type but not Testing.
588 Type struct{}
589 )
590 `,
591 },
592 },
593
594 {
595 ctxt: main(`package main
596
597 // T is a test type.
598 type T struct{}
599 `),
600 from: "main.T", to: "Type",
601 want: map[string]string{
602 "/go/src/main/0.go": `package main
603
604 // Type is a test type.
605 type Type struct{}
606 `,
607 },
608 },
609
610 {
611 ctxt: main(`package main
612
613 const (
614 // C is the speed of light.
615 C = 2.998e8
616 )
617 `),
618 from: "main.C", to: "Lightspeed",
619 want: map[string]string{
620 "/go/src/main/0.go": `package main
621
622 const (
623 // Lightspeed is the speed of light.
624 Lightspeed = 2.998e8
625 )
626 `,
627 },
628 },
629
630 {
631 ctxt: main(`package main
632
633 var out *string
634 `),
635 from: "main.out", to: "discard",
636 want: map[string]string{
637 "/go/src/main/0.go": `package main
638
639 var discard *string
640 `,
641 },
642 },
643
644 {
645 ctxt: main(`package main
646
647 type Struct struct {
648 // Field is a struct field.
649 Field string
650 }
651 `),
652 from: "main.Struct.Field", to: "Foo",
653 want: map[string]string{
654 "/go/src/main/0.go": `package main
655
656 type Struct struct {
657 // Foo is a struct field.
658 Foo string
659 }
660 `,
661 },
662 },
663
664 {
665 ctxt: main(`package main
666 func f() {
667 loop:
668 loop := 0
669 go func() {
670 loop:
671 goto loop
672 }()
673 loop++
674 goto loop
675 }
676 `),
677 offset: "/go/src/main/0.go:#25", to: "loop2",
678 want: map[string]string{
679 "/go/src/main/0.go": `package main
680
681 func f() {
682 loop2:
683 loop := 0
684 go func() {
685 loop:
686 goto loop
687 }()
688 loop++
689 goto loop2
690 }
691 `,
692 },
693 },
694 {
695 offset: "/go/src/main/0.go:#70", to: "loop2",
696 want: map[string]string{
697 "/go/src/main/0.go": `package main
698
699 func f() {
700 loop:
701 loop := 0
702 go func() {
703 loop2:
704 goto loop2
705 }()
706 loop++
707 goto loop
708 }
709 `,
710 },
711 },
712
713 {
714 ctxt: main(`package main
715
716 type T int
717 type U struct { T }
718
719 var _ = U{}.T
720 `),
721 from: "main.T", to: "T2",
722 want: map[string]string{
723 "/go/src/main/0.go": `package main
724
725 type T2 int
726 type U struct{ T2 }
727
728 var _ = U{}.T2
729 `,
730 },
731 },
732
733 {
734 ctxt: main(`package main
735
736 type T int
737 type U struct { T }
738
739 var _ = U{}.T
740 `),
741 offset: "/go/src/main/0.go:#58", to: "T2",
742 want: map[string]string{
743 "/go/src/main/0.go": `package main
744
745 type T2 int
746 type U struct{ T2 }
747
748 var _ = U{}.T2
749 `,
750 },
751 },
752
753 {
754 ctxt: main(`package main
755
756 type T int
757 type U struct { *T }
758
759 var _ = U{}.T
760 `),
761 offset: "/go/src/main/0.go:#59", to: "T2",
762 want: map[string]string{
763 "/go/src/main/0.go": `package main
764
765 type T2 int
766 type U struct{ *T2 }
767
768 var _ = U{}.T2
769 `,
770 },
771 },
772
773 {
774 alias: true,
775 ctxt: main(`package main
776
777 type T int
778 type A = T
779 type U struct{ A }
780
781 var _ = U{}.A
782 var a A
783 `),
784 offset: "/go/src/main/0.go:#68", to: "A2",
785 want: map[string]string{
786 "/go/src/main/0.go": `package main
787
788 type T int
789 type A2 = T
790 type U struct{ A2 }
791
792 var _ = U{}.A2
793 var a A2
794 `,
795 },
796 },
797
798 {
799 alias: true,
800 ctxt: main(`package main
801
802 type T int
803 type A = T
804 type U struct{ *A }
805
806 var _ = U{}.A
807 var a A
808 `),
809 offset: "/go/src/main/0.go:#69", to: "A2",
810 want: map[string]string{
811 "/go/src/main/0.go": `package main
812
813 type T int
814 type A2 = T
815 type U struct{ *A2 }
816
817 var _ = U{}.A2
818 var a A2
819 `,
820 },
821 },
822
823 {
824 ctxt: main(`package main
825
826 type A = int
827
828 func _() A {
829 return A(0)
830 }
831 `),
832 offset: "/go/src/main/0.go:#49", to: "A2",
833 want: map[string]string{
834 "/go/src/main/0.go": `package main
835
836 type A2 = int
837
838 func _() A2 {
839 return A2(0)
840 }
841 `,
842 },
843 },
844
845
846 {
847 ctxt: main(`package main
848
849 var y int
850
851 func f() {
852 print(y)
853 y := ""
854 print(y)
855 }
856 `),
857 from: "main.y", to: "x",
858 want: map[string]string{
859 "/go/src/main/0.go": `package main
860
861 var x int
862
863 func f() {
864 print(x)
865 y := ""
866 print(y)
867 }
868 `,
869 },
870 },
871 {
872 from: "main.f::y", to: "x",
873 want: map[string]string{
874 "/go/src/main/0.go": `package main
875
876 var y int
877
878 func f() {
879 print(y)
880 x := ""
881 print(x)
882 }
883 `,
884 },
885 },
886
887 {
888 ctxt: main(`package main
889
890 func f(z interface{}) {
891 switch y := z.(type) {
892 case int:
893 print(y)
894 default:
895 print(y)
896 }
897 }
898 `),
899 offset: "/go/src/main/0.go:#46", to: "x",
900 want: map[string]string{
901 "/go/src/main/0.go": `package main
902
903 func f(z interface{}) {
904 switch x := z.(type) {
905 case int:
906 print(x)
907 default:
908 print(x)
909 }
910 }
911 `},
912 },
913 {
914 offset: "/go/src/main/0.go:#81", to: "x",
915 want: map[string]string{
916 "/go/src/main/0.go": `package main
917
918 func f(z interface{}) {
919 switch x := z.(type) {
920 case int:
921 print(x)
922 default:
923 print(x)
924 }
925 }
926 `},
927 },
928 {
929 offset: "/go/src/main/0.go:#102", to: "x",
930 want: map[string]string{
931 "/go/src/main/0.go": `package main
932
933 func f(z interface{}) {
934 switch x := z.(type) {
935 case int:
936 print(x)
937 default:
938 print(x)
939 }
940 }
941 `},
942 },
943
944
945
946 {
947 ctxt: fakeContext(map[string][]string{
948 "foo": {`package foo; type T int`},
949 "main": {`package main
950
951 import "foo"
952
953 type _ struct{ *foo.T }
954 `},
955 }),
956 offset: "/go/src/main/0.go:#48", to: "U",
957 want: map[string]string{
958 "/go/src/foo/0.go": `package foo
959
960 type U int
961 `,
962 "/go/src/main/0.go": `package main
963
964 import "foo"
965
966 type _ struct{ *foo.U }
967 `,
968 },
969 },
970
971
972
973 {
974 ctxt: fakeContext(map[string][]string{
975 "foo": {`package foo; type T int`},
976 "main": {`package main
977
978 import "foo"
979
980 type V struct{ *foo.T }
981 `},
982 }),
983 from: "(main.V).T", to: "U",
984 want: map[string]string{
985 "/go/src/foo/0.go": `package foo
986
987 type U int
988 `,
989 "/go/src/main/0.go": `package main
990
991 import "foo"
992
993 type V struct{ *foo.U }
994 `,
995 },
996 },
997 {
998 ctxt: fakeContext(map[string][]string{
999 "foo": {`package foo; type T int`},
1000 "main": {`package main
1001
1002 import "foo"
1003
1004 type V struct{ foo.T }
1005 `},
1006 }),
1007 from: "(main.V).T", to: "U",
1008 want: map[string]string{
1009 "/go/src/foo/0.go": `package foo
1010
1011 type U int
1012 `,
1013 "/go/src/main/0.go": `package main
1014
1015 import "foo"
1016
1017 type V struct{ foo.U }
1018 `,
1019 },
1020 },
1021
1022
1023 {
1024 ctxt: fakeContext(map[string][]string{
1025 "main": {`
1026 package main
1027 type I interface {
1028 f()
1029 }
1030 type J interface { f(); g() }
1031 type A int
1032 func (A) f()
1033 type B int
1034 func (B) f()
1035 func (B) g()
1036 type C int
1037 func (C) f()
1038 func (C) g()
1039 var _, _ I = A(0), B(0)
1040 var _, _ J = B(0), C(0)
1041 `,
1042 },
1043 }),
1044 offset: "/go/src/main/0.go:#34", to: "F",
1045 want: map[string]string{
1046 "/go/src/main/0.go": `package main
1047
1048 type I interface {
1049 F()
1050 }
1051 type J interface {
1052 F()
1053 g()
1054 }
1055 type A int
1056
1057 func (A) F()
1058
1059 type B int
1060
1061 func (B) F()
1062 func (B) g()
1063
1064 type C int
1065
1066 func (C) F()
1067 func (C) g()
1068
1069 var _, _ I = A(0), B(0)
1070 var _, _ J = B(0), C(0)
1071 `,
1072 },
1073 },
1074 {
1075 offset: "/go/src/main/0.go:#59", to: "F",
1076 want: map[string]string{
1077 "/go/src/main/0.go": `package main
1078
1079 type I interface {
1080 F()
1081 }
1082 type J interface {
1083 F()
1084 g()
1085 }
1086 type A int
1087
1088 func (A) F()
1089
1090 type B int
1091
1092 func (B) F()
1093 func (B) g()
1094
1095 type C int
1096
1097 func (C) F()
1098 func (C) g()
1099
1100 var _, _ I = A(0), B(0)
1101 var _, _ J = B(0), C(0)
1102 `,
1103 },
1104 },
1105 {
1106 offset: "/go/src/main/0.go:#64", to: "G",
1107 want: map[string]string{
1108 "/go/src/main/0.go": `package main
1109
1110 type I interface {
1111 f()
1112 }
1113 type J interface {
1114 f()
1115 G()
1116 }
1117 type A int
1118
1119 func (A) f()
1120
1121 type B int
1122
1123 func (B) f()
1124 func (B) G()
1125
1126 type C int
1127
1128 func (C) f()
1129 func (C) G()
1130
1131 var _, _ I = A(0), B(0)
1132 var _, _ J = B(0), C(0)
1133 `,
1134 },
1135 },
1136
1137 {
1138 ctxt: fakeContext(map[string][]string{
1139 "main": {`
1140 package main
1141 type I interface {
1142 f()
1143 }
1144 type C int
1145 func (C) f()
1146 type D struct{C}
1147 var _ I = D{}
1148 `,
1149 },
1150 }),
1151 offset: "/go/src/main/0.go:#34", to: "F",
1152 want: map[string]string{
1153 "/go/src/main/0.go": `package main
1154
1155 type I interface {
1156 F()
1157 }
1158 type C int
1159
1160 func (C) F()
1161
1162 type D struct{ C }
1163
1164 var _ I = D{}
1165 `,
1166 },
1167 },
1168
1169 {
1170 ctxt: fakeContext(map[string][]string{
1171 "main": {`
1172 package main
1173 type I interface {
1174 f()
1175 }
1176 type C struct{I}
1177 func (C) g() int
1178 var _ int = C{}.g()
1179 `,
1180 },
1181 }),
1182 offset: "/go/src/main/0.go:#34", to: "g",
1183 want: map[string]string{
1184 "/go/src/main/0.go": `package main
1185
1186 type I interface {
1187 g()
1188 }
1189 type C struct{ I }
1190
1191 func (C) g() int
1192
1193 var _ int = C{}.g()
1194 `,
1195 },
1196 },
1197
1198 {
1199 ctxt: fakeContext(map[string][]string{
1200 "main": {`package main
1201 type I interface{
1202 f()
1203 }
1204 type J interface{
1205 f()
1206 }
1207 var _ = I(nil).(J)
1208 `,
1209 },
1210 }),
1211 offset: "/go/src/main/0.go:#32", to: "g",
1212 want: map[string]string{
1213 "/go/src/main/0.go": `package main
1214
1215 type I interface {
1216 g()
1217 }
1218 type J interface {
1219 g()
1220 }
1221
1222 var _ = I(nil).(J)
1223 `,
1224 },
1225 },
1226
1227 {
1228 ctxt: fakeContext(map[string][]string{
1229 "main": {`package main
1230 type I interface{
1231 f()
1232 }
1233 type J interface{
1234 f()int
1235 }
1236 var _ = I(nil).(J)
1237 `,
1238 },
1239 }),
1240 offset: "/go/src/main/0.go:#32", to: "g",
1241 want: map[string]string{
1242 "/go/src/main/0.go": `package main
1243
1244 type I interface {
1245 g()
1246 }
1247 type J interface {
1248 f() int
1249 }
1250
1251 var _ = I(nil).(J)
1252 `,
1253 },
1254 },
1255
1256 {
1257 ctxt: fakeContext(map[string][]string{
1258 "main": {`package main
1259 type I interface{
1260 f()
1261 }
1262 type C int
1263 func (C) f()
1264 type J interface{
1265 f()int
1266 }
1267 var _ = I(C(0)).(J)
1268 `,
1269 },
1270 }),
1271 offset: "/go/src/main/0.go:#32", to: "g",
1272 want: map[string]string{
1273 "/go/src/main/0.go": `package main
1274
1275 type I interface {
1276 g()
1277 }
1278 type C int
1279
1280 func (C) g()
1281
1282 type J interface {
1283 f() int
1284 }
1285
1286 var _ = I(C(0)).(J)
1287 `,
1288 },
1289 },
1290
1291 {
1292 ctxt: fakeContext(map[string][]string{
1293 "main": {`package main
1294
1295 func main() {
1296 var unused, x int
1297 print(x)
1298 }
1299 `,
1300 },
1301 }),
1302 offset: "/go/src/main/0.go:#54", to: "y",
1303 want: map[string]string{
1304 "/go/src/main/0.go": `package main
1305
1306 func main() {
1307 var unused, y int
1308 print(y)
1309 }
1310 `,
1311 },
1312 },
1313 } {
1314 if test.ctxt != nil {
1315 ctxt = test.ctxt
1316 }
1317
1318 got := make(map[string]string)
1319 writeFile = func(filename string, content []byte) error {
1320 got[filepath.ToSlash(filename)] = string(content)
1321 return nil
1322 }
1323
1324
1325
1326
1327 if test.alias && !aliases.Enabled() {
1328 t.Log("test requires aliases")
1329 continue
1330 }
1331
1332 err := Main(ctxt, test.offset, test.from, test.to)
1333 var prefix string
1334 if test.offset == "" {
1335 prefix = fmt.Sprintf("-from %q -to %q", test.from, test.to)
1336 } else {
1337 prefix = fmt.Sprintf("-offset %q -to %q", test.offset, test.to)
1338 }
1339 if err != nil {
1340 t.Errorf("%s: unexpected error: %s", prefix, err)
1341 continue
1342 }
1343
1344 for file, wantContent := range test.want {
1345 gotContent, ok := got[file]
1346 delete(got, file)
1347 if !ok {
1348 t.Errorf("%s: file %s not rewritten", prefix, file)
1349 continue
1350 }
1351 if gotContent != wantContent {
1352 t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
1353 "want <<<%s>>>", prefix, file, gotContent, wantContent)
1354 }
1355 }
1356
1357 for file := range got {
1358 t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
1359 }
1360 }
1361 }
1362
1363 func TestDiff(t *testing.T) {
1364 switch runtime.GOOS {
1365 case "windows":
1366 if os.Getenv("GO_BUILDER_NAME") != "" {
1367 if _, err := exec.LookPath(DiffCmd); err != nil {
1368 t.Skipf("diff tool non-existent for %s on builders", runtime.GOOS)
1369 }
1370 }
1371 case "plan9":
1372 t.Skipf("plan9 diff tool doesn't support -u flag")
1373 }
1374 testenv.NeedsTool(t, DiffCmd)
1375 testenv.NeedsTool(t, "go")
1376
1377 defer func() {
1378 Diff = false
1379 stdout = os.Stdout
1380 }()
1381 Diff = true
1382 stdout = new(bytes.Buffer)
1383
1384
1385
1386 tmpdir, err := os.MkdirTemp("", "TestDiff")
1387 if err != nil {
1388 t.Fatal(err)
1389 }
1390 defer os.RemoveAll(tmpdir)
1391 buildCtx := build.Default
1392 buildCtx.GOPATH = tmpdir
1393
1394 pkgDir := filepath.Join(tmpdir, "src", "example.com", "rename")
1395 if err := os.MkdirAll(pkgDir, 0777); err != nil {
1396 t.Fatal(err)
1397 }
1398
1399 prevWD, err := os.Getwd()
1400 if err != nil {
1401 t.Fatal(err)
1402 }
1403 defer os.Chdir(prevWD)
1404
1405 if err := os.Chdir(pkgDir); err != nil {
1406 t.Fatal(err)
1407 }
1408
1409 const modFile = `module example.com/rename
1410
1411 go 1.15
1412 `
1413 if err := os.WriteFile(filepath.Join(pkgDir, "go.mod"), []byte(modFile), 0644); err != nil {
1414 t.Fatal(err)
1415 }
1416
1417 const goFile = `package rename
1418
1419 func justHereForTestingDiff() {
1420 justHereForTestingDiff()
1421 }
1422 `
1423 if err := os.WriteFile(filepath.Join(pkgDir, "rename_test.go"), []byte(goFile), 0644); err != nil {
1424 t.Fatal(err)
1425 }
1426
1427 if err := Main(&buildCtx, "", `"example.com/rename".justHereForTestingDiff`, "Foo"); err != nil {
1428 t.Fatal(err)
1429 }
1430
1431
1432 if !strings.Contains(stdout.(fmt.Stringer).String(), `
1433 -func justHereForTestingDiff() {
1434 - justHereForTestingDiff()
1435 +func Foo() {
1436 + Foo()
1437 }
1438 `) {
1439 t.Errorf("unexpected diff:\n<<%s>>", stdout)
1440 }
1441 }
1442
1443
1444
1445
1446
1447
1448 func fakeContext(pkgs map[string][]string) *build.Context {
1449 pkgs2 := make(map[string]map[string]string)
1450 for path, files := range pkgs {
1451 filemap := make(map[string]string)
1452 for i, contents := range files {
1453 filemap[fmt.Sprintf("%d.go", i)] = contents
1454 }
1455 pkgs2[path] = filemap
1456 }
1457 return buildutil.FakeContext(pkgs2)
1458 }
1459
1460
1461 func main(content string) *build.Context {
1462 return fakeContext(map[string][]string{"main": {content}})
1463 }
1464
View as plain text