Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / cmd / gorename / gorename_test.go
1 // Copyright 2017 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 main_test
6
7 import (
8         "fmt"
9         "io/ioutil"
10         "os"
11         "os/exec"
12         "path/filepath"
13         "runtime"
14         "strconv"
15         "strings"
16         "testing"
17
18         "golang.org/x/tools/internal/testenv"
19 )
20
21 type test struct {
22         offset, from, to string // specify the arguments
23         fileSpecified    bool   // true if the offset or from args specify a specific file
24         pkgs             map[string][]string
25         wantErr          bool
26         wantOut          string              // a substring expected to be in the output
27         packages         map[string][]string // a map of the package name to the files contained within, which will be numbered by i.go where i is the index
28 }
29
30 // Test that renaming that would modify cgo files will produce an error and not modify the file.
31 func TestGeneratedFiles(t *testing.T) {
32         testenv.NeedsTool(t, "go")
33         testenv.NeedsTool(t, "cgo")
34
35         tmp, bin, cleanup := buildGorename(t)
36         defer cleanup()
37
38         srcDir := filepath.Join(tmp, "src")
39         err := os.Mkdir(srcDir, os.ModePerm)
40         if err != nil {
41                 t.Fatal(err)
42         }
43
44         var env = []string{fmt.Sprintf("GOPATH=%s", tmp)}
45         for _, envVar := range os.Environ() {
46                 if !strings.HasPrefix(envVar, "GOPATH=") {
47                         env = append(env, envVar)
48                 }
49         }
50         // gorename currently requires GOPATH mode.
51         env = append(env, "GO111MODULE=off")
52
53         // Testing renaming in packages that include cgo files:
54         for iter, renameTest := range []test{
55                 {
56                         // Test: variable not used in any cgo file -> no error
57                         from: `"mytest"::f`, to: "g",
58                         packages: map[string][]string{
59                                 "mytest": []string{`package mytest; func f() {}`,
60                                         `package mytest
61 // #include <stdio.h>
62 import "C"
63
64 func z() {C.puts(nil)}`},
65                         },
66                         wantErr: false,
67                         wantOut: "Renamed 1 occurrence in 1 file in 1 package.",
68                 }, {
69                         // Test: to name used in cgo file -> rename error
70                         from: `"mytest"::f`, to: "g",
71                         packages: map[string][]string{
72                                 "mytest": []string{`package mytest; func f() {}`,
73                                         `package mytest
74 // #include <stdio.h>
75 import "C"
76
77 func g() {C.puts(nil)}`},
78                         },
79                         wantErr: true,
80                         wantOut: "conflicts with func in same block",
81                 },
82                 {
83                         // Test: from name in package in cgo file -> error
84                         from: `"mytest"::f`, to: "g",
85                         packages: map[string][]string{
86                                 "mytest": []string{`package mytest
87
88 // #include <stdio.h>
89 import "C"
90
91 func f() { C.puts(nil); }
92 `},
93                         },
94                         wantErr: true,
95                         wantOut: "gorename: refusing to modify generated file containing DO NOT EDIT marker:",
96                 }, {
97                         // Test: from name in cgo file -> error
98                         from: filepath.Join("mytest", "0.go") + `::f`, to: "g",
99                         fileSpecified: true,
100                         packages: map[string][]string{
101                                 "mytest": []string{`package mytest
102
103 // #include <stdio.h>
104 import "C"
105
106 func f() { C.puts(nil); }
107 `},
108                         },
109                         wantErr: true,
110                         wantOut: "gorename: refusing to modify generated file containing DO NOT EDIT marker:",
111                 }, {
112                         // Test: offset in cgo file -> identifier in cgo error
113                         offset: filepath.Join("main", "0.go") + `:#78`, to: "bar",
114                         fileSpecified: true,
115                         wantErr:       true,
116                         packages: map[string][]string{
117                                 "main": {`package main
118
119 // #include <unistd.h>
120 import "C"
121 import "fmt"
122
123 func main() {
124         foo := 1
125         C.close(2)
126         fmt.Println(foo)
127 }
128 `},
129                         },
130                         wantOut: "cannot rename identifiers in generated file containing DO NOT EDIT marker:",
131                 }, {
132                         // Test: from identifier appears in cgo file in another package -> error
133                         from: `"test"::Foo`, to: "Bar",
134                         packages: map[string][]string{
135                                 "test": []string{
136                                         `package test
137
138 func Foo(x int) (int){
139         return x * 2
140 }
141 `,
142                                 },
143                                 "main": []string{
144                                         `package main
145
146 import "test"
147 import "fmt"
148 // #include <unistd.h>
149 import "C"
150
151 func fun() {
152         x := test.Foo(3)
153         C.close(3)
154         fmt.Println(x)
155 }
156 `,
157                                 },
158                         },
159                         wantErr: true,
160                         wantOut: "gorename: refusing to modify generated file containing DO NOT EDIT marker:",
161                 }, {
162                         // Test: from identifier doesn't appear in cgo file that includes modified package -> rename successful
163                         from: `"test".Foo::x`, to: "y",
164                         packages: map[string][]string{
165                                 "test": []string{
166                                         `package test
167
168 func Foo(x int) (int){
169         return x * 2
170 }
171 `,
172                                 },
173                                 "main": []string{
174                                         `package main
175 import "test"
176 import "fmt"
177 // #include <unistd.h>
178 import "C"
179
180 func fun() {
181         x := test.Foo(3)
182         C.close(3)
183         fmt.Println(x)
184 }
185 `,
186                                 },
187                         },
188                         wantErr: false,
189                         wantOut: "Renamed 2 occurrences in 1 file in 1 package.",
190                 }, {
191                         // Test: from name appears in cgo file in same package -> error
192                         from: `"mytest"::f`, to: "g",
193                         packages: map[string][]string{
194                                 "mytest": []string{`package mytest; func f() {}`,
195                                         `package mytest
196 // #include <stdio.h>
197 import "C"
198
199 func z() {C.puts(nil); f()}`,
200                                         `package mytest
201 // #include <unistd.h>
202 import "C"
203
204 func foo() {C.close(3); f()}`,
205                                 },
206                         },
207                         wantErr: true,
208                         wantOut: "gorename: refusing to modify generated files containing DO NOT EDIT marker:",
209                 }, {
210                         // Test: from name in file, identifier not used in cgo file -> rename successful
211                         from: filepath.Join("mytest", "0.go") + `::f`, to: "g",
212                         fileSpecified: true,
213                         packages: map[string][]string{
214                                 "mytest": []string{`package mytest; func f() {}`,
215                                         `package mytest
216 // #include <stdio.h>
217 import "C"
218
219 func z() {C.puts(nil)}`},
220                         },
221                         wantErr: false,
222                         wantOut: "Renamed 1 occurrence in 1 file in 1 package.",
223                 }, {
224                         // Test: from identifier imported to another package but does not modify cgo file -> rename successful
225                         from: `"test".Foo`, to: "Bar",
226                         packages: map[string][]string{
227                                 "test": []string{
228                                         `package test
229
230 func Foo(x int) (int){
231         return x * 2
232 }
233 `,
234                                 },
235                                 "main": []string{
236                                         `package main
237 // #include <unistd.h>
238 import "C"
239
240 func fun() {
241         C.close(3)
242 }
243 `,
244                                         `package main
245 import "test"
246 import "fmt"
247 func g() { fmt.Println(test.Foo(3)) }
248 `,
249                                 },
250                         },
251                         wantErr: false,
252                         wantOut: "Renamed 2 occurrences in 2 files in 2 packages.",
253                 },
254         } {
255                 // Write the test files
256                 testCleanup := setUpPackages(t, srcDir, renameTest.packages)
257
258                 // Set up arguments
259                 var args []string
260
261                 var arg, val string
262                 if renameTest.offset != "" {
263                         arg, val = "-offset", renameTest.offset
264                 } else {
265                         arg, val = "-from", renameTest.from
266                 }
267
268                 prefix := fmt.Sprintf("%d: %s %q -to %q", iter, arg, val, renameTest.to)
269
270                 if renameTest.fileSpecified {
271                         // add the src dir to the value of the argument
272                         val = filepath.Join(srcDir, val)
273                 }
274
275                 args = append(args, arg, val, "-to", renameTest.to)
276
277                 // Run command
278                 cmd := exec.Command(bin, args...)
279                 cmd.Args[0] = "gorename"
280                 cmd.Env = env
281
282                 // Check the output
283                 out, err := cmd.CombinedOutput()
284                 // errors should result in no changes to files
285                 if err != nil {
286                         if !renameTest.wantErr {
287                                 t.Errorf("%s: received unexpected error %s", prefix, err)
288                         }
289                         // Compare output
290                         if ok := strings.Contains(string(out), renameTest.wantOut); !ok {
291                                 t.Errorf("%s: unexpected command output: %s (want: %s)", prefix, out, renameTest.wantOut)
292                         }
293                         // Check that no files were modified
294                         if modified := modifiedFiles(t, srcDir, renameTest.packages); len(modified) != 0 {
295                                 t.Errorf("%s: files unexpectedly modified: %s", prefix, modified)
296                         }
297
298                 } else {
299                         if !renameTest.wantErr {
300                                 if ok := strings.Contains(string(out), renameTest.wantOut); !ok {
301                                         t.Errorf("%s: unexpected command output: %s (want: %s)", prefix, out, renameTest.wantOut)
302                                 }
303                         } else {
304                                 t.Errorf("%s: command succeeded unexpectedly, output: %s", prefix, out)
305                         }
306                 }
307                 testCleanup()
308         }
309 }
310
311 // buildGorename builds the gorename executable.
312 // It returns its path, and a cleanup function.
313 func buildGorename(t *testing.T) (tmp, bin string, cleanup func()) {
314         if runtime.GOOS == "android" {
315                 t.Skipf("the dependencies are not available on android")
316         }
317
318         tmp, err := ioutil.TempDir("", "gorename-regtest-")
319         if err != nil {
320                 t.Fatal(err)
321         }
322
323         defer func() {
324                 if cleanup == nil { // probably, go build failed.
325                         os.RemoveAll(tmp)
326                 }
327         }()
328
329         bin = filepath.Join(tmp, "gorename")
330         if runtime.GOOS == "windows" {
331                 bin += ".exe"
332         }
333         cmd := exec.Command("go", "build", "-o", bin)
334         if err := cmd.Run(); err != nil {
335                 t.Fatalf("Building gorename: %v", err)
336         }
337         return tmp, bin, func() { os.RemoveAll(tmp) }
338 }
339
340 // setUpPackages sets up the files in a temporary directory provided by arguments.
341 func setUpPackages(t *testing.T, dir string, packages map[string][]string) (cleanup func()) {
342         var pkgDirs []string
343
344         for pkgName, files := range packages {
345                 // Create a directory for the package.
346                 pkgDir := filepath.Join(dir, pkgName)
347                 pkgDirs = append(pkgDirs, pkgDir)
348
349                 if err := os.Mkdir(pkgDir, os.ModePerm); err != nil {
350                         t.Fatal(err)
351                 }
352                 // Write the packages files
353                 for i, val := range files {
354                         file := filepath.Join(pkgDir, strconv.Itoa(i)+".go")
355                         if err := ioutil.WriteFile(file, []byte(val), os.ModePerm); err != nil {
356                                 t.Fatal(err)
357                         }
358                 }
359         }
360         return func() {
361                 for _, dir := range pkgDirs {
362                         os.RemoveAll(dir)
363                 }
364         }
365 }
366
367 // modifiedFiles returns a list of files that were renamed (without the prefix dir).
368 func modifiedFiles(t *testing.T, dir string, packages map[string][]string) (results []string) {
369
370         for pkgName, files := range packages {
371                 pkgDir := filepath.Join(dir, pkgName)
372
373                 for i, val := range files {
374                         file := filepath.Join(pkgDir, strconv.Itoa(i)+".go")
375                         // read file contents and compare to val
376                         if contents, err := ioutil.ReadFile(file); err != nil {
377                                 t.Fatalf("File missing: %s", err)
378                         } else if string(contents) != val {
379                                 results = append(results, strings.TrimPrefix(dir, file))
380                         }
381                 }
382         }
383         return results
384 }