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 / refactor / rename / mvpkg_test.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // licence that can be found in the LICENSE file.
4
5 package rename
6
7 import (
8         "fmt"
9         "go/build"
10         "go/token"
11         "io/ioutil"
12         "path/filepath"
13         "reflect"
14         "regexp"
15         "strings"
16         "testing"
17
18         "golang.org/x/tools/go/buildutil"
19 )
20
21 func TestErrors(t *testing.T) {
22         tests := []struct {
23                 ctxt     *build.Context
24                 from, to string
25                 want     string // regexp to match error, or "OK"
26         }{
27                 // Simple example.
28                 {
29                         ctxt: fakeContext(map[string][]string{
30                                 "foo": {`package foo; type T int`},
31                                 "bar": {`package bar`},
32                                 "main": {`package main
33
34 import "foo"
35
36 var _ foo.T
37 `},
38                         }),
39                         from: "foo", to: "bar",
40                         want: `invalid move destination: bar conflicts with directory .go.src.bar`,
41                 },
42                 // Subpackage already exists.
43                 {
44                         ctxt: fakeContext(map[string][]string{
45                                 "foo":     {`package foo; type T int`},
46                                 "foo/sub": {`package sub`},
47                                 "bar/sub": {`package sub`},
48                                 "main": {`package main
49
50 import "foo"
51
52 var _ foo.T
53 `},
54                         }),
55                         from: "foo", to: "bar",
56                         want: "invalid move destination: bar; package or subpackage bar/sub already exists",
57                 },
58                 // Invalid base name.
59                 {
60                         ctxt: fakeContext(map[string][]string{
61                                 "foo": {`package foo; type T int`},
62                                 "main": {`package main
63
64 import "foo"
65
66 var _ foo.T
67 `},
68                         }),
69                         from: "foo", to: "bar-v2.0",
70                         want: "invalid move destination: bar-v2.0; gomvpkg does not " +
71                                 "support move destinations whose base names are not valid " +
72                                 "go identifiers",
73                 },
74                 {
75                         ctxt: fakeContext(map[string][]string{
76                                 "foo": {``},
77                                 "bar": {`package bar`},
78                         }),
79                         from: "foo", to: "bar",
80                         want: `no initial packages were loaded`,
81                 },
82         }
83
84         for _, test := range tests {
85                 ctxt := test.ctxt
86
87                 got := make(map[string]string)
88                 writeFile = func(filename string, content []byte) error {
89                         got[filename] = string(content)
90                         return nil
91                 }
92                 moveDirectory = func(from, to string) error {
93                         for path, contents := range got {
94                                 if strings.HasPrefix(path, from) {
95                                         newPath := strings.Replace(path, from, to, 1)
96                                         delete(got, path)
97                                         got[newPath] = contents
98                                 }
99                         }
100                         return nil
101                 }
102
103                 err := Move(ctxt, test.from, test.to, "")
104                 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
105                 if err == nil {
106                         t.Errorf("%s: nil error. Expected error: %s", prefix, test.want)
107                         continue
108                 }
109                 matched, err2 := regexp.MatchString(test.want, err.Error())
110                 if err2 != nil {
111                         t.Errorf("regexp.MatchString failed %s", err2)
112                         continue
113                 }
114                 if !matched {
115                         t.Errorf("%s: conflict does not match expectation:\n"+
116                                 "Error: %q\n"+
117                                 "Pattern: %q",
118                                 prefix, err.Error(), test.want)
119                 }
120         }
121 }
122
123 func TestMoves(t *testing.T) {
124         tests := []struct {
125                 ctxt         *build.Context
126                 from, to     string
127                 want         map[string]string
128                 wantWarnings []string
129         }{
130                 // Simple example.
131                 {
132                         ctxt: fakeContext(map[string][]string{
133                                 "foo": {`package foo; type T int`},
134                                 "main": {`package main
135
136 import "foo"
137
138 var _ foo.T
139 `},
140                         }),
141                         from: "foo", to: "bar",
142                         want: map[string]string{
143                                 "/go/src/main/0.go": `package main
144
145 import "bar"
146
147 var _ bar.T
148 `,
149                                 "/go/src/bar/0.go": `package bar
150
151 type T int
152 `,
153                         },
154                 },
155
156                 // Example with subpackage.
157                 {
158                         ctxt: fakeContext(map[string][]string{
159                                 "foo":     {`package foo; type T int`},
160                                 "foo/sub": {`package sub; type T int`},
161                                 "main": {`package main
162
163 import "foo"
164 import "foo/sub"
165
166 var _ foo.T
167 var _ sub.T
168 `},
169                         }),
170                         from: "foo", to: "bar",
171                         want: map[string]string{
172                                 "/go/src/main/0.go": `package main
173
174 import "bar"
175 import "bar/sub"
176
177 var _ bar.T
178 var _ sub.T
179 `,
180                                 "/go/src/bar/0.go": `package bar
181
182 type T int
183 `,
184                                 "/go/src/bar/sub/0.go": `package sub; type T int`,
185                         },
186                 },
187
188                 // References into subpackages
189                 {
190                         ctxt: fakeContext(map[string][]string{
191                                 "foo":   {`package foo; import "foo/a"; var _ a.T`},
192                                 "foo/a": {`package a; type T int`},
193                                 "foo/b": {`package b; import "foo/a"; var _ a.T`},
194                         }),
195                         from: "foo", to: "bar",
196                         want: map[string]string{
197                                 "/go/src/bar/0.go": `package bar
198
199 import "bar/a"
200
201 var _ a.T
202 `,
203                                 "/go/src/bar/a/0.go": `package a; type T int`,
204                                 "/go/src/bar/b/0.go": `package b
205
206 import "bar/a"
207
208 var _ a.T
209 `,
210                         },
211                 },
212
213                 // References into subpackages where directories have overlapped names
214                 {
215                         ctxt: fakeContext(map[string][]string{
216                                 "foo":    {},
217                                 "foo/a":  {`package a`},
218                                 "foo/aa": {`package bar`},
219                                 "foo/c":  {`package c; import _ "foo/bar";`},
220                         }),
221                         from: "foo/a", to: "foo/spam",
222                         want: map[string]string{
223                                 "/go/src/foo/spam/0.go": `package spam
224 `,
225                                 "/go/src/foo/aa/0.go": `package bar`,
226                                 "/go/src/foo/c/0.go":  `package c; import _ "foo/bar";`,
227                         },
228                 },
229
230                 // External test packages
231                 {
232                         ctxt: buildutil.FakeContext(map[string]map[string]string{
233                                 "foo": {
234                                         "0.go":      `package foo; type T int`,
235                                         "0_test.go": `package foo_test; import "foo"; var _ foo.T`,
236                                 },
237                                 "baz": {
238                                         "0_test.go": `package baz_test; import "foo"; var _ foo.T`,
239                                 },
240                         }),
241                         from: "foo", to: "bar",
242                         want: map[string]string{
243                                 "/go/src/bar/0.go": `package bar
244
245 type T int
246 `,
247                                 "/go/src/bar/0_test.go": `package bar_test
248
249 import "bar"
250
251 var _ bar.T
252 `,
253                                 "/go/src/baz/0_test.go": `package baz_test
254
255 import "bar"
256
257 var _ bar.T
258 `,
259                         },
260                 },
261                 // package import comments
262                 {
263                         ctxt: fakeContext(map[string][]string{"foo": {`package foo // import "baz"`}}),
264                         from: "foo", to: "bar",
265                         want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
266 `},
267                 },
268                 {
269                         ctxt: fakeContext(map[string][]string{"foo": {`package foo /* import "baz" */`}}),
270                         from: "foo", to: "bar",
271                         want: map[string]string{"/go/src/bar/0.go": `package bar /* import "bar" */
272 `},
273                 },
274                 {
275                         ctxt: fakeContext(map[string][]string{"foo": {`package foo       // import "baz"`}}),
276                         from: "foo", to: "bar",
277                         want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
278 `},
279                 },
280                 {
281                         ctxt: fakeContext(map[string][]string{"foo": {`package foo
282 // import " this is not an import comment`}}),
283                         from: "foo", to: "bar",
284                         want: map[string]string{"/go/src/bar/0.go": `package bar
285
286 // import " this is not an import comment
287 `},
288                 },
289                 {
290                         ctxt: fakeContext(map[string][]string{"foo": {`package foo
291 /* import " this is not an import comment */`}}),
292                         from: "foo", to: "bar",
293                         want: map[string]string{"/go/src/bar/0.go": `package bar
294
295 /* import " this is not an import comment */
296 `},
297                 },
298                 // Import name conflict generates a warning, not an error.
299                 {
300                         ctxt: fakeContext(map[string][]string{
301                                 "x": {},
302                                 "a": {`package a; type A int`},
303                                 "b": {`package b; type B int`},
304                                 "conflict": {`package conflict
305
306 import "a"
307 import "b"
308 var _ a.A
309 var _ b.B
310 `},
311                                 "ok": {`package ok
312 import "b"
313 var _ b.B
314 `},
315                         }),
316                         from: "b", to: "x/a",
317                         want: map[string]string{
318                                 "/go/src/a/0.go": `package a; type A int`,
319                                 "/go/src/ok/0.go": `package ok
320
321 import "x/a"
322
323 var _ a.B
324 `,
325                                 "/go/src/conflict/0.go": `package conflict
326
327 import "a"
328 import "x/a"
329
330 var _ a.A
331 var _ b.B
332 `,
333                                 "/go/src/x/a/0.go": `package a
334
335 type B int
336 `,
337                         },
338                         wantWarnings: []string{
339                                 `/go/src/conflict/0.go:4:8: renaming this imported package name "b" to "a"`,
340                                 `/go/src/conflict/0.go:3:8:     conflicts with imported package name in same block`,
341                                 `/go/src/conflict/0.go:3:8: skipping update of this file`,
342                         },
343                 },
344                 // Rename with same base name.
345                 {
346                         ctxt: fakeContext(map[string][]string{
347                                 "x": {},
348                                 "y": {},
349                                 "x/foo": {`package foo
350
351 type T int
352 `},
353                                 "main": {`package main; import "x/foo"; var _ foo.T`},
354                         }),
355                         from: "x/foo", to: "y/foo",
356                         want: map[string]string{
357                                 "/go/src/y/foo/0.go": `package foo
358
359 type T int
360 `,
361                                 "/go/src/main/0.go": `package main
362
363 import "y/foo"
364
365 var _ foo.T
366 `,
367                         },
368                 },
369         }
370
371         for _, test := range tests {
372                 ctxt := test.ctxt
373
374                 got := make(map[string]string)
375                 // Populate got with starting file set. rewriteFile and moveDirectory
376                 // will mutate got to produce resulting file set.
377                 buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
378                         if err != nil {
379                                 return
380                         }
381                         path := filepath.Join("/go/src", importPath, "0.go")
382                         if !buildutil.FileExists(ctxt, path) {
383                                 return
384                         }
385                         f, err := ctxt.OpenFile(path)
386                         if err != nil {
387                                 t.Errorf("unexpected error opening file: %s", err)
388                                 return
389                         }
390                         bytes, err := ioutil.ReadAll(f)
391                         f.Close()
392                         if err != nil {
393                                 t.Errorf("unexpected error reading file: %s", err)
394                                 return
395                         }
396                         got[path] = string(bytes)
397                 })
398                 var warnings []string
399                 reportError = func(posn token.Position, message string) {
400                         warning := fmt.Sprintf("%s:%d:%d: %s",
401                                 filepath.ToSlash(posn.Filename), // for MS Windows
402                                 posn.Line,
403                                 posn.Column,
404                                 message)
405                         warnings = append(warnings, warning)
406
407                 }
408                 writeFile = func(filename string, content []byte) error {
409                         got[filename] = string(content)
410                         return nil
411                 }
412                 moveDirectory = func(from, to string) error {
413                         for path, contents := range got {
414                                 if !(strings.HasPrefix(path, from) &&
415                                         (len(path) == len(from) || path[len(from)] == filepath.Separator)) {
416                                         continue
417                                 }
418                                 newPath := strings.Replace(path, from, to, 1)
419                                 delete(got, path)
420                                 got[newPath] = contents
421                         }
422                         return nil
423                 }
424
425                 err := Move(ctxt, test.from, test.to, "")
426                 prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
427                 if err != nil {
428                         t.Errorf("%s: unexpected error: %s", prefix, err)
429                         continue
430                 }
431
432                 if !reflect.DeepEqual(warnings, test.wantWarnings) {
433                         t.Errorf("%s: unexpected warnings:\n%s\nwant:\n%s",
434                                 prefix,
435                                 strings.Join(warnings, "\n"),
436                                 strings.Join(test.wantWarnings, "\n"))
437                 }
438
439                 for file, wantContent := range test.want {
440                         k := filepath.FromSlash(file)
441                         gotContent, ok := got[k]
442                         delete(got, k)
443                         if !ok {
444                                 // TODO(matloob): some testcases might have files that won't be
445                                 // rewritten
446                                 t.Errorf("%s: file %s not rewritten", prefix, file)
447                                 continue
448                         }
449                         if gotContent != wantContent {
450                                 t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
451                                         "want <<<%s>>>", prefix, file, gotContent, wantContent)
452                         }
453                 }
454                 // got should now be empty
455                 for file := range got {
456                         t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
457                 }
458         }
459 }