Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.5.2 / internal / regtest / workspace_test.go
1 // Copyright 2020 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 regtest
6
7 import (
8         "fmt"
9         "strings"
10         "testing"
11
12         "golang.org/x/tools/internal/lsp"
13         "golang.org/x/tools/internal/lsp/fake"
14         "golang.org/x/tools/internal/testenv"
15 )
16
17 const workspaceProxy = `
18 -- example.com@v1.2.3/go.mod --
19 module example.com
20
21 go 1.12
22 -- example.com@v1.2.3/blah/blah.go --
23 package blah
24
25 func SaySomething() {
26         fmt.Println("something")
27 }
28 -- random.org@v1.2.3/go.mod --
29 module random.org
30
31 go 1.12
32 -- random.org@v1.2.3/bye/bye.go --
33 package bye
34
35 func Goodbye() {
36         println("Bye")
37 }
38 `
39
40 // TODO: Add a replace directive.
41 const workspaceModule = `
42 -- pkg/go.mod --
43 module mod.com
44
45 go 1.14
46
47 require (
48         example.com v1.2.3
49         random.org v1.2.3
50 )
51 -- pkg/main.go --
52 package main
53
54 import (
55         "example.com/blah"
56         "mod.com/inner"
57         "random.org/bye"
58 )
59
60 func main() {
61         blah.SaySomething()
62         inner.Hi()
63         bye.Goodbye()
64 }
65 -- pkg/main2.go --
66 package main
67
68 import "fmt"
69
70 func _() {
71         fmt.Print("%s")
72 }
73 -- pkg/inner/inner.go --
74 package inner
75
76 import "example.com/blah"
77
78 func Hi() {
79         blah.SaySomething()
80 }
81 -- goodbye/bye/bye.go --
82 package bye
83
84 func Bye() {}
85 -- goodbye/go.mod --
86 module random.org
87
88 go 1.12
89 `
90
91 // Confirm that find references returns all of the references in the module,
92 // regardless of what the workspace root is.
93 func TestReferences(t *testing.T) {
94         for _, tt := range []struct {
95                 name, rootPath string
96         }{
97                 {
98                         name:     "module root",
99                         rootPath: "pkg",
100                 },
101                 {
102                         name:     "subdirectory",
103                         rootPath: "pkg/inner",
104                 },
105         } {
106                 t.Run(tt.name, func(t *testing.T) {
107                         opts := []RunOption{WithProxyFiles(workspaceProxy)}
108                         if tt.rootPath != "" {
109                                 opts = append(opts, WithRootPath(tt.rootPath))
110                         }
111                         withOptions(opts...).run(t, workspaceModule, func(t *testing.T, env *Env) {
112                                 f := "pkg/inner/inner.go"
113                                 env.OpenFile(f)
114                                 locations := env.References(f, env.RegexpSearch(f, `SaySomething`))
115                                 want := 3
116                                 if got := len(locations); got != want {
117                                         t.Fatalf("expected %v locations, got %v", want, got)
118                                 }
119                         })
120                 })
121         }
122 }
123
124 // Make sure that analysis diagnostics are cleared for the whole package when
125 // the only opened file is closed. This test was inspired by the experience in
126 // VS Code, where clicking on a reference result triggers a
127 // textDocument/didOpen without a corresponding textDocument/didClose.
128 func TestClearAnalysisDiagnostics(t *testing.T) {
129         withOptions(WithProxyFiles(workspaceProxy), WithRootPath("pkg/inner")).run(t, workspaceModule, func(t *testing.T, env *Env) {
130                 env.OpenFile("pkg/main.go")
131                 env.Await(
132                         env.DiagnosticAtRegexp("pkg/main2.go", "fmt.Print"),
133                 )
134                 env.CloseBuffer("pkg/main.go")
135                 env.Await(
136                         EmptyDiagnostics("pkg/main2.go"),
137                 )
138         })
139 }
140
141 // This test checks that gopls updates the set of files it watches when a
142 // replace target is added to the go.mod.
143 func TestWatchReplaceTargets(t *testing.T) {
144         withOptions(WithProxyFiles(workspaceProxy), WithRootPath("pkg")).run(t, workspaceModule, func(t *testing.T, env *Env) {
145                 // Add a replace directive and expect the files that gopls is watching
146                 // to change.
147                 dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename()
148                 goModWithReplace := fmt.Sprintf(`%s
149 replace random.org => %s
150 `, env.ReadWorkspaceFile("pkg/go.mod"), dir)
151                 env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace)
152                 env.Await(
153                         CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
154                         UnregistrationMatching("didChangeWatchedFiles"),
155                         RegistrationMatching("didChangeWatchedFiles"),
156                 )
157         })
158 }
159
160 const workspaceModuleProxy = `
161 -- b.com@v1.2.3/go.mod --
162 module b.com
163
164 go 1.12
165 -- b.com@v1.2.3/b/b.go --
166 package b
167
168 func Hello() {}
169 `
170
171 func TestAutomaticWorkspaceModule_Interdependent(t *testing.T) {
172         const multiModule = `
173 -- moda/a/go.mod --
174 module a.com
175
176 require b.com v1.2.3
177
178 -- moda/a/a.go --
179 package a
180
181 import (
182         "b.com/b"
183 )
184
185 func main() {
186         var x int
187         _ = b.Hello()
188 }
189 -- modb/go.mod --
190 module b.com
191
192 -- modb/b/b.go --
193 package b
194
195 func Hello() int {
196         var x int
197 }
198 `
199         withOptions(
200                 WithProxyFiles(workspaceModuleProxy),
201                 WithModes(Experimental),
202         ).run(t, multiModule, func(t *testing.T, env *Env) {
203                 env.Await(
204                         env.DiagnosticAtRegexp("moda/a/a.go", "x"),
205                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
206                         env.NoDiagnosticAtRegexp("moda/a/a.go", `"b.com/b"`),
207                 )
208         })
209 }
210
211 // This change tests that the version of the module used changes after it has
212 // been deleted from the workspace.
213 func TestDeleteModule_Interdependent(t *testing.T) {
214         const multiModule = `
215 -- moda/a/go.mod --
216 module a.com
217
218 require b.com v1.2.3
219
220 -- moda/a/a.go --
221 package a
222
223 import (
224         "b.com/b"
225 )
226
227 func main() {
228         var x int
229         _ = b.Hello()
230 }
231 -- modb/go.mod --
232 module b.com
233
234 -- modb/b/b.go --
235 package b
236
237 func Hello() int {
238         var x int
239 }
240 `
241         withOptions(
242                 WithProxyFiles(workspaceModuleProxy),
243                 WithModes(Experimental),
244         ).run(t, multiModule, func(t *testing.T, env *Env) {
245                 env.OpenFile("moda/a/a.go")
246
247                 original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
248                 if want := "modb/b/b.go"; !strings.HasSuffix(original, want) {
249                         t.Errorf("expected %s, got %v", want, original)
250                 }
251                 env.CloseBuffer(original)
252                 env.RemoveWorkspaceFile("modb/b/b.go")
253                 env.RemoveWorkspaceFile("modb/go.mod")
254                 env.Await(
255                         CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 2),
256                 )
257                 got, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
258                 if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(got, want) {
259                         t.Errorf("expected %s, got %v", want, got)
260                 }
261         })
262 }
263
264 // Tests that the version of the module used changes after it has been added
265 // to the workspace.
266 func TestCreateModule_Interdependent(t *testing.T) {
267         const multiModule = `
268 -- moda/a/go.mod --
269 module a.com
270
271 require b.com v1.2.3
272
273 -- moda/a/a.go --
274 package a
275
276 import (
277         "b.com/b"
278 )
279
280 func main() {
281         var x int
282         _ = b.Hello()
283 }
284 `
285         withOptions(
286                 WithModes(Experimental),
287                 WithProxyFiles(workspaceModuleProxy),
288         ).run(t, multiModule, func(t *testing.T, env *Env) {
289                 env.OpenFile("moda/a/a.go")
290                 original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
291                 if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(original, want) {
292                         t.Errorf("expected %s, got %v", want, original)
293                 }
294                 env.CloseBuffer(original)
295                 env.WriteWorkspaceFiles(map[string]string{
296                         "modb/go.mod": "module b.com",
297                         "modb/b/b.go": `package b
298
299 func Hello() int {
300         var x int
301 }
302 `,
303                 })
304                 env.Await(
305                         OnceMet(
306                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
307                                 env.DiagnosticAtRegexp("modb/b/b.go", "x"),
308                         ),
309                 )
310                 got, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
311                 if want := "modb/b/b.go"; !strings.HasSuffix(got, want) {
312                         t.Errorf("expected %s, got %v", want, original)
313                 }
314         })
315 }
316
317 // This test confirms that a gopls workspace can recover from initialization
318 // with one invalid module.
319 func TestOneBrokenModule(t *testing.T) {
320         const multiModule = `
321 -- moda/a/go.mod --
322 module a.com
323
324 require b.com v1.2.3
325
326 -- moda/a/a.go --
327 package a
328
329 import (
330         "b.com/b"
331 )
332
333 func main() {
334         var x int
335         _ = b.Hello()
336 }
337 -- modb/go.mod --
338 modul b.com // typo here
339
340 -- modb/b/b.go --
341 package b
342
343 func Hello() int {
344         var x int
345 }
346 `
347         withOptions(
348                 WithProxyFiles(workspaceModuleProxy),
349                 WithModes(Experimental),
350         ).run(t, multiModule, func(t *testing.T, env *Env) {
351                 env.OpenFile("modb/go.mod")
352                 env.Await(
353                         OnceMet(
354                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
355                                 DiagnosticAt("modb/go.mod", 0, 0),
356                         ),
357                 )
358                 env.RegexpReplace("modb/go.mod", "modul", "module")
359                 env.Editor.SaveBufferWithoutActions(env.Ctx, "modb/go.mod")
360                 env.Await(
361                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
362                 )
363         })
364 }
365
366 func TestUseGoplsMod(t *testing.T) {
367         const multiModule = `
368 -- moda/a/go.mod --
369 module a.com
370
371 require b.com v1.2.3
372
373 -- moda/a/a.go --
374 package a
375
376 import (
377         "b.com/b"
378 )
379
380 func main() {
381         var x int
382         _ = b.Hello()
383 }
384 -- modb/go.mod --
385 module b.com
386
387 -- modb/b/b.go --
388 package b
389
390 func Hello() int {
391         var x int
392 }
393 -- gopls.mod --
394 module gopls-workspace
395
396 require (
397         a.com v0.0.0-goplsworkspace
398         b.com v1.2.3
399 )
400
401 replace a.com => $SANDBOX_WORKDIR/moda/a
402 `
403         withOptions(
404                 WithProxyFiles(workspaceModuleProxy),
405                 WithModes(Experimental),
406         ).run(t, multiModule, func(t *testing.T, env *Env) {
407                 env.OpenFile("moda/a/a.go")
408                 original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
409                 if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(original, want) {
410                         t.Errorf("expected %s, got %v", want, original)
411                 }
412                 workdir := env.Sandbox.Workdir.RootURI().SpanURI().Filename()
413                 env.WriteWorkspaceFile("gopls.mod", fmt.Sprintf(`module gopls-workspace
414
415 require (
416         a.com v0.0.0-goplsworkspace
417         b.com v0.0.0-goplsworkspace
418 )
419
420 replace a.com => %s/moda/a
421 replace b.com => %s/modb
422 `, workdir, workdir))
423                 env.Await(
424                         OnceMet(
425                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
426                                 env.DiagnosticAtRegexp("modb/b/b.go", "x"),
427                         ),
428                 )
429                 newLocation, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
430                 if want := "modb/b/b.go"; !strings.HasSuffix(newLocation, want) {
431                         t.Errorf("expected %s, got %v", want, newLocation)
432                 }
433         })
434 }
435
436 func TestNonWorkspaceFileCreation(t *testing.T) {
437         testenv.NeedsGo1Point(t, 13)
438
439         const files = `
440 -- go.mod --
441 module mod.com
442
443 -- x.go --
444 package x
445 `
446
447         const code = `
448 package foo
449 import "fmt"
450 var _ = fmt.Printf
451 `
452         run(t, files, func(t *testing.T, env *Env) {
453                 env.CreateBuffer("/tmp/foo.go", "")
454                 env.EditBuffer("/tmp/foo.go", fake.NewEdit(0, 0, 0, 0, code))
455                 env.GoToDefinition("/tmp/foo.go", env.RegexpSearch("/tmp/foo.go", `Printf`))
456         })
457 }
458
459 func TestMultiModuleV2(t *testing.T) {
460         const multiModule = `
461 -- moda/a/go.mod --
462 module a.com
463
464 require b.com/v2 v2.0.0
465 -- moda/a/a.go --
466 package a
467
468 import (
469         "b.com/v2/b"
470 )
471
472 func main() {
473         var x int
474         _ = b.Hi()
475 }
476 -- modb/go.mod --
477 module b.com
478
479 -- modb/b/b.go --
480 package b
481
482 func Hello() int {
483         var x int
484 }
485 -- modb/v2/go.mod --
486 module b.com/v2
487
488 -- modb/v2/b/b.go --
489 package b
490
491 func Hi() int {
492         var x int
493 }
494 -- modc/go.mod --
495 module gopkg.in/yaml.v1 // test gopkg.in versions
496 -- modc/main.go --
497 package main
498
499 func main() {
500         var x int
501 }
502 `
503         withOptions(
504                 WithModes(Experimental),
505         ).run(t, multiModule, func(t *testing.T, env *Env) {
506                 env.Await(
507                         env.DiagnosticAtRegexp("moda/a/a.go", "x"),
508                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
509                         env.DiagnosticAtRegexp("modb/v2/b/b.go", "x"),
510                         env.DiagnosticAtRegexp("modc/main.go", "x"),
511                 )
512         })
513 }