GoPLS Viewer

Home|gopls/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
5package main_test
6
7import (
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
21type test struct {
22    offsetfromto 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.
31func TestGeneratedFiles(t *testing.T) {
32    testenv.NeedsTool(t"go")
33    testenv.NeedsTool(t"cgo")
34
35    tmpbincleanup := buildGorename(t)
36    defer cleanup()
37
38    srcDir := filepath.Join(tmp"src")
39    err := os.Mkdir(srcDiros.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(envenvVar)
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 iterrenameTest := 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>
62import "C"
63
64func z() {C.puts(nil)}`},
65            },
66            wantErrfalse,
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>
75import "C"
76
77func g() {C.puts(nil)}`},
78            },
79            wantErrtrue,
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>
89import "C"
90
91func f() { C.puts(nil); }
92`},
93            },
94            wantErrtrue,
95            wantOut"gorename: refusing to modify generated file containing DO NOT EDIT marker:",
96        }, {
97            // Test: from name in cgo file -> error
98            fromfilepath.Join("mytest""0.go") + `::f`to"g",
99            fileSpecifiedtrue,
100            packages: map[string][]string{
101                "mytest": []string{`package mytest
102
103// #include <stdio.h>
104import "C"
105
106func f() { C.puts(nil); }
107`},
108            },
109            wantErrtrue,
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            offsetfilepath.Join("main""0.go") + `:#78`to"bar",
114            fileSpecifiedtrue,
115            wantErr:       true,
116            packages: map[string][]string{
117                "main": {`package main
118
119// #include <unistd.h>
120import "C"
121import "fmt"
122
123func 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
138func Foo(x int) (int){
139    return x * 2
140}
141`,
142                },
143                "main": []string{
144                    `package main
145
146import "test"
147import "fmt"
148// #include <unistd.h>
149import "C"
150
151func fun() {
152    x := test.Foo(3)
153    C.close(3)
154    fmt.Println(x)
155}
156`,
157                },
158            },
159            wantErrtrue,
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
168func Foo(x int) (int){
169    return x * 2
170}
171`,
172                },
173                "main": []string{
174                    `package main
175import "test"
176import "fmt"
177// #include <unistd.h>
178import "C"
179
180func fun() {
181    x := test.Foo(3)
182    C.close(3)
183    fmt.Println(x)
184}
185`,
186                },
187            },
188            wantErrfalse,
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>
197import "C"
198
199func z() {C.puts(nil); f()}`,
200                    `package mytest
201// #include <unistd.h>
202import "C"
203
204func foo() {C.close(3); f()}`,
205                },
206            },
207            wantErrtrue,
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            fromfilepath.Join("mytest""0.go") + `::f`to"g",
212            fileSpecifiedtrue,
213            packages: map[string][]string{
214                "mytest": []string{`package mytest; func f() {}`,
215                    `package mytest
216// #include <stdio.h>
217import "C"
218
219func z() {C.puts(nil)}`},
220            },
221            wantErrfalse,
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
230func Foo(x int) (int){
231    return x * 2
232}
233`,
234                },
235                "main": []string{
236                    `package main
237// #include <unistd.h>
238import "C"
239
240func fun() {
241    C.close(3)
242}
243`,
244                    `package main
245import "test"
246import "fmt"
247func g() { fmt.Println(test.Foo(3)) }
248`,
249                },
250            },
251            wantErrfalse,
252            wantOut"Renamed 2 occurrences in 2 files in 2 packages.",
253        },
254    } {
255        // Write the test files
256        testCleanup := setUpPackages(tsrcDirrenameTest.packages)
257
258        // Set up arguments
259        var args []string
260
261        var argval string
262        if renameTest.offset != "" {
263            argval = "-offset"renameTest.offset
264        } else {
265            argval = "-from"renameTest.from
266        }
267
268        prefix := fmt.Sprintf("%d: %s %q -to %q"iterargvalrenameTest.to)
269
270        if renameTest.fileSpecified {
271            // add the src dir to the value of the argument
272            val = filepath.Join(srcDirval)
273        }
274
275        args = append(argsargval"-to"renameTest.to)
276
277        // Run command
278        cmd := exec.Command(binargs...)
279        cmd.Args[0] = "gorename"
280        cmd.Env = env
281
282        // Check the output
283        outerr := 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"prefixerr)
288            }
289            // Compare output
290            if ok := strings.Contains(string(out), renameTest.wantOut); !ok {
291                t.Errorf("%s: unexpected command output: %s (want: %s)"prefixoutrenameTest.wantOut)
292            }
293            // Check that no files were modified
294            if modified := modifiedFiles(tsrcDirrenameTest.packages); len(modified) != 0 {
295                t.Errorf("%s: files unexpectedly modified: %s"prefixmodified)
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)"prefixoutrenameTest.wantOut)
302                }
303            } else {
304                t.Errorf("%s: command succeeded unexpectedly, output: %s"prefixout)
305            }
306        }
307        testCleanup()
308    }
309}
310
311// buildGorename builds the gorename executable.
312// It returns its path, and a cleanup function.
313func buildGorename(t *testing.T) (tmpbin stringcleanup func()) {
314    if runtime.GOOS == "android" {
315        t.Skipf("the dependencies are not available on android")
316    }
317
318    tmperr := 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 outerr := cmd.CombinedOutput(); err != nil {
335        t.Fatalf("Building gorename: %v\n%s"errout)
336    }
337    return tmpbin, func() { os.RemoveAll(tmp) }
338}
339
340// setUpPackages sets up the files in a temporary directory provided by arguments.
341func setUpPackages(t *testing.Tdir stringpackages map[string][]string) (cleanup func()) {
342    var pkgDirs []string
343
344    for pkgNamefiles := range packages {
345        // Create a directory for the package.
346        pkgDir := filepath.Join(dirpkgName)
347        pkgDirs = append(pkgDirspkgDir)
348
349        if err := os.Mkdir(pkgDiros.ModePerm); err != nil {
350            t.Fatal(err)
351        }
352        // Write the packages files
353        for ival := range files {
354            file := filepath.Join(pkgDirstrconv.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).
368func modifiedFiles(t *testing.Tdir stringpackages map[string][]string) (results []string) {
369
370    for pkgNamefiles := range packages {
371        pkgDir := filepath.Join(dirpkgName)
372
373        for ival := range files {
374            file := filepath.Join(pkgDirstrconv.Itoa(i)+".go")
375            // read file contents and compare to val
376            if contentserr := ioutil.ReadFile(file); err != nil {
377                t.Fatalf("File missing: %s"err)
378            } else if string(contents) != val {
379                results = append(resultsstrings.TrimPrefix(dirfile))
380            }
381        }
382    }
383    return results
384}
385
MembersX
TestGeneratedFiles.RangeStmt_1455.BlockStmt.BlockStmt.ok
modifiedFiles.packages
modifiedFiles.RangeStmt_9136.BlockStmt.RangeStmt_9218.BlockStmt.file
modifiedFiles.RangeStmt_9136.BlockStmt.RangeStmt_9218.BlockStmt.err
TestGeneratedFiles
modifiedFiles.RangeStmt_9136.pkgName
setUpPackages.RangeStmt_8419.BlockStmt.RangeStmt_8684.val
setUpPackages.packages
setUpPackages.cleanup
setUpPackages.RangeStmt_8419.BlockStmt.RangeStmt_8684.BlockStmt.file
modifiedFiles.RangeStmt_9136.files
modifiedFiles.RangeStmt_9136.BlockStmt.RangeStmt_9218.BlockStmt.contents
TestGeneratedFiles.t
TestGeneratedFiles.RangeStmt_1455.BlockStmt.BlockStmt.BlockStmt.ok
setUpPackages
setUpPackages.RangeStmt_8419.BlockStmt.err
setUpPackages.RangeStmt_8419.BlockStmt.RangeStmt_8684.BlockStmt.err
setUpPackages.BlockStmt.RangeStmt_8892.dir
TestGeneratedFiles.RangeStmt_1455.BlockStmt.arg
filepath
strings
buildGorename.bin
setUpPackages.RangeStmt_8419.pkgName
modifiedFiles.dir
modifiedFiles.results
ioutil
test.wantErr
TestGeneratedFiles.tmp
TestGeneratedFiles.RangeStmt_1194.envVar
buildGorename.cleanup
buildGorename.cmd
test.fileSpecified
exec
runtime
testing
TestGeneratedFiles.RangeStmt_1455.iter
TestGeneratedFiles.RangeStmt_1455.BlockStmt.args
setUpPackages.RangeStmt_8419.BlockStmt.pkgDir
os
TestGeneratedFiles.srcDir
modifiedFiles.t
test
TestGeneratedFiles.cleanup
TestGeneratedFiles.err
TestGeneratedFiles.RangeStmt_1455.BlockStmt.cmd
buildGorename.tmp
strconv
TestGeneratedFiles.RangeStmt_1455.BlockStmt.testCleanup
TestGeneratedFiles.RangeStmt_1455.BlockStmt.err
test.from
TestGeneratedFiles.RangeStmt_1455.BlockStmt.val
buildGorename.err
buildGorename.out
test.pkgs
test.to
TestGeneratedFiles.RangeStmt_1455.BlockStmt.BlockStmt.modified
buildGorename
buildGorename.t
setUpPackages.t
setUpPackages.pkgDirs
test.offset
TestGeneratedFiles.bin
setUpPackages.dir
setUpPackages.RangeStmt_8419.BlockStmt.RangeStmt_8684.i
modifiedFiles.RangeStmt_9136.BlockStmt.pkgDir
testenv
modifiedFiles.RangeStmt_9136.BlockStmt.RangeStmt_9218.i
test.wantOut
TestGeneratedFiles.RangeStmt_1455.BlockStmt.out
setUpPackages.RangeStmt_8419.files
modifiedFiles.RangeStmt_9136.BlockStmt.RangeStmt_9218.val
test.packages
TestGeneratedFiles.RangeStmt_1455.renameTest
TestGeneratedFiles.RangeStmt_1455.BlockStmt.prefix
modifiedFiles
fmt
Members
X