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.
13 . "golang.org/x/tools/gopls/internal/regtest"
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"
21 func TestMain(m *testing.M) {
25 // Use mod.com for all go.mod files due to golang/go#35230.
26 const exampleProgram = `
37 fmt.Println("Hello World.")
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
47 env.OpenFile("main.go")
48 env.RegexpReplace("main.go", "Printl(n)", "")
50 // Once we have gotten diagnostics for the change above, we should
51 // satisfy the DiagnosticAtRegexp assertion.
54 env.DiagnosticAtRegexp("main.go", "Printl"),
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
65 func TestMissingImportDiagsClearOnFirstFile(t *testing.T) {
72 Run(t, onlyMod, func(t *testing.T, env *Env) {
73 env.CreateBuffer("main.go", `package main
80 env.DiagnosticAtRegexp("main.go", "log"),
82 env.SaveBuffer("main.go")
84 EmptyDiagnostics("main.go"),
89 func TestDiagnosticErrorInNewFile(t *testing.T) {
90 const brokenFile = `package main
94 Run(t, brokenFile, func(t *testing.T, env *Env) {
95 env.CreateBuffer("broken.go", brokenFile)
96 env.Await(env.DiagnosticAtRegexp("broken.go", "\"abc"))
100 // badPackage contains a duplicate definition of the 'a' const.
116 func TestDiagnosticClearingOnEdit(t *testing.T) {
117 Run(t, badPackage, func(t *testing.T, env *Env) {
119 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
121 // Fix the error by editing the const name in b.go to `b`.
122 env.RegexpReplace("b.go", "(a) = 2", "b")
124 EmptyDiagnostics("a.go"),
125 EmptyDiagnostics("b.go"),
130 func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) {
131 Run(t, badPackage, func(t *testing.T, env *Env) {
133 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
134 env.RemoveWorkspaceFile("b.go")
136 env.Await(EmptyDiagnostics("a.go"), EmptyDiagnostics("b.go"))
140 func TestDiagnosticClearingOnClose(t *testing.T) {
141 Run(t, badPackage, func(t *testing.T, env *Env) {
142 env.CreateBuffer("c.go", `package consts
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")
151 env.DiagnosticAtRegexp("a.go", "a = 1"),
152 env.DiagnosticAtRegexp("b.go", "a = 2"),
153 EmptyDiagnostics("c.go"))
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", "")
163 // Write the file contents with a missing import.
164 env.EditBuffer("c/c.go", fake.Edit{
167 const a = http.MethodGet
171 env.DiagnosticAtRegexp("c/c.go", "http.MethodGet"),
173 // Save file, which will organize imports, adding the expected import.
174 // Expect the diagnostics to clear.
175 env.SaveBuffer("c/c.go")
177 EmptyDiagnostics("c/c.go"),
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
202 func TestA(t *testing.T) {
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"))
215 // Make sure the test variant has been removed from the workspace by
216 // triggering a metadata load.
218 env.RegexpReplace("a.go", `// import`, "import")
219 env.Await(env.DiagnosticAtRegexp("a.go", `"fmt"`))
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")
232 env.DoneWithChangeWatchedFiles(),
233 DiagnosticAt("a_test.go", 5, 3)))
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) {
257 t.Run("manual", func(t *testing.T) {
258 Run(t, noMod, func(t *testing.T, env *Env) {
260 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
262 env.CreateBuffer("go.mod", `module mod.com
266 env.SaveBuffer("go.mod")
268 EmptyDiagnostics("main.go"),
270 var d protocol.PublishDiagnosticsParams
273 env.DiagnosticAtRegexp("bob/bob.go", "x"),
274 ReadDiagnostics("bob/bob.go", &d),
277 if len(d.Diagnostics) != 1 {
278 t.Fatalf("expected 1 diagnostic, got %v", len(d.Diagnostics))
282 t.Run("initialized", func(t *testing.T) {
283 Run(t, noMod, func(t *testing.T, env *Env) {
285 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
287 env.RunGoCommand("mod", "init", "mod.com")
289 EmptyDiagnostics("main.go"),
290 env.DiagnosticAtRegexp("bob/bob.go", "x"),
295 t.Run("without workspace module", func(t *testing.T) {
298 ).Run(t, noMod, func(t *testing.T, env *Env) {
300 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
302 if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}); err != nil {
306 EmptyDiagnostics("main.go"),
307 env.DiagnosticAtRegexp("bob/bob.go", "x"),
313 // Tests golang/go#38267.
314 func TestIssue38267(t *testing.T) {
315 const testPackage = `
323 func Hello(x string) {
331 type testStruct struct{
335 func TestHello(t *testing.T) {
336 testStructs := []*testStruct{
337 &testStruct{"hello"},
338 &testStruct{"goodbye"},
340 for y := range testStructs {
346 Run(t, testPackage, func(t *testing.T, env *Env) {
347 env.OpenFile("lib_test.go")
349 DiagnosticAt("lib_test.go", 10, 2),
350 DiagnosticAt("lib_test.go", 11, 2),
352 env.OpenFile("lib.go")
353 env.RegexpReplace("lib.go", "_ = x", "var y int")
355 env.DiagnosticAtRegexp("lib.go", "y int"),
356 EmptyDiagnostics("lib_test.go"),
361 // Tests golang/go#38328.
362 func TestPackageChange_Issue38328(t *testing.T) {
363 const packageChange = `
372 Run(t, packageChange, func(t *testing.T, env *Env) {
374 env.RegexpReplace("a.go", "foo", "foox")
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
382 env.DoneWithChange(),
383 NoDiagnostics("a.go"),
389 const testPackageWithRequire = `
395 require foo.test v1.2.3
397 foo.test v1.2.3 h1:TMA+lyd1ck0TqjSFpNe4T6cf/K6TYkoHwOOcMBMjaEw=
398 foo.test v1.2.3/go.mod h1:Ij3kyLIe5lzjycjh13NL8I2gX0quZuTdW0MnmlwGBL4=
409 fmt.Printf("answer: %s", bar.Answer)
413 const testPackageWithRequireProxy = `
414 -- foo.test@v1.2.3/go.mod --
418 -- foo.test@v1.2.3/bar/const.go --
424 func TestResolveDiagnosticWithDownload(t *testing.T) {
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"))
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))
443 // Tests golang/go#36951.
444 func TestAdHocPackages_Issue36951(t *testing.T) {
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"))
459 // Tests golang/go#37984: GOPATH should be read from the go command.
460 func TestNoGOPATH_Issue37984(t *testing.T) {
466 fmt.Println("Hello World")
471 Env: map[string]string{
473 "GO111MODULE": "off",
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"))
483 // Tests golang/go#38669.
484 func TestEqualInEnv_Issue38669(t *testing.T) {
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"))
507 // Tests golang/go#38467.
508 func TestNoSuggestedFixesForGeneratedFiles_Issue38467(t *testing.T) {
517 // Code generated by generator.go. DO NOT EDIT.
520 for i, _ := range []string{} {
525 Run(t, generated, func(t *testing.T, env *Env) {
526 env.OpenFile("main.go")
527 var d protocol.PublishDiagnosticsParams
530 DiagnosticAt("main.go", 5, 8),
531 ReadDiagnostics("main.go", &d),
534 if fixes := env.GetQuickFixes("main.go", d.Diagnostics); len(fixes) != 0 {
535 t.Errorf("got quick fixes %v, wanted none", fixes)
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) {
547 import "mod.com/hello"
553 Run(t, noModule, func(t *testing.T, env *Env) {
556 OutstandingWork(lsp.WorkspaceLoadFailure, "outside of a module"),
558 env.RegexpReplace("a.go", `import "mod.com/hello"`, "")
565 func TestNonGoFolder(t *testing.T) {
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")
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) {
606 WithOptions(InGOPATH()).Run(t, collision, func(t *testing.T, env *Env) {
607 env.OpenFile("x/x.go")
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)"),
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`)
617 env.DoneWithChange(),
618 env.DiagnosticAtRegexpWithMessage("x/main.go", `fmt`, "undeclared name")))
623 const ardanLabsProxy = `
624 -- github.com/ardanlabs/conf@v1.2.3/go.mod --
625 module github.com/ardanlabs/conf
628 -- github.com/ardanlabs/conf@v1.2.3/conf.go --
631 var ErrHelpWanted error
634 // Test for golang/go#38211.
635 func Test_Issue38211(t *testing.T) {
636 testenv.NeedsGo1Point(t, 14)
645 import "github.com/ardanlabs/conf"
648 _ = conf.ErrHelpWanted
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
661 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
662 ReadDiagnostics("main.go", &d),
665 env.ApplyQuickFixes("main.go", d.Diagnostics)
666 env.SaveBuffer("go.mod")
668 EmptyDiagnostics("main.go"),
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")
674 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
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"))
681 env.DiagnosticAtRegexpWithMessage("go.mod", "require github.com/ardanlabs/conf", "not used in this module"),
682 ReadDiagnostics("go.mod", &d),
685 env.ApplyQuickFixes("go.mod", d.Diagnostics)
686 env.SaveBuffer("go.mod")
688 EmptyDiagnostics("go.mod"),
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")
694 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
699 // Test for golang/go#38207.
700 func TestNewModule_Issue38207(t *testing.T) {
701 testenv.NeedsGo1Point(t, 14)
710 ProxyFiles(ardanLabsProxy),
711 ).Run(t, emptyFile, func(t *testing.T, env *Env) {
712 env.CreateBuffer("main.go", `package main
714 import "github.com/ardanlabs/conf"
717 _ = conf.ErrHelpWanted
720 env.SaveBuffer("main.go")
721 var d protocol.PublishDiagnosticsParams
724 env.DiagnosticAtRegexpWithMessage("main.go", `"github.com/ardanlabs/conf"`, "no required module"),
725 ReadDiagnostics("main.go", &d),
728 env.ApplyQuickFixes("main.go", d.Diagnostics)
730 EmptyDiagnostics("main.go"),
735 // Test for golang/go#36960.
736 func TestNewFileBadImports_Issue36960(t *testing.T) {
737 testenv.NeedsGo1Point(t, 14)
738 const simplePackage = `
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")
759 NoDiagnostics("a/a1.go"),
762 env.EditBuffer("a/a2.go", fake.NewEdit(0, 0, 0, 0, `package a`))
764 OnceMet(env.DoneWithChange(), NoDiagnostics("a/a1.go")),
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)
775 // Create a package that already has a test variant (in-package test).
776 const testVariant = `
787 -- hello/hello_test.go --
792 func TestHello(t *testing.T) {
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")
802 env.DiagnosticAtRegexp("hello/hello.go", "x"),
803 env.DiagnosticAtRegexp("hello/hello_test.go", "x"),
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
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", ``)
814 // Save the empty file (no actions since formatting will fail).
815 env.SaveBufferWithoutActions("hello/hello_x_test.go")
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
824 func TestHello(t *testing.T) {
828 // Expect a diagnostic for the missing import. Save, which should
829 // trigger import organization. The diagnostic should clear.
831 env.DiagnosticAtRegexp("hello/hello_x_test.go", "hello.Hello"),
833 env.SaveBuffer("hello/hello_x_test.go")
835 EmptyDiagnostics("hello/hello_x_test.go"),
840 // Reproduce golang/go#40690.
841 func TestCreateOnlyXTest(t *testing.T) {
842 testenv.NeedsGo1Point(t, 13)
851 -- foo/bar_test.go --
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
861 func TestX(t *testing.T) {
866 env.DiagnosticAtRegexp("foo/bar_test.go", "x"),
871 func TestChangePackageName(t *testing.T) {
872 t.Skip("This issue hasn't been fixed yet. See golang.org/issue/41061.")
881 -- foo/bar_test.go --
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")
891 NoDiagnostics("foo/bar_test.go"),
895 NoDiagnostics("foo/foo.go"),
901 // Reproduces golang/go#40825.
902 func TestEmptyGOPATHXTest_40825(t *testing.T) {
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"))
913 env.DoneWithChange(),
919 func TestIgnoredFiles(t *testing.T) {
930 Run(t, ws, func(t *testing.T, env *Env) {
931 env.OpenFile("_foo/x.go")
935 NoDiagnostics("_foo/x.go"),
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) {
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")
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`))
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)
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
995 writeGoVim := func(env *Env, name, content string) {
996 env.WriteWorkspaceFile(name, "")
997 env.Await(env.DoneWithChangeWatchedFiles())
999 env.CreateBuffer(name, "\n")
1000 env.Await(env.DoneWithOpen())
1002 env.EditBuffer(name, fake.NewEdit(1, 0, 1, 0, content))
1003 env.Await(env.DoneWithChange())
1005 env.EditBuffer(name, fake.NewEdit(0, 0, 1, 0, ""))
1006 env.Await(env.DoneWithChange())
1009 const p = `package p; func DoIt(s string) {};`
1010 const main = `package main
1018 // A simple version of the test that reproduces most of the problems it
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"))
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
1037 func TestDoIt(t *testing.T) {
1041 writeGoVim(env, "p/x_test.go", `package p_test
1049 func TestDoIt(t *testing.T) {
1054 env.DiagnosticAtRegexp("main.go", "5"),
1055 env.DiagnosticAtRegexp("p/p_test.go", "5"),
1056 env.DiagnosticAtRegexp("p/x_test.go", "5"),
1058 env.RegexpReplace("p/p.go", "s string", "i int")
1060 EmptyDiagnostics("main.go"),
1061 EmptyDiagnostics("p/p_test.go"),
1062 EmptyDiagnostics("p/x_test.go"),
1068 func TestSingleFile(t *testing.T) {
1082 // Empty workspace folders.
1084 ).Run(t, mod, func(t *testing.T, env *Env) {
1085 env.OpenFile("a/a.go")
1087 env.DiagnosticAtRegexp("a/a.go", "x"),
1092 // Reproduces the case described in
1093 // https://github.com/golang/go/issues/39296#issuecomment-652058883.
1094 func TestPkgm(t *testing.T) {
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.
1112 env.WriteWorkspaceFile("foo/foo_test.go", `package main
1117 env.OpenFile("foo/foo_test.go")
1118 env.RegexpReplace("foo/foo_test.go", `package main`, `package foo`)
1121 env.DoneWithChange(),
1122 NoDiagnostics("foo/foo.go"),
1128 func TestClosingBuffer(t *testing.T) {
1139 Run(t, basic, func(t *testing.T, env *Env) {
1140 env.Editor.CreateBuffer(env.Ctx, "foo.go", `package main`)
1144 env.CloseBuffer("foo.go")
1147 env.DoneWithClose(),
1148 NoLogMatching(protocol.Info, "packages=0"),
1154 // Reproduces golang/go#38424.
1155 func TestCutAndPaste(t *testing.T) {
1164 Run(t, basic, func(t *testing.T, env *Env) {
1165 env.CreateBuffer("main.go", "")
1166 env.Await(env.DoneWithOpen())
1168 env.SaveBufferWithoutActions("main.go")
1169 env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles())
1171 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1176 env.Await(env.DoneWithChange())
1178 env.SaveBuffer("main.go")
1179 env.Await(env.DoneWithSave(), env.DoneWithChangeWatchedFiles())
1181 env.EditBuffer("main.go", fake.NewEdit(0, 0, 4, 0, ""))
1182 env.Await(env.DoneWithChange())
1184 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1191 env.DiagnosticAtRegexp("main.go", "x"),
1196 // Reproduces golang/go#39763.
1197 func TestInvalidPackageName(t *testing.T) {
1198 testenv.NeedsGo1Point(t, 15)
1200 const pkgDefault = `
1210 Run(t, pkgDefault, func(t *testing.T, env *Env) {
1211 env.OpenFile("main.go")
1213 env.DiagnosticAtRegexpWithMessage("main.go", "default", "expected 'IDENT'"),
1218 // This tests the functionality of the "limitWorkspaceScope"
1219 func TestLimitWorkspaceScope(t *testing.T) {
1237 WorkspaceFolders("a"),
1238 ).Run(t, mod, func(t *testing.T, env *Env) {
1239 env.OpenFile("a/main.go")
1241 env.DiagnosticAtRegexp("main.go", "x"),
1245 WorkspaceFolders("a"),
1246 LimitWorkspaceScope(),
1247 ).Run(t, mod, func(t *testing.T, env *Env) {
1248 env.OpenFile("a/main.go")
1250 NoDiagnostics("main.go"),
1255 func TestSimplifyCompositeLitDiagnostic(t *testing.T) {
1277 EditorConfig{EnableStaticcheck: true},
1278 ).Run(t, files, func(t *testing.T, env *Env) {
1279 env.OpenFile("main.go")
1280 var d protocol.PublishDiagnosticsParams
1282 env.DiagnosticAtRegexpWithMessage("main.go", `t{"msg"}`, "redundant type"),
1283 ReadDiagnostics("main.go", &d),
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)
1288 env.ApplyQuickFixes("main.go", d.Diagnostics)
1289 env.Await(EmptyDiagnostics("main.go"))
1293 // Test some secondary diagnostics
1294 func TestSecondaryDiagnostics(t *testing.T) {
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")
1315 t.Fatalf("expected 1 diagnostic, got none")
1317 if len(x.Diagnostics) != 1 {
1318 t.Fatalf("main.go, got %d diagnostics, expected 1", len(x.Diagnostics))
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))
1325 if len(y.Diagnostics[0].RelatedInformation) != 1 {
1326 t.Fatalf("got %d RelatedInformations, expected 1", len(y.Diagnostics[0].RelatedInformation))
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)
1336 func TestNotifyOrphanedFiles(t *testing.T) {
1337 // Need GO111MODULE=on for this test to work with Go 1.12.
1338 testenv.NeedsGo1Point(t, 13)
1360 Run(t, files, func(t *testing.T, env *Env) {
1361 env.OpenFile("a/a.go")
1363 env.DiagnosticAtRegexp("a/a.go", "x"),
1365 env.OpenFile("a/a_ignore.go")
1367 DiagnosticAt("a/a_ignore.go", 2, 8),
1372 func TestEnableAllExperiments(t *testing.T) {
1383 func b(c bytes.Buffer) {
1389 AllExperiments: true,
1391 ).Run(t, mod, func(t *testing.T, env *Env) {
1392 // Confirm that the setting doesn't cause any warnings.
1393 env.Await(NoShowMessage())
1397 func TestSwig(t *testing.T) {
1398 t.Skipf("skipped until golang/go#37098 is resolved")
1405 -- pkg/simple/export_swig.go --
1408 func ExportSimple(x, y int) int {
1411 -- pkg/simple/simple.swigcxx --
1415 extern int gcd(int x, int y)
1434 Run(t, mod, func(t *testing.T, env *Env) {
1437 InitialWorkspaceLoad,
1438 NoDiagnosticWithMessage("", "illegal character U+0023 '#'"),
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)
1452 -- example.com@v1.2.3/go.mod --
1456 -- example.com@v1.2.3/blah/blah.go --
1460 -- random.org@v1.2.3/go.mod --
1464 -- random.org@v1.2.3/blah/blah.go --
1467 const Name = "Hello"
1478 import "example.com/blah"
1487 -- foo/foo_test.go --
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())
1504 EmptyDiagnostics("foo/foo_test.go"),
1505 NoOutstandingWork(),
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)
1523 Run(t, pkg, func(t *testing.T, env *Env) {
1524 env.OpenFile("go.mod")
1526 OutstandingWork(lsp.WorkspaceLoadFailure, "unknown directive"),
1528 env.EditBuffer("go.mod", fake.NewEdit(0, 0, 3, 0, `module mod.com
1532 // As of golang/go#42529, go.mod changes do not reload the workspace until
1534 env.SaveBufferWithoutActions("go.mod")
1536 OutstandingWork(lsp.WorkspaceLoadFailure, "invalid go version"),
1538 env.RegexpReplace("go.mod", "go 1.hello", "go 1.12")
1539 env.SaveBufferWithoutActions("go.mod")
1541 NoOutstandingWork(),
1546 func TestDeleteDirectory(t *testing.T) {
1547 testenv.NeedsGo1Point(t, 14)
1561 import "mod.com/bob"
1567 Run(t, mod, func(t *testing.T, env *Env) {
1568 env.RemoveWorkspaceFile("bob")
1570 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
1571 EmptyDiagnostics("bob/bob.go"),
1576 // Confirms that circular imports are tested and reported.
1577 func TestCircularImports(t *testing.T) {
1586 import _ "mod.com/self"
1591 import _ "mod.com/double/b"
1595 import _ "mod.com/double/a"
1599 import _ "mod.com/triple/b"
1603 import _ "mod.com/triple/c"
1607 import _ "mod.com/triple/a"
1609 Run(t, mod, func(t *testing.T, env *Env) {
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"),
1618 func TestBadImport(t *testing.T) {
1619 testenv.NeedsGo1Point(t, 14)
1633 t.Run("module", func(t *testing.T) {
1634 Run(t, mod, func(t *testing.T, env *Env) {
1636 env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `could not import nosuchpkg (no required module provides package "nosuchpkg"`),
1640 t.Run("GOPATH", func(t *testing.T) {
1644 Env: map[string]string{"GO111MODULE": "off"},
1647 ).Run(t, mod, func(t *testing.T, env *Env) {
1649 env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `cannot find package "nosuchpkg" in any of`),
1655 func TestMultipleModules_Warning(t *testing.T) {
1670 for _, go111module := range []string{"on", "auto"} {
1671 t.Run("GO111MODULE="+go111module, func(t *testing.T) {
1675 Env: map[string]string{
1676 "GO111MODULE": go111module,
1679 ).Run(t, modules, func(t *testing.T, env *Env) {
1680 env.OpenFile("a/a.go")
1681 env.OpenFile("b/go.mod")
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."),
1691 // Expect no warning if GO111MODULE=auto in a directory in GOPATH.
1692 t.Run("GOPATH_GO111MODULE_auto", func(t *testing.T) {
1696 Env: map[string]string{
1697 "GO111MODULE": "auto",
1701 ).Run(t, modules, func(t *testing.T, env *Env) {
1702 env.OpenFile("a/a.go")
1706 NoDiagnostics("a/a.go"),
1708 NoOutstandingWork(),
1714 func TestNestedModules(t *testing.T) {
1716 -- nested.com@v1.0.0/go.mod --
1720 -- nested.com@v1.0.0/hello/hello.go --
1732 require nested.com v1.0.0
1734 nested.com v1.0.0 h1:I6spLE4CgFqMdBPc+wTV2asDO2QJ3tU0YAT+jkLeN1I=
1735 nested.com v1.0.0/go.mod h1:ly53UzXQgVjSlV7wicdBB4p8BxfytuGT1Xcyv0ReJfI=
1739 import "nested.com/hello"
1747 -- nested/hello/hello.go --
1753 -- nested/hello/hello_helper.go --
1756 func helloHelper() {}
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()
1768 env.DiagnosticAtRegexp("nested/hello/hello.go", "helloHelper"),
1772 env.DiagnosticAtRegexpWithMessage("nested/hello/hello.go", "package hello", "nested module"),
1776 OutstandingWork(lsp.WorkspaceLoadFailure, "nested module"),
1782 func TestAdHocPackagesReloading(t *testing.T) {
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
1794 env.DoneWithChange(),
1795 NoLogMatching(protocol.Info, "packages=1"),
1801 func TestBuildTagChange(t *testing.T) {
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"))
1828 func TestIssue44736(t *testing.T) {
1841 fmt.Printf("This is a test %v")
1848 Run(t, files, func(t *testing.T, env *Env) {
1849 env.OpenFile("main.go")
1850 env.OpenFile("other.go")
1852 env.DiagnosticAtRegexpWithMessage("main.go", "asdf", "undeclared name"),
1853 env.DiagnosticAtRegexpWithMessage("main.go", "fdas", "undeclared name"),
1855 env.SetBufferContent("other.go", "package main\n\nasdf")
1856 // The new diagnostic in other.go should not suppress diagnostics in main.go.
1859 env.DiagnosticAtRegexpWithMessage("other.go", "asdf", "expected declaration"),
1860 env.DiagnosticAtRegexpWithMessage("main.go", "asdf", "undeclared name"),
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)
1884 Run(t, files, func(t *testing.T, env *Env) {
1885 env.OpenFile("main.go")
1887 env.DiagnosticAtRegexpWithMessage("main.go", `return x`, "wrong number of return values"),
1888 LogMatching(protocol.Error, `.*analysis fillreturns.*panicked.*`, 2),