.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / internal / regtest / diagnostics / diagnostics_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 diagnostics
6
7 import (
8         "context"
9         "fmt"
10         "log"
11         "testing"
12
13         . "golang.org/x/tools/gopls/internal/regtest"
14
15         "golang.org/x/tools/internal/lsp"
16         "golang.org/x/tools/internal/lsp/fake"
17         "golang.org/x/tools/internal/lsp/protocol"
18         "golang.org/x/tools/internal/testenv"
19 )
20
21 func TestMain(m *testing.M) {
22         Main(m)
23 }
24
25 // Use mod.com for all go.mod files due to golang/go#35230.
26 const exampleProgram = `
27 -- go.mod --
28 module mod.com
29
30 go 1.12
31 -- main.go --
32 package main
33
34 import "fmt"
35
36 func main() {
37         fmt.Println("Hello World.")
38 }`
39
40 func TestDiagnosticErrorInEditedFile(t *testing.T) {
41         // This test is very basic: start with a clean Go program, make an error, and
42         // get a diagnostic for that error. However, it also demonstrates how to
43         // combine Expectations to await more complex state in the editor.
44         Run(t, exampleProgram, func(t *testing.T, env *Env) {
45                 // Deleting the 'n' at the end of Println should generate a single error
46                 // diagnostic.
47                 env.OpenFile("main.go")
48                 env.RegexpReplace("main.go", "Printl(n)", "")
49                 env.Await(
50                         // Once we have gotten diagnostics for the change above, we should
51                         // satisfy the DiagnosticAtRegexp assertion.
52                         OnceMet(
53                                 env.DoneWithChange(),
54                                 env.DiagnosticAtRegexp("main.go", "Printl"),
55                         ),
56                         // Assert that this test has sent no error logs to the client. This is not
57                         // strictly necessary for testing this regression, but is included here
58                         // as an example of using the NoErrorLogs() expectation. Feel free to
59                         // delete.
60                         NoErrorLogs(),
61                 )
62         })
63 }
64
65 func TestMissingImportDiagsClearOnFirstFile(t *testing.T) {
66         const onlyMod = `
67 -- go.mod --
68 module mod.com
69
70 go 1.12
71 `
72         Run(t, onlyMod, func(t *testing.T, env *Env) {
73                 env.CreateBuffer("main.go", `package main
74
75 func m() {
76         log.Println()
77 }
78 `)
79                 env.Await(
80                         env.DiagnosticAtRegexp("main.go", "log"),
81                 )
82                 env.SaveBuffer("main.go")
83                 env.Await(
84                         EmptyDiagnostics("main.go"),
85                 )
86         })
87 }
88
89 func TestDiagnosticErrorInNewFile(t *testing.T) {
90         const brokenFile = `package main
91
92 const Foo = "abc
93 `
94         Run(t, brokenFile, func(t *testing.T, env *Env) {
95                 env.CreateBuffer("broken.go", brokenFile)
96                 env.Await(env.DiagnosticAtRegexp("broken.go", "\"abc"))
97         })
98 }
99
100 // badPackage contains a duplicate definition of the 'a' const.
101 const badPackage = `
102 -- go.mod --
103 module mod.com
104
105 go 1.12
106 -- a.go --
107 package consts
108
109 const a = 1
110 -- b.go --
111 package consts
112
113 const a = 2
114 `
115
116 func TestDiagnosticClearingOnEdit(t *testing.T) {
117         Run(t, badPackage, func(t *testing.T, env *Env) {
118                 env.OpenFile("b.go")
119                 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
120
121                 // Fix the error by editing the const name in b.go to `b`.
122                 env.RegexpReplace("b.go", "(a) = 2", "b")
123                 env.Await(
124                         EmptyDiagnostics("a.go"),
125                         EmptyDiagnostics("b.go"),
126                 )
127         })
128 }
129
130 func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) {
131         Run(t, badPackage, func(t *testing.T, env *Env) {
132                 env.OpenFile("a.go")
133                 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
134                 env.RemoveWorkspaceFile("b.go")
135
136                 env.Await(EmptyDiagnostics("a.go"), EmptyDiagnostics("b.go"))
137         })
138 }
139
140 func TestDiagnosticClearingOnClose(t *testing.T) {
141         Run(t, badPackage, func(t *testing.T, env *Env) {
142                 env.CreateBuffer("c.go", `package consts
143
144 const a = 3`)
145                 env.Await(
146                         env.DiagnosticAtRegexp("a.go", "a = 1"),
147                         env.DiagnosticAtRegexp("b.go", "a = 2"),
148                         env.DiagnosticAtRegexp("c.go", "a = 3"))
149                 env.CloseBuffer("c.go")
150                 env.Await(
151                         env.DiagnosticAtRegexp("a.go", "a = 1"),
152                         env.DiagnosticAtRegexp("b.go", "a = 2"),
153                         EmptyDiagnostics("c.go"))
154         })
155 }
156
157 // Tests golang/go#37978.
158 func TestIssue37978(t *testing.T) {
159         Run(t, exampleProgram, func(t *testing.T, env *Env) {
160                 // Create a new workspace-level directory and empty file.
161                 env.CreateBuffer("c/c.go", "")
162
163                 // Write the file contents with a missing import.
164                 env.EditBuffer("c/c.go", fake.Edit{
165                         Text: `package c
166
167 const a = http.MethodGet
168 `,
169                 })
170                 env.Await(
171                         env.DiagnosticAtRegexp("c/c.go", "http.MethodGet"),
172                 )
173                 // Save file, which will organize imports, adding the expected import.
174                 // Expect the diagnostics to clear.
175                 env.SaveBuffer("c/c.go")
176                 env.Await(
177                         EmptyDiagnostics("c/c.go"),
178                 )
179         })
180 }
181
182 // Tests golang/go#38878: good a.go, bad a_test.go, remove a_test.go but its errors remain
183 // If the file is open in the editor, this is working as intended
184 // If the file is not open in the editor, the errors go away
185 const test38878 = `
186 -- go.mod --
187 module foo
188
189 go 1.12
190 -- a.go --
191 package x
192
193 // import "fmt"
194
195 func f() {}
196
197 -- a_test.go --
198 package x
199
200 import "testing"
201
202 func TestA(t *testing.T) {
203         f(3)
204 }
205 `
206
207 // Tests golang/go#38878: deleting a test file should clear its errors, and
208 // not break the workspace.
209 func TestDeleteTestVariant(t *testing.T) {
210         Run(t, test38878, func(t *testing.T, env *Env) {
211                 env.Await(env.DiagnosticAtRegexp("a_test.go", `f\((3)\)`))
212                 env.RemoveWorkspaceFile("a_test.go")
213                 env.Await(EmptyDiagnostics("a_test.go"))
214
215                 // Make sure the test variant has been removed from the workspace by
216                 // triggering a metadata load.
217                 env.OpenFile("a.go")
218                 env.RegexpReplace("a.go", `// import`, "import")
219                 env.Await(env.DiagnosticAtRegexp("a.go", `"fmt"`))
220         })
221 }
222
223 // Tests golang/go#38878: deleting a test file on disk while it's still open
224 // should not clear its errors.
225 func TestDeleteTestVariant_DiskOnly(t *testing.T) {
226         log.SetFlags(log.Lshortfile)
227         Run(t, test38878, func(t *testing.T, env *Env) {
228                 env.OpenFile("a_test.go")
229                 env.Await(DiagnosticAt("a_test.go", 5, 3))
230                 env.Sandbox.Workdir.RemoveFile(context.Background(), "a_test.go")
231                 env.Await(OnceMet(
232                         env.DoneWithChangeWatchedFiles(),
233                         DiagnosticAt("a_test.go", 5, 3)))
234         })
235 }
236
237 // TestNoMod confirms that gopls continues to work when a user adds a go.mod
238 // file to their workspace.
239 func TestNoMod(t *testing.T) {
240         const noMod = `
241 -- main.go --
242 package main
243
244 import "mod.com/bob"
245
246 func main() {
247         bob.Hello()
248 }
249 -- bob/bob.go --
250 package bob
251
252 func Hello() {
253         var x int
254 }
255 `
256
257         t.Run("manual", func(t *testing.T) {
258                 Run(t, noMod, func(t *testing.T, env *Env) {
259                         env.Await(
260                                 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
261                         )
262                         env.CreateBuffer("go.mod", `module mod.com
263
264         go 1.12
265 `)
266                         env.SaveBuffer("go.mod")
267                         env.Await(
268                                 EmptyDiagnostics("main.go"),
269                         )
270                         var d protocol.PublishDiagnosticsParams
271                         env.Await(
272                                 OnceMet(
273                                         env.DiagnosticAtRegexp("bob/bob.go", "x"),
274                                         ReadDiagnostics("bob/bob.go", &d),
275                                 ),
276                         )
277                         if len(d.Diagnostics) != 1 {
278                                 t.Fatalf("expected 1 diagnostic, got %v", len(d.Diagnostics))
279                         }
280                 })
281         })
282         t.Run("initialized", func(t *testing.T) {
283                 Run(t, noMod, func(t *testing.T, env *Env) {
284                         env.Await(
285                                 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
286                         )
287                         env.RunGoCommand("mod", "init", "mod.com")
288                         env.Await(
289                                 EmptyDiagnostics("main.go"),
290                                 env.DiagnosticAtRegexp("bob/bob.go", "x"),
291                         )
292                 })
293         })
294
295         t.Run("without workspace module", func(t *testing.T) {
296                 WithOptions(
297                         Modes(Singleton),
298                 ).Run(t, noMod, func(t *testing.T, env *Env) {
299                         env.Await(
300                                 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
301                         )
302                         if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}); err != nil {
303                                 t.Fatal(err)
304                         }
305                         env.Await(
306                                 EmptyDiagnostics("main.go"),
307                                 env.DiagnosticAtRegexp("bob/bob.go", "x"),
308                         )
309                 })
310         })
311 }
312
313 // Tests golang/go#38267.
314 func TestIssue38267(t *testing.T) {
315         const testPackage = `
316 -- go.mod --
317 module mod.com
318
319 go 1.12
320 -- lib.go --
321 package lib
322
323 func Hello(x string) {
324         _ = x
325 }
326 -- lib_test.go --
327 package lib
328
329 import "testing"
330
331 type testStruct struct{
332         name string
333 }
334
335 func TestHello(t *testing.T) {
336         testStructs := []*testStruct{
337                 &testStruct{"hello"},
338                 &testStruct{"goodbye"},
339         }
340         for y := range testStructs {
341                 _ = y
342         }
343 }
344 `
345
346         Run(t, testPackage, func(t *testing.T, env *Env) {
347                 env.OpenFile("lib_test.go")
348                 env.Await(
349                         DiagnosticAt("lib_test.go", 10, 2),
350                         DiagnosticAt("lib_test.go", 11, 2),
351                 )
352                 env.OpenFile("lib.go")
353                 env.RegexpReplace("lib.go", "_ = x", "var y int")
354                 env.Await(
355                         env.DiagnosticAtRegexp("lib.go", "y int"),
356                         EmptyDiagnostics("lib_test.go"),
357                 )
358         })
359 }
360
361 // Tests golang/go#38328.
362 func TestPackageChange_Issue38328(t *testing.T) {
363         const packageChange = `
364 -- go.mod --
365 module fake
366
367 go 1.12
368 -- a.go --
369 package foo
370 func main() {}
371 `
372         Run(t, packageChange, func(t *testing.T, env *Env) {
373                 env.OpenFile("a.go")
374                 env.RegexpReplace("a.go", "foo", "foox")
375                 env.Await(
376                         // When the bug reported in #38328 was present, we didn't get erroneous
377                         // file diagnostics until after the didChange message generated by the
378                         // package renaming was fully processed. Therefore, in order for this
379                         // test to actually exercise the bug, we must wait until that work has
380                         // completed.
381                         OnceMet(
382                                 env.DoneWithChange(),
383                                 NoDiagnostics("a.go"),
384                         ),
385                 )
386         })
387 }
388
389 const testPackageWithRequire = `
390 -- go.mod --
391 module mod.com
392
393 go 1.12
394
395 require foo.test v1.2.3
396 -- go.sum --
397 foo.test v1.2.3 h1:TMA+lyd1ck0TqjSFpNe4T6cf/K6TYkoHwOOcMBMjaEw=
398 foo.test v1.2.3/go.mod h1:Ij3kyLIe5lzjycjh13NL8I2gX0quZuTdW0MnmlwGBL4=
399 -- print.go --
400 package lib
401
402 import (
403         "fmt"
404
405         "foo.test/bar"
406 )
407
408 func PrintAnswer() {
409         fmt.Printf("answer: %s", bar.Answer)
410 }
411 `
412
413 const testPackageWithRequireProxy = `
414 -- foo.test@v1.2.3/go.mod --
415 module foo.test
416
417 go 1.12
418 -- foo.test@v1.2.3/bar/const.go --
419 package bar
420
421 const Answer = 42
422 `
423
424 func TestResolveDiagnosticWithDownload(t *testing.T) {
425         WithOptions(
426                 ProxyFiles(testPackageWithRequireProxy),
427         ).Run(t, testPackageWithRequire, func(t *testing.T, env *Env) {
428                 env.OpenFile("print.go")
429                 // Check that gopackages correctly loaded this dependency. We should get a
430                 // diagnostic for the wrong formatting type.
431                 // TODO: we should be able to easily also match the diagnostic message.
432                 env.Await(env.DiagnosticAtRegexp("print.go", "fmt.Printf"))
433         })
434 }
435
436 func TestMissingDependency(t *testing.T) {
437         Run(t, testPackageWithRequire, func(t *testing.T, env *Env) {
438                 env.OpenFile("print.go")
439                 env.Await(LogMatching(protocol.Error, "initial workspace load failed", 1))
440         })
441 }
442
443 // Tests golang/go#36951.
444 func TestAdHocPackages_Issue36951(t *testing.T) {
445         const adHoc = `
446 -- b/b.go --
447 package b
448
449 func Hello() {
450         var x int
451 }
452 `
453         Run(t, adHoc, func(t *testing.T, env *Env) {
454                 env.OpenFile("b/b.go")
455                 env.Await(env.DiagnosticAtRegexp("b/b.go", "x"))
456         })
457 }
458
459 // Tests golang/go#37984: GOPATH should be read from the go command.
460 func TestNoGOPATH_Issue37984(t *testing.T) {
461         const files = `
462 -- main.go --
463 package main
464
465 func _() {
466         fmt.Println("Hello World")
467 }
468 `
469         WithOptions(
470                 EditorConfig{
471                         Env: map[string]string{
472                                 "GOPATH":      "",
473                                 "GO111MODULE": "off",
474                         },
475                 }).Run(t, files, func(t *testing.T, env *Env) {
476                 env.OpenFile("main.go")
477                 env.Await(env.DiagnosticAtRegexp("main.go", "fmt"))
478                 env.SaveBuffer("main.go")
479                 env.Await(EmptyDiagnostics("main.go"))
480         })
481 }
482
483 // Tests golang/go#38669.
484 func TestEqualInEnv_Issue38669(t *testing.T) {
485         const files = `
486 -- go.mod --
487 module mod.com
488
489 go 1.12
490 -- main.go --
491 package main
492
493 var _ = x.X
494 -- x/x.go --
495 package x
496
497 var X = 0
498 `
499         editorConfig := EditorConfig{Env: map[string]string{"GOFLAGS": "-tags=foo"}}
500         WithOptions(editorConfig).Run(t, files, func(t *testing.T, env *Env) {
501                 env.OpenFile("main.go")
502                 env.OrganizeImports("main.go")
503                 env.Await(EmptyDiagnostics("main.go"))
504         })
505 }
506
507 // Tests golang/go#38467.
508 func TestNoSuggestedFixesForGeneratedFiles_Issue38467(t *testing.T) {
509         const generated = `
510 -- go.mod --
511 module mod.com
512
513 go 1.12
514 -- main.go --
515 package main
516
517 // Code generated by generator.go. DO NOT EDIT.
518
519 func _() {
520         for i, _ := range []string{} {
521                 _ = i
522         }
523 }
524 `
525         Run(t, generated, func(t *testing.T, env *Env) {
526                 env.OpenFile("main.go")
527                 var d protocol.PublishDiagnosticsParams
528                 env.Await(
529                         OnceMet(
530                                 DiagnosticAt("main.go", 5, 8),
531                                 ReadDiagnostics("main.go", &d),
532                         ),
533                 )
534                 if fixes := env.GetQuickFixes("main.go", d.Diagnostics); len(fixes) != 0 {
535                         t.Errorf("got quick fixes %v, wanted none", fixes)
536                 }
537         })
538 }
539
540 // Expect a module/GOPATH error if there is an error in the file at startup.
541 // Tests golang/go#37279.
542 func TestShowCriticalError_Issue37279(t *testing.T) {
543         const noModule = `
544 -- a.go --
545 package foo
546
547 import "mod.com/hello"
548
549 func f() {
550         hello.Goodbye()
551 }
552 `
553         Run(t, noModule, func(t *testing.T, env *Env) {
554                 env.OpenFile("a.go")
555                 env.Await(
556                         OutstandingWork(lsp.WorkspaceLoadFailure, "outside of a module"),
557                 )
558                 env.RegexpReplace("a.go", `import "mod.com/hello"`, "")
559                 env.Await(
560                         NoOutstandingWork(),
561                 )
562         })
563 }
564
565 func TestNonGoFolder(t *testing.T) {
566         const files = `
567 -- hello.txt --
568 hi mom
569 `
570         for _, go111module := range []string{"on", "off", ""} {
571                 t.Run(fmt.Sprintf("GO111MODULE_%v", go111module), func(t *testing.T) {
572                         WithOptions(EditorConfig{
573                                 Env: map[string]string{"GO111MODULE": go111module},
574                         }).Run(t, files, func(t *testing.T, env *Env) {
575                                 env.OpenFile("hello.txt")
576                                 env.Await(
577                                         OnceMet(
578                                                 env.DoneWithOpen(),
579                                                 NoShowMessage(),
580                                         ),
581                                 )
582                         })
583                 })
584         }
585 }
586
587 // Tests the repro case from golang/go#38602. Diagnostics are now handled properly,
588 // which blocks type checking.
589 func TestConflictingMainPackageErrors(t *testing.T) {
590         const collision = `
591 -- x/x.go --
592 package x
593
594 import "x/hello"
595
596 func Hello() {
597         hello.HiThere()
598 }
599 -- x/main.go --
600 package main
601
602 func main() {
603         fmt.Println("")
604 }
605 `
606         WithOptions(InGOPATH()).Run(t, collision, func(t *testing.T, env *Env) {
607                 env.OpenFile("x/x.go")
608                 env.Await(
609                         env.DiagnosticAtRegexpWithMessage("x/x.go", `^`, "found packages main (main.go) and x (x.go)"),
610                         env.DiagnosticAtRegexpWithMessage("x/main.go", `^`, "found packages main (main.go) and x (x.go)"),
611                 )
612
613                 // We don't recover cleanly from the errors without good overlay support.
614                 if testenv.Go1Point() >= 16 {
615                         env.RegexpReplace("x/x.go", `package x`, `package main`)
616                         env.Await(OnceMet(
617                                 env.DoneWithChange(),
618                                 env.DiagnosticAtRegexpWithMessage("x/main.go", `fmt`, "undeclared name")))
619                 }
620         })
621 }
622
623 const ardanLabsProxy = `
624 -- github.com/ardanlabs/conf@v1.2.3/go.mod --
625 module github.com/ardanlabs/conf
626
627 go 1.12
628 -- github.com/ardanlabs/conf@v1.2.3/conf.go --
629 package conf
630
631 var ErrHelpWanted error
632 `
633
634 // Test for golang/go#38211.
635 func Test_Issue38211(t *testing.T) {
636         testenv.NeedsGo1Point(t, 14)
637         const ardanLabs = `
638 -- go.mod --
639 module mod.com
640
641 go 1.14
642 -- main.go --
643 package main
644
645 import "github.com/ardanlabs/conf"
646
647 func main() {
648         _ = conf.ErrHelpWanted
649 }
650 `
651         WithOptions(
652                 ProxyFiles(ardanLabsProxy),
653         ).Run(t, ardanLabs, func(t *testing.T, env *Env) {
654                 // Expect a diagnostic with a suggested fix to add
655                 // "github.com/ardanlabs/conf" to the go.mod file.
656                 env.OpenFile("go.mod")
657                 env.OpenFile("main.go")
658                 var d protocol.PublishDiagnosticsParams
659                 env.Await(
660                         OnceMet(
661                                 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
662                                 ReadDiagnostics("main.go", &d),
663                         ),
664                 )
665                 env.ApplyQuickFixes("main.go", d.Diagnostics)
666                 env.SaveBuffer("go.mod")
667                 env.Await(
668                         EmptyDiagnostics("main.go"),
669                 )
670                 // Comment out the line that depends on conf and expect a
671                 // diagnostic and a fix to remove the import.
672                 env.RegexpReplace("main.go", "_ = conf.ErrHelpWanted", "//_ = conf.ErrHelpWanted")
673                 env.Await(
674                         env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
675                 )
676                 env.SaveBuffer("main.go")
677                 // Expect a diagnostic and fix to remove the dependency in the go.mod.
678                 env.Await(EmptyDiagnostics("main.go"))
679                 env.Await(
680                         OnceMet(
681                                 env.DiagnosticAtRegexpWithMessage("go.mod", "require github.com/ardanlabs/conf", "not used in this module"),
682                                 ReadDiagnostics("go.mod", &d),
683                         ),
684                 )
685                 env.ApplyQuickFixes("go.mod", d.Diagnostics)
686                 env.SaveBuffer("go.mod")
687                 env.Await(
688                         EmptyDiagnostics("go.mod"),
689                 )
690                 // Uncomment the lines and expect a new diagnostic for the import.
691                 env.RegexpReplace("main.go", "//_ = conf.ErrHelpWanted", "_ = conf.ErrHelpWanted")
692                 env.SaveBuffer("main.go")
693                 env.Await(
694                         env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
695                 )
696         })
697 }
698
699 // Test for golang/go#38207.
700 func TestNewModule_Issue38207(t *testing.T) {
701         testenv.NeedsGo1Point(t, 14)
702         const emptyFile = `
703 -- go.mod --
704 module mod.com
705
706 go 1.12
707 -- main.go --
708 `
709         WithOptions(
710                 ProxyFiles(ardanLabsProxy),
711         ).Run(t, emptyFile, func(t *testing.T, env *Env) {
712                 env.CreateBuffer("main.go", `package main
713
714 import "github.com/ardanlabs/conf"
715
716 func main() {
717         _ = conf.ErrHelpWanted
718 }
719 `)
720                 env.SaveBuffer("main.go")
721                 var d protocol.PublishDiagnosticsParams
722                 env.Await(
723                         OnceMet(
724                                 env.DiagnosticAtRegexpWithMessage("main.go", `"github.com/ardanlabs/conf"`, "no required module"),
725                                 ReadDiagnostics("main.go", &d),
726                         ),
727                 )
728                 env.ApplyQuickFixes("main.go", d.Diagnostics)
729                 env.Await(
730                         EmptyDiagnostics("main.go"),
731                 )
732         })
733 }
734
735 // Test for golang/go#36960.
736 func TestNewFileBadImports_Issue36960(t *testing.T) {
737         testenv.NeedsGo1Point(t, 14)
738         const simplePackage = `
739 -- go.mod --
740 module mod.com
741
742 go 1.14
743 -- a/a1.go --
744 package a
745
746 import "fmt"
747
748 func _() {
749         fmt.Println("hi")
750 }
751 `
752         Run(t, simplePackage, func(t *testing.T, env *Env) {
753                 env.OpenFile("a/a1.go")
754                 env.CreateBuffer("a/a2.go", ``)
755                 env.SaveBufferWithoutActions("a/a2.go")
756                 env.Await(
757                         OnceMet(
758                                 env.DoneWithSave(),
759                                 NoDiagnostics("a/a1.go"),
760                         ),
761                 )
762                 env.EditBuffer("a/a2.go", fake.NewEdit(0, 0, 0, 0, `package a`))
763                 env.Await(
764                         OnceMet(env.DoneWithChange(), NoDiagnostics("a/a1.go")),
765                 )
766         })
767 }
768
769 // This test tries to replicate the workflow of a user creating a new x test.
770 // It also tests golang/go#39315.
771 func TestManuallyCreatingXTest(t *testing.T) {
772         // Only for 1.15 because of golang/go#37971.
773         testenv.NeedsGo1Point(t, 15)
774
775         // Create a package that already has a test variant (in-package test).
776         const testVariant = `
777 -- go.mod --
778 module mod.com
779
780 go 1.15
781 -- hello/hello.go --
782 package hello
783
784 func Hello() {
785         var x int
786 }
787 -- hello/hello_test.go --
788 package hello
789
790 import "testing"
791
792 func TestHello(t *testing.T) {
793         var x int
794         Hello()
795 }
796 `
797         Run(t, testVariant, func(t *testing.T, env *Env) {
798                 // Open the file, triggering the workspace load.
799                 // There are errors in the code to ensure all is working as expected.
800                 env.OpenFile("hello/hello.go")
801                 env.Await(
802                         env.DiagnosticAtRegexp("hello/hello.go", "x"),
803                         env.DiagnosticAtRegexp("hello/hello_test.go", "x"),
804                 )
805
806                 // Create an empty file with the intention of making it an x test.
807                 // This resembles a typical flow in an editor like VS Code, in which
808                 // a user would create an empty file and add content, saving
809                 // intermittently.
810                 // TODO(rstambler): There might be more edge cases here, as file
811                 // content can be added incrementally.
812                 env.CreateBuffer("hello/hello_x_test.go", ``)
813
814                 // Save the empty file (no actions since formatting will fail).
815                 env.SaveBufferWithoutActions("hello/hello_x_test.go")
816
817                 // Add the content. The missing import is for the package under test.
818                 env.EditBuffer("hello/hello_x_test.go", fake.NewEdit(0, 0, 0, 0, `package hello_test
819
820 import (
821         "testing"
822 )
823
824 func TestHello(t *testing.T) {
825         hello.Hello()
826 }
827 `))
828                 // Expect a diagnostic for the missing import. Save, which should
829                 // trigger import organization. The diagnostic should clear.
830                 env.Await(
831                         env.DiagnosticAtRegexp("hello/hello_x_test.go", "hello.Hello"),
832                 )
833                 env.SaveBuffer("hello/hello_x_test.go")
834                 env.Await(
835                         EmptyDiagnostics("hello/hello_x_test.go"),
836                 )
837         })
838 }
839
840 // Reproduce golang/go#40690.
841 func TestCreateOnlyXTest(t *testing.T) {
842         testenv.NeedsGo1Point(t, 13)
843
844         const mod = `
845 -- go.mod --
846 module mod.com
847
848 go 1.12
849 -- foo/foo.go --
850 package foo
851 -- foo/bar_test.go --
852 `
853         Run(t, mod, func(t *testing.T, env *Env) {
854                 env.OpenFile("foo/bar_test.go")
855                 env.EditBuffer("foo/bar_test.go", fake.NewEdit(0, 0, 0, 0, "package foo"))
856                 env.Await(env.DoneWithChange())
857                 env.RegexpReplace("foo/bar_test.go", "package foo", `package foo_test
858
859 import "testing"
860
861 func TestX(t *testing.T) {
862         var x int
863 }
864 `)
865                 env.Await(
866                         env.DiagnosticAtRegexp("foo/bar_test.go", "x"),
867                 )
868         })
869 }
870
871 func TestChangePackageName(t *testing.T) {
872         t.Skip("This issue hasn't been fixed yet. See golang.org/issue/41061.")
873
874         const mod = `
875 -- go.mod --
876 module mod.com
877
878 go 1.12
879 -- foo/foo.go --
880 package foo
881 -- foo/bar_test.go --
882 package foo_
883 `
884         Run(t, mod, func(t *testing.T, env *Env) {
885                 env.OpenFile("foo/bar_test.go")
886                 env.RegexpReplace("foo/bar_test.go", "package foo_", "package foo_test")
887                 env.SaveBuffer("foo/bar_test.go")
888                 env.Await(
889                         OnceMet(
890                                 env.DoneWithSave(),
891                                 NoDiagnostics("foo/bar_test.go"),
892                         ),
893                         OnceMet(
894                                 env.DoneWithSave(),
895                                 NoDiagnostics("foo/foo.go"),
896                         ),
897                 )
898         })
899 }
900
901 // Reproduces golang/go#40825.
902 func TestEmptyGOPATHXTest_40825(t *testing.T) {
903         const files = `
904 -- x.go --
905 package x
906 -- x_test.go --
907 `
908
909         WithOptions(InGOPATH()).Run(t, files, func(t *testing.T, env *Env) {
910                 env.OpenFile("x_test.go")
911                 env.EditBuffer("x_test.go", fake.NewEdit(0, 0, 0, 0, "pack"))
912                 env.Await(
913                         env.DoneWithChange(),
914                         NoShowMessage(),
915                 )
916         })
917 }
918
919 func TestIgnoredFiles(t *testing.T) {
920         const ws = `
921 -- go.mod --
922 module mod.com
923
924 go 1.12
925 -- _foo/x.go --
926 package x
927
928 var _ = foo.Bar
929 `
930         Run(t, ws, func(t *testing.T, env *Env) {
931                 env.OpenFile("_foo/x.go")
932                 env.Await(
933                         OnceMet(
934                                 env.DoneWithOpen(),
935                                 NoDiagnostics("_foo/x.go"),
936                         ))
937         })
938 }
939
940 // Partially reproduces golang/go#38977, moving a file between packages.
941 // It also gets hit by some go command bug fixed in 1.15, but we don't
942 // care about that so much here.
943 func TestDeletePackage(t *testing.T) {
944         const ws = `
945 -- go.mod --
946 module mod.com
947
948 go 1.15
949 -- a/a.go --
950 package a
951
952 const A = 1
953
954 -- b/b.go --
955 package b
956
957 import "mod.com/a"
958
959 const B = a.A
960
961 -- c/c.go --
962 package c
963
964 import "mod.com/a"
965
966 const C = a.A
967 `
968         Run(t, ws, func(t *testing.T, env *Env) {
969                 env.OpenFile("b/b.go")
970                 env.Await(env.DoneWithOpen())
971                 // Delete c/c.go, the only file in package c.
972                 env.RemoveWorkspaceFile("c/c.go")
973
974                 // We should still get diagnostics for files that exist.
975                 env.RegexpReplace("b/b.go", `a.A`, "a.Nonexistant")
976                 env.Await(env.DiagnosticAtRegexp("b/b.go", `Nonexistant`))
977         })
978 }
979
980 // This is a copy of the scenario_default/quickfix_empty_files.txt test from
981 // govim. Reproduces golang/go#39646.
982 func TestQuickFixEmptyFiles(t *testing.T) {
983         testenv.NeedsGo1Point(t, 15)
984
985         const mod = `
986 -- go.mod --
987 module mod.com
988
989 go 1.12
990 `
991         // To fully recreate the govim tests, we create files by inserting
992         // a newline, adding to the file, and then deleting the newline.
993         // Wait for each event to process to avoid cancellations and force
994         // package loads.
995         writeGoVim := func(env *Env, name, content string) {
996                 env.WriteWorkspaceFile(name, "")
997                 env.Await(env.DoneWithChangeWatchedFiles())
998
999                 env.CreateBuffer(name, "\n")
1000                 env.Await(env.DoneWithOpen())
1001
1002                 env.EditBuffer(name, fake.NewEdit(1, 0, 1, 0, content))
1003                 env.Await(env.DoneWithChange())
1004
1005                 env.EditBuffer(name, fake.NewEdit(0, 0, 1, 0, ""))
1006                 env.Await(env.DoneWithChange())
1007         }
1008
1009         const p = `package p; func DoIt(s string) {};`
1010         const main = `package main
1011
1012 import "mod.com/p"
1013
1014 func main() {
1015         p.DoIt(5)
1016 }
1017 `
1018         // A simple version of the test that reproduces most of the problems it
1019         // exposes.
1020         t.Run("short", func(t *testing.T) {
1021                 Run(t, mod, func(t *testing.T, env *Env) {
1022                         writeGoVim(env, "p/p.go", p)
1023                         writeGoVim(env, "main.go", main)
1024                         env.Await(env.DiagnosticAtRegexp("main.go", "5"))
1025                 })
1026         })
1027
1028         // A full version that replicates the whole flow of the test.
1029         t.Run("full", func(t *testing.T) {
1030                 Run(t, mod, func(t *testing.T, env *Env) {
1031                         writeGoVim(env, "p/p.go", p)
1032                         writeGoVim(env, "main.go", main)
1033                         writeGoVim(env, "p/p_test.go", `package p
1034
1035 import "testing"
1036
1037 func TestDoIt(t *testing.T) {
1038         DoIt(5)
1039 }
1040 `)
1041                         writeGoVim(env, "p/x_test.go", `package p_test
1042
1043 import (
1044         "testing"
1045
1046         "mod.com/p"
1047 )
1048
1049 func TestDoIt(t *testing.T) {
1050         p.DoIt(5)
1051 }
1052 `)
1053                         env.Await(
1054                                 env.DiagnosticAtRegexp("main.go", "5"),
1055                                 env.DiagnosticAtRegexp("p/p_test.go", "5"),
1056                                 env.DiagnosticAtRegexp("p/x_test.go", "5"),
1057                         )
1058                         env.RegexpReplace("p/p.go", "s string", "i int")
1059                         env.Await(
1060                                 EmptyDiagnostics("main.go"),
1061                                 EmptyDiagnostics("p/p_test.go"),
1062                                 EmptyDiagnostics("p/x_test.go"),
1063                         )
1064                 })
1065         })
1066 }
1067
1068 func TestSingleFile(t *testing.T) {
1069         const mod = `
1070 -- go.mod --
1071 module mod.com
1072
1073 go 1.13
1074 -- a/a.go --
1075 package a
1076
1077 func _() {
1078         var x int
1079 }
1080 `
1081         WithOptions(
1082                 // Empty workspace folders.
1083                 WorkspaceFolders(),
1084         ).Run(t, mod, func(t *testing.T, env *Env) {
1085                 env.OpenFile("a/a.go")
1086                 env.Await(
1087                         env.DiagnosticAtRegexp("a/a.go", "x"),
1088                 )
1089         })
1090 }
1091
1092 // Reproduces the case described in
1093 // https://github.com/golang/go/issues/39296#issuecomment-652058883.
1094 func TestPkgm(t *testing.T) {
1095         const basic = `
1096 -- go.mod --
1097 module mod.com
1098
1099 go 1.15
1100 -- foo/foo.go --
1101 package foo
1102
1103 import "fmt"
1104
1105 func Foo() {
1106         fmt.Println("")
1107 }
1108 `
1109         Run(t, basic, func(t *testing.T, env *Env) {
1110                 testenv.NeedsGo1Point(t, 16) // We can't recover cleanly from this case without good overlay support.
1111
1112                 env.WriteWorkspaceFile("foo/foo_test.go", `package main
1113
1114 func main() {
1115
1116 }`)
1117                 env.OpenFile("foo/foo_test.go")
1118                 env.RegexpReplace("foo/foo_test.go", `package main`, `package foo`)
1119                 env.Await(
1120                         OnceMet(
1121                                 env.DoneWithChange(),
1122                                 NoDiagnostics("foo/foo.go"),
1123                         ),
1124                 )
1125         })
1126 }
1127
1128 func TestClosingBuffer(t *testing.T) {
1129         const basic = `
1130 -- go.mod --
1131 module mod.com
1132
1133 go 1.14
1134 -- main.go --
1135 package main
1136
1137 func main() {}
1138 `
1139         Run(t, basic, func(t *testing.T, env *Env) {
1140                 env.Editor.CreateBuffer(env.Ctx, "foo.go", `package main`)
1141                 env.Await(
1142                         env.DoneWithOpen(),
1143                 )
1144                 env.CloseBuffer("foo.go")
1145                 env.Await(
1146                         OnceMet(
1147                                 env.DoneWithClose(),
1148                                 NoLogMatching(protocol.Info, "packages=0"),
1149                         ),
1150                 )
1151         })
1152 }
1153
1154 // Reproduces golang/go#38424.
1155 func TestCutAndPaste(t *testing.T) {
1156         const basic = `
1157 -- go.mod --
1158 module mod.com
1159
1160 go 1.14
1161 -- main2.go --
1162 package main
1163 `
1164         Run(t, basic, func(t *testing.T, env *Env) {
1165                 env.CreateBuffer("main.go", "")
1166                 env.Await(env.DoneWithOpen())
1167
1168                 env.SaveBufferWithoutActions("main.go")
1169                 env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles())
1170
1171                 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1172
1173 func main() {
1174 }
1175 `))
1176                 env.Await(env.DoneWithChange())
1177
1178                 env.SaveBuffer("main.go")
1179                 env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles())
1180
1181                 env.EditBuffer("main.go", fake.NewEdit(0, 0, 4, 0, ""))
1182                 env.Await(env.DoneWithChange())
1183
1184                 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1185
1186 func main() {
1187         var x int
1188 }
1189 `))
1190                 env.Await(
1191                         env.DiagnosticAtRegexp("main.go", "x"),
1192                 )
1193         })
1194 }
1195
1196 // Reproduces golang/go#39763.
1197 func TestInvalidPackageName(t *testing.T) {
1198         testenv.NeedsGo1Point(t, 15)
1199
1200         const pkgDefault = `
1201 -- go.mod --
1202 module mod.com
1203
1204 go 1.12
1205 -- main.go --
1206 package default
1207
1208 func main() {}
1209 `
1210         Run(t, pkgDefault, func(t *testing.T, env *Env) {
1211                 env.OpenFile("main.go")
1212                 env.Await(
1213                         env.DiagnosticAtRegexpWithMessage("main.go", "default", "expected 'IDENT'"),
1214                 )
1215         })
1216 }
1217
1218 // This tests the functionality of the "limitWorkspaceScope"
1219 func TestLimitWorkspaceScope(t *testing.T) {
1220         const mod = `
1221 -- go.mod --
1222 module mod.com
1223
1224 go 1.12
1225 -- a/main.go --
1226 package main
1227
1228 func main() {}
1229 -- main.go --
1230 package main
1231
1232 func main() {
1233         var x int
1234 }
1235 `
1236         WithOptions(
1237                 WorkspaceFolders("a"),
1238         ).Run(t, mod, func(t *testing.T, env *Env) {
1239                 env.OpenFile("a/main.go")
1240                 env.Await(
1241                         env.DiagnosticAtRegexp("main.go", "x"),
1242                 )
1243         })
1244         WithOptions(
1245                 WorkspaceFolders("a"),
1246                 LimitWorkspaceScope(),
1247         ).Run(t, mod, func(t *testing.T, env *Env) {
1248                 env.OpenFile("a/main.go")
1249                 env.Await(
1250                         NoDiagnostics("main.go"),
1251                 )
1252         })
1253 }
1254
1255 func TestSimplifyCompositeLitDiagnostic(t *testing.T) {
1256         const files = `
1257 -- go.mod --
1258 module mod.com
1259
1260 go 1.12
1261 -- main.go --
1262 package main
1263
1264 import "fmt"
1265
1266 type t struct {
1267         msg string
1268 }
1269
1270 func main() {
1271         x := []t{t{"msg"}}
1272         fmt.Println(x)
1273 }
1274 `
1275
1276         WithOptions(
1277                 EditorConfig{EnableStaticcheck: true},
1278         ).Run(t, files, func(t *testing.T, env *Env) {
1279                 env.OpenFile("main.go")
1280                 var d protocol.PublishDiagnosticsParams
1281                 env.Await(OnceMet(
1282                         env.DiagnosticAtRegexpWithMessage("main.go", `t{"msg"}`, "redundant type"),
1283                         ReadDiagnostics("main.go", &d),
1284                 ))
1285                 if tags := d.Diagnostics[0].Tags; len(tags) == 0 || tags[0] != protocol.Unnecessary {
1286                         t.Errorf("wanted Unnecessary tag on diagnostic, got %v", tags)
1287                 }
1288                 env.ApplyQuickFixes("main.go", d.Diagnostics)
1289                 env.Await(EmptyDiagnostics("main.go"))
1290         })
1291 }
1292
1293 // Test some secondary diagnostics
1294 func TestSecondaryDiagnostics(t *testing.T) {
1295         const dir = `
1296 -- go.mod --
1297 module mod.com
1298
1299 go 1.12
1300 -- main.go --
1301 package main
1302 func main() {
1303         panic("not here")
1304 }
1305 -- other.go --
1306 package main
1307 func main() {}
1308 `
1309         Run(t, dir, func(t *testing.T, env *Env) {
1310                 log.SetFlags(log.Lshortfile)
1311                 env.OpenFile("main.go")
1312                 env.OpenFile("other.go")
1313                 x := env.DiagnosticsFor("main.go")
1314                 if x == nil {
1315                         t.Fatalf("expected 1 diagnostic, got none")
1316                 }
1317                 if len(x.Diagnostics) != 1 {
1318                         t.Fatalf("main.go, got %d diagnostics, expected 1", len(x.Diagnostics))
1319                 }
1320                 keep := x.Diagnostics[0]
1321                 y := env.DiagnosticsFor("other.go")
1322                 if len(y.Diagnostics) != 1 {
1323                         t.Fatalf("other.go: got %d diagnostics, expected 1", len(y.Diagnostics))
1324                 }
1325                 if len(y.Diagnostics[0].RelatedInformation) != 1 {
1326                         t.Fatalf("got %d RelatedInformations, expected 1", len(y.Diagnostics[0].RelatedInformation))
1327                 }
1328                 // check that the RelatedInformation matches the error from main.go
1329                 c := y.Diagnostics[0].RelatedInformation[0]
1330                 if c.Location.Range != keep.Range {
1331                         t.Errorf("locations don't match. Got %v expected %v", c.Location.Range, keep.Range)
1332                 }
1333         })
1334 }
1335
1336 func TestNotifyOrphanedFiles(t *testing.T) {
1337         // Need GO111MODULE=on for this test to work with Go 1.12.
1338         testenv.NeedsGo1Point(t, 13)
1339
1340         const files = `
1341 -- go.mod --
1342 module mod.com
1343
1344 go 1.12
1345 -- a/a.go --
1346 package a
1347
1348 func main() {
1349         var x int
1350 }
1351 -- a/a_ignore.go --
1352 // +build ignore
1353
1354 package a
1355
1356 func _() {
1357         var x int
1358 }
1359 `
1360         Run(t, files, func(t *testing.T, env *Env) {
1361                 env.OpenFile("a/a.go")
1362                 env.Await(
1363                         env.DiagnosticAtRegexp("a/a.go", "x"),
1364                 )
1365                 env.OpenFile("a/a_ignore.go")
1366                 env.Await(
1367                         DiagnosticAt("a/a_ignore.go", 2, 8),
1368                 )
1369         })
1370 }
1371
1372 func TestEnableAllExperiments(t *testing.T) {
1373         const mod = `
1374 -- go.mod --
1375 module mod.com
1376
1377 go 1.12
1378 -- main.go --
1379 package main
1380
1381 import "bytes"
1382
1383 func b(c bytes.Buffer) {
1384         _ = 1
1385 }
1386 `
1387         WithOptions(
1388                 EditorConfig{
1389                         AllExperiments: true,
1390                 },
1391         ).Run(t, mod, func(t *testing.T, env *Env) {
1392                 // Confirm that the setting doesn't cause any warnings.
1393                 env.Await(NoShowMessage())
1394         })
1395 }
1396
1397 func TestSwig(t *testing.T) {
1398         t.Skipf("skipped until golang/go#37098 is resolved")
1399
1400         const mod = `
1401 -- go.mod --
1402 module mod.com
1403
1404 go 1.12
1405 -- pkg/simple/export_swig.go --
1406 package simple
1407
1408 func ExportSimple(x, y int) int {
1409         return Gcd(x, y)
1410 }
1411 -- pkg/simple/simple.swigcxx --
1412 %module simple
1413
1414 %inline %{
1415 extern int gcd(int x, int y)
1416 {
1417   int g;
1418   g = y;
1419   while (x > 0) {
1420     g = x;
1421     x = y % x;
1422     y = g;
1423   }
1424   return g;
1425 }
1426 %}
1427 -- main.go --
1428 package a
1429
1430 func main() {
1431         var x int
1432 }
1433 `
1434         Run(t, mod, func(t *testing.T, env *Env) {
1435                 env.Await(
1436                         OnceMet(
1437                                 InitialWorkspaceLoad,
1438                                 NoDiagnosticWithMessage("", "illegal character U+0023 '#'"),
1439                         ),
1440                 )
1441         })
1442 }
1443
1444 // When foo_test.go is opened, gopls will object to the borked package name.
1445 // This test asserts that when the package name is fixed, gopls will soon after
1446 // have no more complaints about it.
1447 // https://github.com/golang/go/issues/41061
1448 func TestRenamePackage(t *testing.T) {
1449         testenv.NeedsGo1Point(t, 16)
1450
1451         const proxy = `
1452 -- example.com@v1.2.3/go.mod --
1453 module example.com
1454
1455 go 1.12
1456 -- example.com@v1.2.3/blah/blah.go --
1457 package blah
1458
1459 const Name = "Blah"
1460 -- random.org@v1.2.3/go.mod --
1461 module random.org
1462
1463 go 1.12
1464 -- random.org@v1.2.3/blah/blah.go --
1465 package hello
1466
1467 const Name = "Hello"
1468 `
1469
1470         const contents = `
1471 -- go.mod --
1472 module mod.com
1473
1474 go 1.12
1475 -- main.go --
1476 package main
1477
1478 import "example.com/blah"
1479
1480 func main() {
1481         blah.Hello()
1482 }
1483 -- bob.go --
1484 package main
1485 -- foo/foo.go --
1486 package foo
1487 -- foo/foo_test.go --
1488 package foo_
1489 `
1490
1491         WithOptions(
1492                 ProxyFiles(proxy),
1493                 InGOPATH(),
1494         ).Run(t, contents, func(t *testing.T, env *Env) {
1495                 // Simulate typing character by character.
1496                 env.OpenFile("foo/foo_test.go")
1497                 env.Await(env.DoneWithOpen())
1498                 env.RegexpReplace("foo/foo_test.go", "_", "_t")
1499                 env.Await(env.DoneWithChange())
1500                 env.RegexpReplace("foo/foo_test.go", "_t", "_test")
1501                 env.Await(env.DoneWithChange())
1502
1503                 env.Await(
1504                         EmptyDiagnostics("foo/foo_test.go"),
1505                         NoOutstandingWork(),
1506                 )
1507         })
1508 }
1509
1510 // TestProgressBarErrors confirms that critical workspace load errors are shown
1511 // and updated via progress reports.
1512 func TestProgressBarErrors(t *testing.T) {
1513         testenv.NeedsGo1Point(t, 14)
1514
1515         const pkg = `
1516 -- go.mod --
1517 modul mod.com
1518
1519 go 1.12
1520 -- main.go --
1521 package main
1522 `
1523         Run(t, pkg, func(t *testing.T, env *Env) {
1524                 env.OpenFile("go.mod")
1525                 env.Await(
1526                         OutstandingWork(lsp.WorkspaceLoadFailure, "unknown directive"),
1527                 )
1528                 env.EditBuffer("go.mod", fake.NewEdit(0, 0, 3, 0, `module mod.com
1529
1530 go 1.hello
1531 `))
1532                 // As of golang/go#42529, go.mod changes do not reload the workspace until
1533                 // they are saved.
1534                 env.SaveBufferWithoutActions("go.mod")
1535                 env.Await(
1536                         OutstandingWork(lsp.WorkspaceLoadFailure, "invalid go version"),
1537                 )
1538                 env.RegexpReplace("go.mod", "go 1.hello", "go 1.12")
1539                 env.SaveBufferWithoutActions("go.mod")
1540                 env.Await(
1541                         NoOutstandingWork(),
1542                 )
1543         })
1544 }
1545
1546 func TestDeleteDirectory(t *testing.T) {
1547         testenv.NeedsGo1Point(t, 14)
1548
1549         const mod = `
1550 -- bob/bob.go --
1551 package bob
1552
1553 func Hello() {
1554         var x int
1555 }
1556 -- go.mod --
1557 module mod.com
1558 -- main.go --
1559 package main
1560
1561 import "mod.com/bob"
1562
1563 func main() {
1564         bob.Hello()
1565 }
1566 `
1567         Run(t, mod, func(t *testing.T, env *Env) {
1568                 env.RemoveWorkspaceFile("bob")
1569                 env.Await(
1570                         env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
1571                         EmptyDiagnostics("bob/bob.go"),
1572                 )
1573         })
1574 }
1575
1576 // Confirms that circular imports are tested and reported.
1577 func TestCircularImports(t *testing.T) {
1578         const mod = `
1579 -- go.mod --
1580 module mod.com
1581
1582 go 1.12
1583 -- self/self.go --
1584 package self
1585
1586 import _ "mod.com/self"
1587 func Hello() {}
1588 -- double/a/a.go --
1589 package a
1590
1591 import _ "mod.com/double/b"
1592 -- double/b/b.go --
1593 package b
1594
1595 import _ "mod.com/double/a"
1596 -- triple/a/a.go --
1597 package a
1598
1599 import _ "mod.com/triple/b"
1600 -- triple/b/b.go --
1601 package b
1602
1603 import _ "mod.com/triple/c"
1604 -- triple/c/c.go --
1605 package c
1606
1607 import _ "mod.com/triple/a"
1608 `
1609         Run(t, mod, func(t *testing.T, env *Env) {
1610                 env.Await(
1611                         env.DiagnosticAtRegexpWithMessage("self/self.go", `_ "mod.com/self"`, "import cycle not allowed"),
1612                         env.DiagnosticAtRegexpWithMessage("double/a/a.go", `_ "mod.com/double/b"`, "import cycle not allowed"),
1613                         env.DiagnosticAtRegexpWithMessage("triple/a/a.go", `_ "mod.com/triple/b"`, "import cycle not allowed"),
1614                 )
1615         })
1616 }
1617
1618 func TestBadImport(t *testing.T) {
1619         testenv.NeedsGo1Point(t, 14)
1620
1621         const mod = `
1622 -- go.mod --
1623 module mod.com
1624
1625 go 1.12
1626 -- main.go --
1627 package main
1628
1629 import (
1630         _ "nosuchpkg"
1631 )
1632 `
1633         t.Run("module", func(t *testing.T) {
1634                 Run(t, mod, func(t *testing.T, env *Env) {
1635                         env.Await(
1636                                 env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `could not import nosuchpkg (no required module provides package "nosuchpkg"`),
1637                         )
1638                 })
1639         })
1640         t.Run("GOPATH", func(t *testing.T) {
1641                 WithOptions(
1642                         InGOPATH(),
1643                         EditorConfig{
1644                                 Env: map[string]string{"GO111MODULE": "off"},
1645                         },
1646                         Modes(Singleton),
1647                 ).Run(t, mod, func(t *testing.T, env *Env) {
1648                         env.Await(
1649                                 env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `cannot find package "nosuchpkg" in any of`),
1650                         )
1651                 })
1652         })
1653 }
1654
1655 func TestMultipleModules_Warning(t *testing.T) {
1656         const modules = `
1657 -- a/go.mod --
1658 module a.com
1659
1660 go 1.12
1661 -- a/a.go --
1662 package a
1663 -- b/go.mod --
1664 module b.com
1665
1666 go 1.12
1667 -- b/b.go --
1668 package b
1669 `
1670         for _, go111module := range []string{"on", "auto"} {
1671                 t.Run("GO111MODULE="+go111module, func(t *testing.T) {
1672                         WithOptions(
1673                                 Modes(Singleton),
1674                                 EditorConfig{
1675                                         Env: map[string]string{
1676                                                 "GO111MODULE": go111module,
1677                                         },
1678                                 },
1679                         ).Run(t, modules, func(t *testing.T, env *Env) {
1680                                 env.OpenFile("a/a.go")
1681                                 env.OpenFile("b/go.mod")
1682                                 env.Await(
1683                                         env.DiagnosticAtRegexp("a/a.go", "package a"),
1684                                         env.DiagnosticAtRegexp("b/go.mod", "module b.com"),
1685                                         OutstandingWork(lsp.WorkspaceLoadFailure, "gopls requires a module at the root of your workspace."),
1686                                 )
1687                         })
1688                 })
1689         }
1690
1691         // Expect no warning if GO111MODULE=auto in a directory in GOPATH.
1692         t.Run("GOPATH_GO111MODULE_auto", func(t *testing.T) {
1693                 WithOptions(
1694                         Modes(Singleton),
1695                         EditorConfig{
1696                                 Env: map[string]string{
1697                                         "GO111MODULE": "auto",
1698                                 },
1699                         },
1700                         InGOPATH(),
1701                 ).Run(t, modules, func(t *testing.T, env *Env) {
1702                         env.OpenFile("a/a.go")
1703                         env.Await(
1704                                 OnceMet(
1705                                         env.DoneWithOpen(),
1706                                         NoDiagnostics("a/a.go"),
1707                                 ),
1708                                 NoOutstandingWork(),
1709                         )
1710                 })
1711         })
1712 }
1713
1714 func TestNestedModules(t *testing.T) {
1715         const proxy = `
1716 -- nested.com@v1.0.0/go.mod --
1717 module nested.com
1718
1719 go 1.12
1720 -- nested.com@v1.0.0/hello/hello.go --
1721 package hello
1722
1723 func Hello() {}
1724 `
1725
1726         const nested = `
1727 -- go.mod --
1728 module mod.com
1729
1730 go 1.12
1731
1732 require nested.com v1.0.0
1733 -- go.sum --
1734 nested.com v1.0.0 h1:I6spLE4CgFqMdBPc+wTV2asDO2QJ3tU0YAT+jkLeN1I=
1735 nested.com v1.0.0/go.mod h1:ly53UzXQgVjSlV7wicdBB4p8BxfytuGT1Xcyv0ReJfI=
1736 -- main.go --
1737 package main
1738
1739 import "nested.com/hello"
1740
1741 func main() {
1742         hello.Hello()
1743 }
1744 -- nested/go.mod --
1745 module nested.com
1746
1747 -- nested/hello/hello.go --
1748 package hello
1749
1750 func Hello() {
1751         helloHelper()
1752 }
1753 -- nested/hello/hello_helper.go --
1754 package hello
1755
1756 func helloHelper() {}
1757 `
1758         WithOptions(
1759                 ProxyFiles(proxy),
1760                 Modes(Singleton),
1761         ).Run(t, nested, func(t *testing.T, env *Env) {
1762                 // Expect a diagnostic in a nested module.
1763                 env.OpenFile("nested/hello/hello.go")
1764                 didOpen := env.DoneWithOpen()
1765                 env.Await(
1766                         OnceMet(
1767                                 didOpen,
1768                                 env.DiagnosticAtRegexp("nested/hello/hello.go", "helloHelper"),
1769                         ),
1770                         OnceMet(
1771                                 didOpen,
1772                                 env.DiagnosticAtRegexpWithMessage("nested/hello/hello.go", "package hello", "nested module"),
1773                         ),
1774                         OnceMet(
1775                                 didOpen,
1776                                 OutstandingWork(lsp.WorkspaceLoadFailure, "nested module"),
1777                         ),
1778                 )
1779         })
1780 }
1781
1782 func TestAdHocPackagesReloading(t *testing.T) {
1783         const nomod = `
1784 -- main.go --
1785 package main
1786
1787 func main() {}
1788 `
1789         Run(t, nomod, func(t *testing.T, env *Env) {
1790                 env.OpenFile("main.go")
1791                 env.RegexpReplace("main.go", "{}", "{ var x int; }") // simulate typing
1792                 env.Await(
1793                         OnceMet(
1794                                 env.DoneWithChange(),
1795                                 NoLogMatching(protocol.Info, "packages=1"),
1796                         ),
1797                 )
1798         })
1799 }
1800
1801 func TestBuildTagChange(t *testing.T) {
1802         const files = `
1803 -- go.mod --
1804 module mod.com
1805
1806 go 1.12
1807 -- foo.go --
1808 // decoy comment
1809 // +build hidden
1810 // decoy comment
1811
1812 package foo
1813 var Foo = 1
1814 -- bar.go --
1815 package foo
1816 var Bar = Foo
1817 `
1818
1819         Run(t, files, func(t *testing.T, env *Env) {
1820                 env.OpenFile("foo.go")
1821                 env.Await(env.DiagnosticAtRegexpWithMessage("bar.go", `Foo`, "undeclared name"))
1822                 env.RegexpReplace("foo.go", `\+build`, "")
1823                 env.Await(EmptyDiagnostics("bar.go"))
1824         })
1825
1826 }
1827
1828 func TestIssue44736(t *testing.T) {
1829         const files = `
1830         -- go.mod --
1831 module blah.com
1832
1833 go 1.16
1834 -- main.go --
1835 package main
1836
1837 import "fmt"
1838
1839 func main() {
1840         asdf
1841         fmt.Printf("This is a test %v")
1842         fdas
1843 }
1844 -- other.go --
1845 package main
1846
1847 `
1848         Run(t, files, func(t *testing.T, env *Env) {
1849                 env.OpenFile("main.go")
1850                 env.OpenFile("other.go")
1851                 env.Await(
1852                         env.DiagnosticAtRegexpWithMessage("main.go", "asdf", "undeclared name"),
1853                         env.DiagnosticAtRegexpWithMessage("main.go", "fdas", "undeclared name"),
1854                 )
1855                 env.SetBufferContent("other.go", "package main\n\nasdf")
1856                 // The new diagnostic in other.go should not suppress diagnostics in main.go.
1857                 env.Await(
1858                         OnceMet(
1859                                 env.DiagnosticAtRegexpWithMessage("other.go", "asdf", "expected declaration"),
1860                                 env.DiagnosticAtRegexpWithMessage("main.go", "asdf", "undeclared name"),
1861                         ),
1862                 )
1863         })
1864 }
1865
1866 // Tests golang/go#45075, a panic in fillreturns breaks diagnostics.
1867 func TestFillReturnsPanic(t *testing.T) {
1868         // At tip, the panic no longer reproduces.
1869         testenv.SkipAfterGo1Point(t, 16)
1870         const files = `
1871 -- go.mod --
1872 module mod.com
1873
1874 go 1.16
1875 -- main.go --
1876 package main
1877
1878
1879 func foo() int {
1880         return x, nil
1881 }
1882
1883 `
1884         Run(t, files, func(t *testing.T, env *Env) {
1885                 env.OpenFile("main.go")
1886                 env.Await(
1887                         env.DiagnosticAtRegexpWithMessage("main.go", `return x`, "wrong number of return values"),
1888                         LogMatching(protocol.Error, `.*analysis fillreturns.*panicked.*`, 2),
1889                 )
1890         })
1891 }