.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / internal / regtest / workspace / 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 workspace
6
7 import (
8         "fmt"
9         "io/ioutil"
10         "os"
11         "path/filepath"
12         "strings"
13         "testing"
14
15         . "golang.org/x/tools/gopls/internal/regtest"
16
17         "golang.org/x/tools/internal/lsp/fake"
18         "golang.org/x/tools/internal/lsp/protocol"
19         "golang.org/x/tools/internal/testenv"
20 )
21
22 func TestMain(m *testing.M) {
23         Main(m)
24 }
25
26 const workspaceProxy = `
27 -- example.com@v1.2.3/go.mod --
28 module example.com
29
30 go 1.12
31 -- example.com@v1.2.3/blah/blah.go --
32 package blah
33
34 func SaySomething() {
35         fmt.Println("something")
36 }
37 -- random.org@v1.2.3/go.mod --
38 module random.org
39
40 go 1.12
41 -- random.org@v1.2.3/bye/bye.go --
42 package bye
43
44 func Goodbye() {
45         println("Bye")
46 }
47 `
48
49 // TODO: Add a replace directive.
50 const workspaceModule = `
51 -- pkg/go.mod --
52 module mod.com
53
54 go 1.14
55
56 require (
57         example.com v1.2.3
58         random.org v1.2.3
59 )
60 -- pkg/go.sum --
61 example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c=
62 example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
63 random.org v1.2.3 h1:+JE2Fkp7gS0zsHXGEQJ7hraom3pNTlkxC4b2qPfA+/Q=
64 random.org v1.2.3/go.mod h1:E9KM6+bBX2g5ykHZ9H27w16sWo3QwgonyjM44Dnej3I=
65 -- pkg/main.go --
66 package main
67
68 import (
69         "example.com/blah"
70         "mod.com/inner"
71         "random.org/bye"
72 )
73
74 func main() {
75         blah.SaySomething()
76         inner.Hi()
77         bye.Goodbye()
78 }
79 -- pkg/main2.go --
80 package main
81
82 import "fmt"
83
84 func _() {
85         fmt.Print("%s")
86 }
87 -- pkg/inner/inner.go --
88 package inner
89
90 import "example.com/blah"
91
92 func Hi() {
93         blah.SaySomething()
94 }
95 -- goodbye/bye/bye.go --
96 package bye
97
98 func Bye() {}
99 -- goodbye/go.mod --
100 module random.org
101
102 go 1.12
103 `
104
105 // Confirm that find references returns all of the references in the module,
106 // regardless of what the workspace root is.
107 func TestReferences(t *testing.T) {
108         for _, tt := range []struct {
109                 name, rootPath string
110         }{
111                 {
112                         name:     "module root",
113                         rootPath: "pkg",
114                 },
115                 {
116                         name:     "subdirectory",
117                         rootPath: "pkg/inner",
118                 },
119         } {
120                 t.Run(tt.name, func(t *testing.T) {
121                         opts := []RunOption{ProxyFiles(workspaceProxy)}
122                         if tt.rootPath != "" {
123                                 opts = append(opts, WorkspaceFolders(tt.rootPath))
124                         }
125                         WithOptions(opts...).Run(t, workspaceModule, func(t *testing.T, env *Env) {
126                                 f := "pkg/inner/inner.go"
127                                 env.OpenFile(f)
128                                 locations := env.References(f, env.RegexpSearch(f, `SaySomething`))
129                                 want := 3
130                                 if got := len(locations); got != want {
131                                         t.Fatalf("expected %v locations, got %v", want, got)
132                                 }
133                         })
134                 })
135         }
136 }
137
138 // Make sure that analysis diagnostics are cleared for the whole package when
139 // the only opened file is closed. This test was inspired by the experience in
140 // VS Code, where clicking on a reference result triggers a
141 // textDocument/didOpen without a corresponding textDocument/didClose.
142 func TestClearAnalysisDiagnostics(t *testing.T) {
143         WithOptions(
144                 ProxyFiles(workspaceProxy),
145                 WorkspaceFolders("pkg/inner"),
146         ).Run(t, workspaceModule, func(t *testing.T, env *Env) {
147                 env.OpenFile("pkg/main.go")
148                 env.Await(
149                         env.DiagnosticAtRegexp("pkg/main2.go", "fmt.Print"),
150                 )
151                 env.CloseBuffer("pkg/main.go")
152                 env.Await(
153                         EmptyDiagnostics("pkg/main2.go"),
154                 )
155         })
156 }
157
158 // This test checks that gopls updates the set of files it watches when a
159 // replace target is added to the go.mod.
160 func TestWatchReplaceTargets(t *testing.T) {
161         WithOptions(
162                 ProxyFiles(workspaceProxy),
163                 WorkspaceFolders("pkg"),
164         ).Run(t, workspaceModule, func(t *testing.T, env *Env) {
165                 // Add a replace directive and expect the files that gopls is watching
166                 // to change.
167                 dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename()
168                 goModWithReplace := fmt.Sprintf(`%s
169 replace random.org => %s
170 `, env.ReadWorkspaceFile("pkg/go.mod"), dir)
171                 env.WriteWorkspaceFile("pkg/go.mod", goModWithReplace)
172                 env.Await(
173                         env.DoneWithChangeWatchedFiles(),
174                         UnregistrationMatching("didChangeWatchedFiles"),
175                         RegistrationMatching("didChangeWatchedFiles"),
176                 )
177         })
178 }
179
180 const workspaceModuleProxy = `
181 -- example.com@v1.2.3/go.mod --
182 module example.com
183
184 go 1.12
185 -- example.com@v1.2.3/blah/blah.go --
186 package blah
187
188 func SaySomething() {
189         fmt.Println("something")
190 }
191 -- b.com@v1.2.3/go.mod --
192 module b.com
193
194 go 1.12
195 -- b.com@v1.2.3/b/b.go --
196 package b
197
198 func Hello() {}
199 `
200
201 func TestAutomaticWorkspaceModule_Interdependent(t *testing.T) {
202         const multiModule = `
203 -- moda/a/go.mod --
204 module a.com
205
206 require b.com v1.2.3
207 -- moda/a/go.sum --
208 b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI=
209 b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8=
210 -- moda/a/a.go --
211 package a
212
213 import (
214         "b.com/b"
215 )
216
217 func main() {
218         var x int
219         _ = b.Hello()
220 }
221 -- modb/go.mod --
222 module b.com
223
224 -- modb/b/b.go --
225 package b
226
227 func Hello() int {
228         var x int
229 }
230 `
231         WithOptions(
232                 ProxyFiles(workspaceModuleProxy),
233                 Modes(Experimental),
234         ).Run(t, multiModule, func(t *testing.T, env *Env) {
235                 env.Await(
236                         env.DiagnosticAtRegexp("moda/a/a.go", "x"),
237                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
238                         env.NoDiagnosticAtRegexp("moda/a/a.go", `"b.com/b"`),
239                 )
240         })
241 }
242
243 // This change tests that the version of the module used changes after it has
244 // been deleted from the workspace.
245 func TestDeleteModule_Interdependent(t *testing.T) {
246         const multiModule = `
247 -- moda/a/go.mod --
248 module a.com
249
250 require b.com v1.2.3
251 -- moda/a/go.sum --
252 b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI=
253 b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8=
254 -- moda/a/a.go --
255 package a
256
257 import (
258         "b.com/b"
259 )
260
261 func main() {
262         var x int
263         _ = b.Hello()
264 }
265 -- modb/go.mod --
266 module b.com
267
268 -- modb/b/b.go --
269 package b
270
271 func Hello() int {
272         var x int
273 }
274 `
275         WithOptions(
276                 ProxyFiles(workspaceModuleProxy),
277                 Modes(Experimental),
278         ).Run(t, multiModule, func(t *testing.T, env *Env) {
279                 env.OpenFile("moda/a/a.go")
280
281                 original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
282                 if want := "modb/b/b.go"; !strings.HasSuffix(original, want) {
283                         t.Errorf("expected %s, got %v", want, original)
284                 }
285                 env.CloseBuffer(original)
286                 env.RemoveWorkspaceFile("modb/b/b.go")
287                 env.RemoveWorkspaceFile("modb/go.mod")
288                 env.Await(
289                         env.DoneWithChangeWatchedFiles(),
290                 )
291
292                 d := protocol.PublishDiagnosticsParams{}
293                 env.Await(
294                         OnceMet(
295                                 env.DiagnosticAtRegexpWithMessage("moda/a/go.mod", "require b.com v1.2.3", "b.com@v1.2.3 has not been downloaded"),
296                                 ReadDiagnostics("moda/a/go.mod", &d),
297                         ),
298                 )
299                 env.ApplyQuickFixes("moda/a/go.mod", d.Diagnostics)
300                 got, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
301                 if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(got, want) {
302                         t.Errorf("expected %s, got %v", want, got)
303                 }
304         })
305 }
306
307 // Tests that the version of the module used changes after it has been added
308 // to the workspace.
309 func TestCreateModule_Interdependent(t *testing.T) {
310         const multiModule = `
311 -- moda/a/go.mod --
312 module a.com
313
314 require b.com v1.2.3
315 -- moda/a/go.sum --
316 b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI=
317 b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8=
318 -- moda/a/a.go --
319 package a
320
321 import (
322         "b.com/b"
323 )
324
325 func main() {
326         var x int
327         _ = b.Hello()
328 }
329 `
330         WithOptions(
331                 Modes(Experimental),
332                 ProxyFiles(workspaceModuleProxy),
333         ).Run(t, multiModule, func(t *testing.T, env *Env) {
334                 env.OpenFile("moda/a/a.go")
335                 original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
336                 if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(original, want) {
337                         t.Errorf("expected %s, got %v", want, original)
338                 }
339                 env.CloseBuffer(original)
340                 env.WriteWorkspaceFiles(map[string]string{
341                         "modb/go.mod": "module b.com",
342                         "modb/b/b.go": `package b
343
344 func Hello() int {
345         var x int
346 }
347 `,
348                 })
349                 env.Await(
350                         OnceMet(
351                                 env.DoneWithChangeWatchedFiles(),
352                                 env.DiagnosticAtRegexp("modb/b/b.go", "x"),
353                         ),
354                 )
355                 got, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
356                 if want := "modb/b/b.go"; !strings.HasSuffix(got, want) {
357                         t.Errorf("expected %s, got %v", want, original)
358                 }
359         })
360 }
361
362 // This test confirms that a gopls workspace can recover from initialization
363 // with one invalid module.
364 func TestOneBrokenModule(t *testing.T) {
365         const multiModule = `
366 -- moda/a/go.mod --
367 module a.com
368
369 require b.com v1.2.3
370
371 -- moda/a/a.go --
372 package a
373
374 import (
375         "b.com/b"
376 )
377
378 func main() {
379         var x int
380         _ = b.Hello()
381 }
382 -- modb/go.mod --
383 modul b.com // typo here
384
385 -- modb/b/b.go --
386 package b
387
388 func Hello() int {
389         var x int
390 }
391 `
392         WithOptions(
393                 ProxyFiles(workspaceModuleProxy),
394                 Modes(Experimental),
395         ).Run(t, multiModule, func(t *testing.T, env *Env) {
396                 env.OpenFile("modb/go.mod")
397                 env.Await(
398                         OnceMet(
399                                 env.DoneWithOpen(),
400                                 DiagnosticAt("modb/go.mod", 0, 0),
401                         ),
402                 )
403                 env.RegexpReplace("modb/go.mod", "modul", "module")
404                 env.SaveBufferWithoutActions("modb/go.mod")
405                 env.Await(
406                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
407                 )
408         })
409 }
410
411 func TestUseGoplsMod(t *testing.T) {
412         // This test validates certain functionality related to using a gopls.mod
413         // file to specify workspace modules.
414         testenv.NeedsGo1Point(t, 14)
415         const multiModule = `
416 -- moda/a/go.mod --
417 module a.com
418
419 require b.com v1.2.3
420 -- moda/a/go.sum --
421 b.com v1.2.3 h1:tXrlXP0rnjRpKNmkbLYoWBdq0ikb3C3bKK9//moAWBI=
422 b.com v1.2.3/go.mod h1:D+J7pfFBZK5vdIdZEFquR586vKKIkqG7Qjw9AxG5BQ8=
423 -- moda/a/a.go --
424 package a
425
426 import (
427         "b.com/b"
428 )
429
430 func main() {
431         var x int
432         _ = b.Hello()
433 }
434 -- modb/go.mod --
435 module b.com
436
437 require example.com v1.2.3
438 -- modb/go.sum --
439 example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c=
440 example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo=
441 -- modb/b/b.go --
442 package b
443
444 func Hello() int {
445         var x int
446 }
447 -- gopls.mod --
448 module gopls-workspace
449
450 require (
451         a.com v0.0.0-goplsworkspace
452         b.com v1.2.3
453 )
454
455 replace a.com => $SANDBOX_WORKDIR/moda/a
456 `
457         WithOptions(
458                 ProxyFiles(workspaceModuleProxy),
459                 Modes(Experimental),
460         ).Run(t, multiModule, func(t *testing.T, env *Env) {
461                 // Initially, the gopls.mod should cause only the a.com module to be
462                 // loaded. Validate this by jumping to a definition in b.com and ensuring
463                 // that we go to the module cache.
464                 env.OpenFile("moda/a/a.go")
465                 env.Await(env.DoneWithOpen())
466
467                 // To verify which modules are loaded, we'll jump to the definition of
468                 // b.Hello.
469                 checkHelloLocation := func(want string) error {
470                         location, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello"))
471                         if !strings.HasSuffix(location, want) {
472                                 return fmt.Errorf("expected %s, got %v", want, location)
473                         }
474                         return nil
475                 }
476
477                 // Initially this should be in the module cache, as b.com is not replaced.
478                 if err := checkHelloLocation("b.com@v1.2.3/b/b.go"); err != nil {
479                         t.Fatal(err)
480                 }
481
482                 // Now, modify the gopls.mod file on disk to activate the b.com module in
483                 // the workspace.
484                 workdir := env.Sandbox.Workdir.RootURI().SpanURI().Filename()
485                 env.WriteWorkspaceFile("gopls.mod", fmt.Sprintf(`module gopls-workspace
486
487 require (
488         a.com v1.9999999.0-goplsworkspace
489         b.com v1.9999999.0-goplsworkspace
490 )
491
492 replace a.com => %s/moda/a
493 replace b.com => %s/modb
494 `, workdir, workdir))
495                 env.Await(env.DoneWithChangeWatchedFiles())
496                 // Check that go.mod diagnostics picked up the newly active mod file.
497                 // The local version of modb has an extra dependency we need to download.
498                 env.OpenFile("modb/go.mod")
499                 env.Await(env.DoneWithOpen())
500
501                 var d protocol.PublishDiagnosticsParams
502                 env.Await(
503                         OnceMet(
504                                 env.DiagnosticAtRegexpWithMessage("modb/go.mod", `require example.com v1.2.3`, "has not been downloaded"),
505                                 ReadDiagnostics("modb/go.mod", &d),
506                         ),
507                 )
508                 env.ApplyQuickFixes("modb/go.mod", d.Diagnostics)
509                 env.Await(env.DiagnosticAtRegexp("modb/b/b.go", "x"))
510                 // Jumping to definition should now go to b.com in the workspace.
511                 if err := checkHelloLocation("modb/b/b.go"); err != nil {
512                         t.Fatal(err)
513                 }
514
515                 // Now, let's modify the gopls.mod *overlay* (not on disk), and verify that
516                 // this change is only picked up once it is saved.
517                 env.OpenFile("gopls.mod")
518                 env.Await(env.DoneWithOpen())
519                 env.SetBufferContent("gopls.mod", fmt.Sprintf(`module gopls-workspace
520
521 require (
522         a.com v0.0.0-goplsworkspace
523 )
524
525 replace a.com => %s/moda/a
526 `, workdir))
527
528                 // Editing the gopls.mod removes modb from the workspace modules, and so
529                 // should clear outstanding diagnostics...
530                 env.Await(OnceMet(
531                         env.DoneWithChange(),
532                         EmptyDiagnostics("modb/go.mod"),
533                 ))
534                 // ...but does not yet cause a workspace reload, so we should still jump to modb.
535                 if err := checkHelloLocation("modb/b/b.go"); err != nil {
536                         t.Fatal(err)
537                 }
538                 // Saving should reload the workspace.
539                 env.SaveBufferWithoutActions("gopls.mod")
540                 if err := checkHelloLocation("b.com@v1.2.3/b/b.go"); err != nil {
541                         t.Fatal(err)
542                 }
543         })
544 }
545
546 func TestNonWorkspaceFileCreation(t *testing.T) {
547         testenv.NeedsGo1Point(t, 13)
548
549         const files = `
550 -- go.mod --
551 module mod.com
552
553 go 1.12
554 -- x.go --
555 package x
556 `
557
558         const code = `
559 package foo
560 import "fmt"
561 var _ = fmt.Printf
562 `
563         Run(t, files, func(t *testing.T, env *Env) {
564                 env.CreateBuffer("/tmp/foo.go", "")
565                 env.EditBuffer("/tmp/foo.go", fake.NewEdit(0, 0, 0, 0, code))
566                 env.GoToDefinition("/tmp/foo.go", env.RegexpSearch("/tmp/foo.go", `Printf`))
567         })
568 }
569
570 func TestMultiModuleV2(t *testing.T) {
571         const multiModule = `
572 -- moda/a/go.mod --
573 module a.com
574
575 require b.com/v2 v2.1.9
576 -- moda/a/a.go --
577 package a
578
579 import (
580         "b.com/v2/b"
581 )
582
583 func main() {
584         var x int
585         _ = b.Hi()
586 }
587 -- modb/go.mod --
588 module b.com
589
590 -- modb/b/b.go --
591 package b
592
593 func Hello() int {
594         var x int
595 }
596 -- modb/v2/go.mod --
597 module b.com/v2
598
599 -- modb/v2/b/b.go --
600 package b
601
602 func Hi() int {
603         var x int
604 }
605 -- modc/go.mod --
606 module gopkg.in/yaml.v1 // test gopkg.in versions
607 -- modc/main.go --
608 package main
609
610 func main() {
611         var x int
612 }
613 `
614         WithOptions(
615                 Modes(Experimental),
616         ).Run(t, multiModule, func(t *testing.T, env *Env) {
617                 env.Await(
618                         env.DiagnosticAtRegexp("moda/a/a.go", "x"),
619                         env.DiagnosticAtRegexp("modb/b/b.go", "x"),
620                         env.DiagnosticAtRegexp("modb/v2/b/b.go", "x"),
621                         env.DiagnosticAtRegexp("modc/main.go", "x"),
622                 )
623         })
624 }
625
626 func TestWorkspaceDirAccess(t *testing.T) {
627         const multiModule = `
628 -- moda/a/go.mod --
629 module a.com
630
631 -- moda/a/a.go --
632 package main
633
634 func main() {
635         fmt.Println("Hello")
636 }
637 -- modb/go.mod --
638 module b.com
639 -- modb/b/b.go --
640 package main
641
642 func main() {
643         fmt.Println("World")
644 }
645 `
646         WithOptions(
647                 Modes(Experimental),
648                 SendPID(),
649         ).Run(t, multiModule, func(t *testing.T, env *Env) {
650                 pid := os.Getpid()
651                 // Don't factor this out of Server.addFolders. vscode-go expects this
652                 // directory.
653                 modPath := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.workspace", pid), "go.mod")
654                 gotb, err := ioutil.ReadFile(modPath)
655                 if err != nil {
656                         t.Fatalf("reading expected workspace modfile: %v", err)
657                 }
658                 got := string(gotb)
659                 for _, want := range []string{"a.com v1.9999999.0-goplsworkspace", "b.com v1.9999999.0-goplsworkspace"} {
660                         if !strings.Contains(got, want) {
661                                 // want before got here, since the go.mod is multi-line
662                                 t.Fatalf("workspace go.mod missing %q. got:\n%s", want, got)
663                         }
664                 }
665                 workdir := env.Sandbox.Workdir.RootURI().SpanURI().Filename()
666                 env.WriteWorkspaceFile("gopls.mod", fmt.Sprintf(`
667                                 module gopls-workspace
668
669                                 require (
670                                         a.com v1.9999999.0-goplsworkspace
671                                 )
672
673                                 replace a.com => %s/moda/a
674                                 `, workdir))
675                 env.Await(env.DoneWithChangeWatchedFiles())
676                 gotb, err = ioutil.ReadFile(modPath)
677                 if err != nil {
678                         t.Fatalf("reading expected workspace modfile: %v", err)
679                 }
680                 got = string(gotb)
681                 want := "b.com v1.9999999.0-goplsworkspace"
682                 if strings.Contains(got, want) {
683                         t.Fatalf("workspace go.mod contains unexpected %q. got:\n%s", want, got)
684                 }
685         })
686 }
687
688 func TestDirectoryFiltersLoads(t *testing.T) {
689         // exclude, and its error, should be excluded from the workspace.
690         const files = `
691 -- go.mod --
692 module example.com
693
694 go 1.12
695 -- exclude/exclude.go --
696 package exclude
697
698 const _ = Nonexistant
699 `
700         cfg := EditorConfig{
701                 DirectoryFilters: []string{"-exclude"},
702         }
703         WithOptions(cfg).Run(t, files, func(t *testing.T, env *Env) {
704                 env.Await(NoDiagnostics("exclude/x.go"))
705         })
706 }
707
708 func TestDirectoryFiltersTransitiveDep(t *testing.T) {
709         // Even though exclude is excluded from the workspace, it should
710         // still be importable as a non-workspace package.
711         const files = `
712 -- go.mod --
713 module example.com
714
715 go 1.12
716 -- include/include.go --
717 package include
718 import "example.com/exclude"
719
720 const _ = exclude.X
721 -- exclude/exclude.go --
722 package exclude
723
724 const _ = Nonexistant // should be ignored, since this is a non-workspace package
725 const X = 1
726 `
727
728         cfg := EditorConfig{
729                 DirectoryFilters: []string{"-exclude"},
730         }
731         WithOptions(cfg).Run(t, files, func(t *testing.T, env *Env) {
732                 env.Await(
733                         NoDiagnostics("exclude/exclude.go"), // filtered out
734                         NoDiagnostics("include/include.go"), // successfully builds
735                 )
736         })
737 }
738
739 func TestDirectoryFiltersWorkspaceModules(t *testing.T) {
740         // Define a module include.com which should be in the workspace, plus a
741         // module exclude.com which should be excluded and therefore come from
742         // the proxy.
743         const files = `
744 -- include/go.mod --
745 module include.com
746
747 go 1.12
748
749 require exclude.com v1.0.0
750
751 -- include/go.sum --
752 exclude.com v1.0.0 h1:Q5QSfDXY5qyNCBeUiWovUGqcLCRZKoTs9XdBeVz+w1I=
753 exclude.com v1.0.0/go.mod h1:hFox2uDlNB2s2Jfd9tHlQVfgqUiLVTmh6ZKat4cvnj4=
754
755 -- include/include.go --
756 package include
757
758 import "exclude.com"
759
760 var _ = exclude.X // satisfied only by the workspace version
761 -- exclude/go.mod --
762 module exclude.com
763
764 go 1.12
765 -- exclude/exclude.go --
766 package exclude
767
768 const X = 1
769 `
770         const proxy = `
771 -- exclude.com@v1.0.0/go.mod --
772 module exclude.com
773
774 go 1.12
775 -- exclude.com@v1.0.0/exclude.go --
776 package exclude
777 `
778         cfg := EditorConfig{
779                 DirectoryFilters: []string{"-exclude"},
780         }
781         WithOptions(cfg, Modes(Experimental), ProxyFiles(proxy)).Run(t, files, func(t *testing.T, env *Env) {
782                 env.Await(env.DiagnosticAtRegexp("include/include.go", `exclude.(X)`))
783         })
784 }
785
786 // Confirm that a fix for a tidy module will correct all modules in the
787 // workspace.
788 func TestMultiModule_OneBrokenModule(t *testing.T) {
789         testenv.NeedsGo1Point(t, 15)
790
791         const mod = `
792 -- a/go.mod --
793 module a.com
794
795 go 1.12
796 -- a/main.go --
797 package main
798 -- b/go.mod --
799 module b.com
800
801 go 1.12
802
803 require (
804         example.com v1.2.3
805 )
806 -- b/go.sum --
807 -- b/main.go --
808 package b
809
810 import "example.com/blah"
811
812 func main() {
813         blah.Hello()
814 }
815 `
816         WithOptions(
817                 ProxyFiles(workspaceProxy),
818                 Modes(Experimental),
819         ).Run(t, mod, func(t *testing.T, env *Env) {
820                 params := &protocol.PublishDiagnosticsParams{}
821                 env.OpenFile("b/go.mod")
822                 env.Await(
823                         OnceMet(
824                                 env.GoSumDiagnostic("b/go.mod", `example.com v1.2.3`),
825                                 ReadDiagnostics("b/go.mod", params),
826                         ),
827                 )
828                 for _, d := range params.Diagnostics {
829                         if !strings.Contains(d.Message, "go.sum is out of sync") {
830                                 continue
831                         }
832                         actions := env.GetQuickFixes("b/go.mod", []protocol.Diagnostic{d})
833                         if len(actions) != 2 {
834                                 t.Fatalf("expected 2 code actions, got %v", len(actions))
835                         }
836                         env.ApplyQuickFixes("b/go.mod", []protocol.Diagnostic{d})
837                 }
838                 env.Await(
839                         EmptyDiagnostics("b/go.mod"),
840                 )
841         })
842 }