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.
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/lsp/tests"
19 "golang.org/x/tools/internal/testenv"
22 // Use mod.com for all go.mod files due to golang/go#35230.
23 const exampleProgram = `
34 fmt.Println("Hello World.")
37 func TestDiagnosticErrorInEditedFile(t *testing.T) {
38 // This test is very basic: start with a clean Go program, make an error, and
39 // get a diagnostic for that error. However, it also demonstrates how to
40 // combine Expectations to await more complex state in the editor.
41 runner.Run(t, exampleProgram, func(t *testing.T, env *Env) {
42 // Deleting the 'n' at the end of Println should generate a single error
44 env.OpenFile("main.go")
45 env.RegexpReplace("main.go", "Printl(n)", "")
47 // Once we have gotten diagnostics for the change above, we should
48 // satisfy the DiagnosticAtRegexp assertion.
50 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
51 env.DiagnosticAtRegexp("main.go", "Printl"),
53 // Assert that this test has sent no error logs to the client. This is not
54 // strictly necessary for testing this regression, but is included here
55 // as an example of using the NoErrorLogs() expectation. Feel free to
62 func TestMissingImportDiagsClearOnFirstFile(t *testing.T) {
69 runner.Run(t, onlyMod, func(t *testing.T, env *Env) {
70 env.CreateBuffer("main.go", `package main
77 env.DiagnosticAtRegexp("main.go", "log"),
79 env.SaveBuffer("main.go")
81 EmptyDiagnostics("main.go"),
86 func TestDiagnosticErrorInNewFile(t *testing.T) {
87 const brokenFile = `package main
91 runner.Run(t, brokenFile, func(t *testing.T, env *Env) {
92 env.CreateBuffer("broken.go", brokenFile)
93 env.Await(env.DiagnosticAtRegexp("broken.go", "\"abc"))
97 // badPackage contains a duplicate definition of the 'a' const.
113 func TestDiagnosticClearingOnEdit(t *testing.T) {
114 runner.Run(t, badPackage, func(t *testing.T, env *Env) {
116 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
118 // Fix the error by editing the const name in b.go to `b`.
119 env.RegexpReplace("b.go", "(a) = 2", "b")
121 EmptyDiagnostics("a.go"),
122 EmptyDiagnostics("b.go"),
127 func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) {
128 runner.Run(t, badPackage, func(t *testing.T, env *Env) {
130 env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2"))
131 env.RemoveWorkspaceFile("b.go")
133 env.Await(EmptyDiagnostics("a.go"), EmptyDiagnostics("b.go"))
137 func TestDiagnosticClearingOnClose(t *testing.T) {
138 runner.Run(t, badPackage, func(t *testing.T, env *Env) {
139 env.CreateBuffer("c.go", `package consts
143 env.DiagnosticAtRegexp("a.go", "a = 1"),
144 env.DiagnosticAtRegexp("b.go", "a = 2"),
145 env.DiagnosticAtRegexp("c.go", "a = 3"))
146 env.CloseBuffer("c.go")
148 env.DiagnosticAtRegexp("a.go", "a = 1"),
149 env.DiagnosticAtRegexp("b.go", "a = 2"),
150 EmptyDiagnostics("c.go"))
154 // Tests golang/go#37978.
155 func TestIssue37978(t *testing.T) {
156 runner.Run(t, exampleProgram, func(t *testing.T, env *Env) {
157 // Create a new workspace-level directory and empty file.
158 env.CreateBuffer("c/c.go", "")
160 // Write the file contents with a missing import.
161 env.EditBuffer("c/c.go", fake.Edit{
164 const a = http.MethodGet
168 env.DiagnosticAtRegexp("c/c.go", "http.MethodGet"),
170 // Save file, which will organize imports, adding the expected import.
171 // Expect the diagnostics to clear.
172 env.SaveBuffer("c/c.go")
174 EmptyDiagnostics("c/c.go"),
179 // Tests golang/go#38878: good a.go, bad a_test.go, remove a_test.go but its errors remain
180 // If the file is open in the editor, this is working as intended
181 // If the file is not open in the editor, the errors go away
196 func TestA(t *testing.T) {
201 func TestRmTest38878Close(t *testing.T) {
202 runner.Run(t, test38878, func(t *testing.T, env *Env) {
203 env.OpenFile("a_test.go")
204 env.Await(DiagnosticAt("a_test.go", 5, 3))
205 env.CloseBuffer("a_test.go")
206 env.RemoveWorkspaceFile("a_test.go")
207 // diagnostics go away
208 env.Await(EmptyDiagnostics("a_test.go"))
212 func TestRmTest38878(t *testing.T) {
213 log.SetFlags(log.Lshortfile)
214 runner.Run(t, test38878, func(t *testing.T, env *Env) {
215 env.OpenFile("a_test.go")
216 env.Await(DiagnosticAt("a_test.go", 5, 3))
217 env.Sandbox.Workdir.RemoveFile(context.Background(), "a_test.go")
218 // diagnostics remain after giving gopls a chance to do something
219 // (there is not yet a better way to decide gopls isn't going
221 time.Sleep(time.Second)
222 env.Await(DiagnosticAt("a_test.go", 5, 3))
226 // TestNoMod confirms that gopls continues to work when a user adds a go.mod
227 // file to their workspace.
228 func TestNoMod(t *testing.T) {
246 t.Run("manual", func(t *testing.T) {
247 runner.Run(t, noMod, func(t *testing.T, env *Env) {
249 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
251 env.CreateBuffer("go.mod", `module mod.com
255 env.SaveBuffer("go.mod")
257 EmptyDiagnostics("main.go"),
259 var d protocol.PublishDiagnosticsParams
262 env.DiagnosticAtRegexp("bob/bob.go", "x"),
263 ReadDiagnostics("bob/bob.go", &d),
266 if len(d.Diagnostics) != 1 {
267 t.Fatalf("expected 1 diagnostic, got %v", len(d.Diagnostics))
271 t.Run("initialized", func(t *testing.T) {
272 runner.Run(t, noMod, func(t *testing.T, env *Env) {
274 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
276 env.RunGoCommand("mod", "init", "mod.com")
278 EmptyDiagnostics("main.go"),
279 env.DiagnosticAtRegexp("bob/bob.go", "x"),
284 t.Run("without workspace module", func(t *testing.T) {
286 WithModes(WithoutExperiments),
287 ).run(t, noMod, func(t *testing.T, env *Env) {
289 env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
291 if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}); err != nil {
295 EmptyDiagnostics("main.go"),
296 env.DiagnosticAtRegexp("bob/bob.go", "x"),
302 // Tests golang/go#38267.
303 func TestIssue38267(t *testing.T) {
304 const testPackage = `
312 func Hello(x string) {
320 type testStruct struct{
324 func TestHello(t *testing.T) {
325 testStructs := []*testStruct{
326 &testStruct{"hello"},
327 &testStruct{"goodbye"},
329 for y := range testStructs {
335 runner.Run(t, testPackage, func(t *testing.T, env *Env) {
336 env.OpenFile("lib_test.go")
338 DiagnosticAt("lib_test.go", 10, 2),
339 DiagnosticAt("lib_test.go", 11, 2),
341 env.OpenFile("lib.go")
342 env.RegexpReplace("lib.go", "_ = x", "var y int")
344 env.DiagnosticAtRegexp("lib.go", "y int"),
345 EmptyDiagnostics("lib_test.go"),
350 // Tests golang/go#38328.
351 func TestPackageChange_Issue38328(t *testing.T) {
352 const packageChange = `
359 runner.Run(t, packageChange, func(t *testing.T, env *Env) {
361 env.RegexpReplace("a.go", "foo", "foox")
363 // When the bug reported in #38328 was present, we didn't get erroneous
364 // file diagnostics until after the didChange message generated by the
365 // package renaming was fully processed. Therefore, in order for this
366 // test to actually exercise the bug, we must wait until that work has
369 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
370 NoDiagnostics("a.go"),
376 const testPackageWithRequire = `
395 fmt.Printf("answer: %s", bar.Answer)
399 const testPackageWithRequireProxy = `
400 -- foo.test@v1.2.3/go.mod --
404 -- foo.test@v1.2.3/bar/const.go --
410 func TestResolveDiagnosticWithDownload(t *testing.T) {
411 runner.Run(t, testPackageWithRequire, func(t *testing.T, env *Env) {
412 env.OpenFile("print.go")
413 // Check that gopackages correctly loaded this dependency. We should get a
414 // diagnostic for the wrong formatting type.
415 // TODO: we should be able to easily also match the diagnostic message.
416 env.Await(env.DiagnosticAtRegexp("print.go", "fmt.Printf"))
417 }, WithProxyFiles(testPackageWithRequireProxy))
420 func TestMissingDependency(t *testing.T) {
421 runner.Run(t, testPackageWithRequire, func(t *testing.T, env *Env) {
422 env.OpenFile("print.go")
423 env.Await(LogMatching(protocol.Error, "initial workspace load failed", 1))
427 // Tests golang/go#36951.
428 func TestAdHocPackages_Issue36951(t *testing.T) {
437 runner.Run(t, adHoc, func(t *testing.T, env *Env) {
438 env.OpenFile("b/b.go")
439 env.Await(env.DiagnosticAtRegexp("b/b.go", "x"))
443 // Tests golang/go#37984: GOPATH should be read from the go command.
444 func TestNoGOPATH_Issue37984(t *testing.T) {
450 fmt.Println("Hello World")
453 editorConfig := EditorConfig{Env: map[string]string{"GOPATH": ""}}
454 withOptions(editorConfig).run(t, files, func(t *testing.T, env *Env) {
455 env.OpenFile("main.go")
456 env.Await(env.DiagnosticAtRegexp("main.go", "fmt"))
457 env.SaveBuffer("main.go")
458 env.Await(EmptyDiagnostics("main.go"))
462 // Tests golang/go#38669.
463 func TestEqualInEnv_Issue38669(t *testing.T) {
477 editorConfig := EditorConfig{Env: map[string]string{"GOFLAGS": "-tags=foo"}}
478 withOptions(editorConfig).run(t, files, func(t *testing.T, env *Env) {
479 env.OpenFile("main.go")
480 env.OrganizeImports("main.go")
481 env.Await(EmptyDiagnostics("main.go"))
485 // Tests golang/go#38467.
486 func TestNoSuggestedFixesForGeneratedFiles_Issue38467(t *testing.T) {
494 // Code generated by generator.go. DO NOT EDIT.
497 for i, _ := range []string{} {
502 runner.Run(t, generated, func(t *testing.T, env *Env) {
503 env.OpenFile("main.go")
504 original := env.ReadWorkspaceFile("main.go")
505 var d protocol.PublishDiagnosticsParams
508 DiagnosticAt("main.go", 5, 8),
509 ReadDiagnostics("main.go", &d),
512 // Apply fixes and save the buffer.
513 env.ApplyQuickFixes("main.go", d.Diagnostics)
514 env.SaveBuffer("main.go")
515 fixed := env.ReadWorkspaceFile("main.go")
516 if original != fixed {
517 t.Fatalf("generated file was changed by quick fixes:\n%s", tests.Diff(original, fixed))
522 // Expect a module/GOPATH error if there is an error in the file at startup.
523 // Tests golang/go#37279.
524 func TestShowMessage_Issue37279(t *testing.T) {
533 runner.Run(t, noModule, func(t *testing.T, env *Env) {
535 env.Await(env.DiagnosticAtRegexp("a.go", "fmt.Printl"), ShownMessage(""))
539 // Expect no module/GOPATH error if there is no error in the file.
540 // Tests golang/go#37279.
541 func TestNoShowMessage_Issue37279(t *testing.T) {
549 runner.Run(t, noModule, func(t *testing.T, env *Env) {
553 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
554 NoDiagnostics("a.go"),
558 // introduce an error, expect no Show Message
559 env.RegexpReplace("a.go", "func", "fun")
560 env.Await(env.DiagnosticAtRegexp("a.go", "fun"), NoShowMessage())
564 func TestNonGoFolder(t *testing.T) {
569 for _, go111module := range []string{"on", "off", ""} {
570 t.Run(fmt.Sprintf("GO111MODULE_%v", go111module), func(t *testing.T) {
571 withOptions(EditorConfig{
572 Env: map[string]string{"GO111MODULE": go111module},
573 }).run(t, files, func(t *testing.T, env *Env) {
574 env.OpenFile("hello.txt")
577 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
586 // Tests golang/go#38602.
587 func TestNonexistentFileDiagnostics_Issue38602(t *testing.T) {
604 runner.Run(t, collision, func(t *testing.T, env *Env) {
605 env.OpenFile("x/main.go")
607 env.DiagnosticAtRegexp("x/main.go", "fmt.Println"),
609 env.OrganizeImports("x/main.go")
610 // span.Parse misparses the error message when multiple packages are
611 // defined in the same directory, creating a garbage filename.
612 // Previously, we would send diagnostics for this nonexistent file.
613 // This test checks that we don't send diagnostics for this file.
614 dir, err := os.Getwd()
618 badFile := fmt.Sprintf("%s/found packages main (main.go) and x (x.go) in %s/src/x", dir, env.Sandbox.GOPATH())
621 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
622 EmptyDiagnostics("x/main.go"),
624 NoDiagnostics(badFile),
629 const ardanLabsProxy = `
630 -- github.com/ardanlabs/conf@v1.2.3/go.mod --
631 module github.com/ardanlabs/conf
634 -- github.com/ardanlabs/conf@v1.2.3/conf.go --
637 var ErrHelpWanted error
640 // Test for golang/go#38211.
641 func Test_Issue38211(t *testing.T) {
642 testenv.NeedsGo1Point(t, 14)
651 import "github.com/ardanlabs/conf"
654 _ = conf.ErrHelpWanted
658 WithProxyFiles(ardanLabsProxy),
659 ).run(t, ardanLabs, func(t *testing.T, env *Env) {
660 // Expect a diagnostic with a suggested fix to add
661 // "github.com/ardanlabs/conf" to the go.mod file.
662 env.OpenFile("go.mod")
663 env.OpenFile("main.go")
664 var d protocol.PublishDiagnosticsParams
667 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
668 ReadDiagnostics("main.go", &d),
671 env.ApplyQuickFixes("main.go", d.Diagnostics)
672 env.SaveBuffer("go.mod")
674 EmptyDiagnostics("main.go"),
676 // Comment out the line that depends on conf and expect a
677 // diagnostic and a fix to remove the import.
678 env.RegexpReplace("main.go", "_ = conf.ErrHelpWanted", "//_ = conf.ErrHelpWanted")
680 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
682 env.SaveBuffer("main.go")
683 // Expect a diagnostic and fix to remove the dependency in the go.mod.
684 env.Await(EmptyDiagnostics("main.go"))
687 env.DiagnosticAtRegexp("go.mod", "require github.com/ardanlabs/conf"),
688 ReadDiagnostics("go.mod", &d),
691 env.ApplyQuickFixes("go.mod", d.Diagnostics)
692 env.SaveBuffer("go.mod")
694 EmptyDiagnostics("go.mod"),
696 // Uncomment the lines and expect a new diagnostic for the import.
697 env.RegexpReplace("main.go", "//_ = conf.ErrHelpWanted", "_ = conf.ErrHelpWanted")
698 env.SaveBuffer("main.go")
700 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
705 // Test for golang/go#38207.
706 func TestNewModule_Issue38207(t *testing.T) {
707 testenv.NeedsGo1Point(t, 14)
716 WithProxyFiles(ardanLabsProxy),
717 ).run(t, emptyFile, func(t *testing.T, env *Env) {
718 env.OpenFile("main.go")
719 env.OpenFile("go.mod")
720 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
722 import "github.com/ardanlabs/conf"
725 _ = conf.ErrHelpWanted
728 env.SaveBuffer("main.go")
729 var d protocol.PublishDiagnosticsParams
732 env.DiagnosticAtRegexp("main.go", `"github.com/ardanlabs/conf"`),
733 ReadDiagnostics("main.go", &d),
736 env.ApplyQuickFixes("main.go", d.Diagnostics)
738 EmptyDiagnostics("main.go"),
743 // Test for golang/go#36960.
744 func TestNewFileBadImports_Issue36960(t *testing.T) {
745 testenv.NeedsGo1Point(t, 14)
746 const simplePackage = `
760 runner.Run(t, simplePackage, func(t *testing.T, env *Env) {
761 env.OpenFile("a/a1.go")
762 env.CreateBuffer("a/a2.go", ``)
763 if err := env.Editor.SaveBufferWithoutActions(env.Ctx, "a/a2.go"); err != nil {
768 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
769 NoDiagnostics("a/a1.go"),
772 env.EditBuffer("a/a2.go", fake.NewEdit(0, 0, 0, 0, `package a`))
775 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
776 NoDiagnostics("a/a1.go"),
782 // This test tries to replicate the workflow of a user creating a new x test.
783 // It also tests golang/go#39315.
784 func TestManuallyCreatingXTest(t *testing.T) {
785 // Only for 1.15 because of golang/go#37971.
786 testenv.NeedsGo1Point(t, 15)
788 // Create a package that already has a test variant (in-package test).
789 const testVariant = `
800 -- hello/hello_test.go --
805 func TestHello(t *testing.T) {
810 runner.Run(t, testVariant, func(t *testing.T, env *Env) {
811 // Open the file, triggering the workspace load.
812 // There are errors in the code to ensure all is working as expected.
813 env.OpenFile("hello/hello.go")
815 env.DiagnosticAtRegexp("hello/hello.go", "x"),
816 env.DiagnosticAtRegexp("hello/hello_test.go", "x"),
819 // Create an empty file with the intention of making it an x test.
820 // This resembles a typical flow in an editor like VS Code, in which
821 // a user would create an empty file and add content, saving
823 // TODO(rstambler): There might be more edge cases here, as file
824 // content can be added incrementally.
825 env.CreateBuffer("hello/hello_x_test.go", ``)
827 // Save the empty file (no actions since formatting will fail).
828 env.Editor.SaveBufferWithoutActions(env.Ctx, "hello/hello_x_test.go")
830 // Add the content. The missing import is for the package under test.
831 env.EditBuffer("hello/hello_x_test.go", fake.NewEdit(0, 0, 0, 0, `package hello_test
837 func TestHello(t *testing.T) {
841 // Expect a diagnostic for the missing import. Save, which should
842 // trigger import organization. The diagnostic should clear.
844 env.DiagnosticAtRegexp("hello/hello_x_test.go", "hello.Hello"),
846 env.SaveBuffer("hello/hello_x_test.go")
848 EmptyDiagnostics("hello/hello_x_test.go"),
853 // Reproduce golang/go#40690.
854 func TestCreateOnlyXTest(t *testing.T) {
855 t.Skip("golang/go#40690 is not resolved yet.")
862 -- foo/bar_test.go --
864 run(t, mod, func(t *testing.T, env *Env) {
865 env.OpenFile("foo/bar_test.go")
866 env.EditBuffer("foo/bar_test.go", fake.NewEdit(0, 0, 0, 0, `package foo
869 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
871 env.RegexpReplace("foo/bar_test.go", "package foo", "package foo_test")
874 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 2),
881 func TestChangePackageName(t *testing.T) {
882 t.Skip("This issue hasn't been fixed yet. See golang.org/issue/41061.")
889 -- foo/bar_test.go --
892 run(t, mod, func(t *testing.T, env *Env) {
893 env.OpenFile("foo/bar_test.go")
894 env.RegexpReplace("foo/bar_test.go", "package foo_", "package foo_test")
895 env.SaveBuffer("foo/bar_test.go")
898 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
899 NoDiagnostics("foo/bar_test.go"),
902 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
903 NoDiagnostics("foo/foo.go"),
909 // Reproduces golang/go#40825.
910 func TestEmptyGOPATHXTest_40825(t *testing.T) {
917 withOptions(InGOPATH()).run(t, files, func(t *testing.T, env *Env) {
918 env.OpenFile("x_test.go")
919 env.EditBuffer("x_test.go", fake.NewEdit(0, 0, 0, 0, "pack"))
921 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
927 func TestIgnoredFiles(t *testing.T) {
938 runner.Run(t, ws, func(t *testing.T, env *Env) {
939 env.OpenFile("_foo/x.go")
942 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
943 NoDiagnostics("_foo/x.go"),
948 // Partially reproduces golang/go#38977, moving a file between packages.
949 // It also gets hit by some go command bug fixed in 1.15, but we don't
950 // care about that so much here.
951 func TestDeletePackage(t *testing.T) {
976 runner.Run(t, ws, func(t *testing.T, env *Env) {
977 env.OpenFile("b/b.go")
978 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1))
979 // Delete c/c.go, the only file in package c.
980 env.RemoveWorkspaceFile("c/c.go")
982 // We should still get diagnostics for files that exist.
983 env.RegexpReplace("b/b.go", `a.A`, "a.Nonexistant")
984 env.Await(env.DiagnosticAtRegexp("b/b.go", `Nonexistant`))
988 // This is a copy of the scenario_default/quickfix_empty_files.txt test from
989 // govim. Reproduces golang/go#39646.
990 func TestQuickFixEmptyFiles(t *testing.T) {
991 testenv.NeedsGo1Point(t, 15)
999 // To fully recreate the govim tests, we create files by inserting
1000 // a newline, adding to the file, and then deleting the newline.
1001 // Wait for each event to process to avoid cancellations and force
1003 writeGoVim := func(env *Env, name, content string) {
1004 env.WriteWorkspaceFile(name, "")
1005 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1))
1007 env.CreateBuffer(name, "\n")
1008 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1))
1010 env.EditBuffer(name, fake.NewEdit(1, 0, 1, 0, content))
1011 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1))
1013 env.EditBuffer(name, fake.NewEdit(0, 0, 1, 0, ""))
1014 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1))
1017 const p = `package p; func DoIt(s string) {};`
1018 const main = `package main
1026 // A simple version of the test that reproduces most of the problems it
1028 t.Run("short", func(t *testing.T) {
1029 runner.Run(t, mod, func(t *testing.T, env *Env) {
1030 writeGoVim(env, "p/p.go", p)
1031 writeGoVim(env, "main.go", main)
1032 env.Await(env.DiagnosticAtRegexp("main.go", "5"))
1036 // A full version that replicates the whole flow of the test.
1037 t.Run("full", func(t *testing.T) {
1038 runner.Run(t, mod, func(t *testing.T, env *Env) {
1039 writeGoVim(env, "p/p.go", p)
1040 writeGoVim(env, "main.go", main)
1041 writeGoVim(env, "p/p_test.go", `package p
1045 func TestDoIt(t *testing.T) {
1049 writeGoVim(env, "p/x_test.go", `package p_test
1057 func TestDoIt(t *testing.T) {
1062 env.DiagnosticAtRegexp("main.go", "5"),
1063 env.DiagnosticAtRegexp("p/p_test.go", "5"),
1064 env.DiagnosticAtRegexp("p/x_test.go", "5"),
1066 env.RegexpReplace("p/p.go", "s string", "i int")
1068 EmptyDiagnostics("main.go"),
1069 EmptyDiagnostics("p/p_test.go"),
1070 EmptyDiagnostics("p/x_test.go"),
1076 func TestSingleFile(t *testing.T) {
1089 runner.Run(t, mod, func(t *testing.T, env *Env) {
1090 env.OpenFile("a/a.go")
1092 env.DiagnosticAtRegexp("a/a.go", "x"),
1094 }, WithoutWorkspaceFolders())
1097 // Reproduces the case described in
1098 // https://github.com/golang/go/issues/39296#issuecomment-652058883.
1099 func TestPkgm(t *testing.T) {
1114 runner.Run(t, basic, func(t *testing.T, env *Env) {
1115 testenv.NeedsGo1Point(t, 15)
1117 env.WriteWorkspaceFile("foo/foo_test.go", `package main
1122 env.OpenFile("foo/foo_test.go")
1123 env.RegexpReplace("foo/foo_test.go", `package main`, `package foo`)
1126 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
1127 NoDiagnostics("foo/foo.go"),
1133 func TestClosingBuffer(t *testing.T) {
1144 runner.Run(t, basic, func(t *testing.T, env *Env) {
1145 env.Editor.CreateBuffer(env.Ctx, "foo.go", `package main`)
1147 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
1149 env.CloseBuffer("foo.go")
1152 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidClose), 1),
1153 NoLogMatching(protocol.Info, "packages=0"),
1159 // Reproduces golang/go#38424.
1160 func TestCutAndPaste(t *testing.T) {
1169 runner.Run(t, basic, func(t *testing.T, env *Env) {
1170 env.CreateBuffer("main.go", "")
1171 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1))
1173 env.Editor.SaveBufferWithoutActions(env.Ctx, "main.go")
1175 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
1176 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
1179 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1184 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1))
1186 env.SaveBuffer("main.go")
1188 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 2),
1189 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 2),
1192 env.EditBuffer("main.go", fake.NewEdit(0, 0, 4, 0, ""))
1193 env.Await(CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 2))
1195 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main
1202 env.DiagnosticAtRegexp("main.go", "x"),
1207 // Reproduces golang/go#39763.
1208 func TestInvalidPackageName(t *testing.T) {
1209 testenv.NeedsGo1Point(t, 15)
1211 const pkgDefault = `
1219 runner.Run(t, pkgDefault, func(t *testing.T, env *Env) {
1220 env.OpenFile("main.go")
1222 env.DiagnosticAtRegexp("main.go", "default"),
1227 // This tests the functionality of the "limitWorkspaceScope"
1228 func TestLimitWorkspaceScope(t *testing.T) {
1243 withOptions(WithRootPath("a")).run(t, mod, func(t *testing.T, env *Env) {
1244 env.OpenFile("a/main.go")
1246 env.DiagnosticAtRegexp("main.go", "x"),
1249 withOptions(WithRootPath("a"), WithLimitWorkspaceScope()).run(t, mod, func(t *testing.T, env *Env) {
1250 env.OpenFile("a/main.go")
1252 NoDiagnostics("main.go"),
1257 func TestStaticcheckDiagnostic(t *testing.T) {
1277 EditorConfig{EnableStaticcheck: true},
1278 ).run(t, files, func(t *testing.T, env *Env) {
1279 env.OpenFile("main.go")
1280 // Staticcheck should generate a diagnostic to simplify this literal.
1281 env.Await(env.DiagnosticAtRegexp("main.go", `t{"msg"}`))
1285 // Test some secondary diagnostics
1286 func TestSecondaryDiagnostics(t *testing.T) {
1299 runner.Run(t, dir, func(t *testing.T, env *Env) {
1300 log.SetFlags(log.Lshortfile)
1301 env.OpenFile("main.go")
1302 env.OpenFile("other.go")
1303 x := env.DiagnosticsFor("main.go")
1305 t.Fatalf("expected 1 diagnostic, got none")
1307 if len(x.Diagnostics) != 1 {
1308 t.Fatalf("main.go, got %d diagnostics, expected 1", len(x.Diagnostics))
1310 keep := x.Diagnostics[0]
1311 y := env.DiagnosticsFor("other.go")
1312 if len(y.Diagnostics) != 1 {
1313 t.Fatalf("other.go: got %d diagnostics, expected 1", len(y.Diagnostics))
1315 if len(y.Diagnostics[0].RelatedInformation) != 1 {
1316 t.Fatalf("got %d RelatedInformations, expected 1", len(y.Diagnostics[0].RelatedInformation))
1318 // check that the RelatedInformation matches the error from main.go
1319 c := y.Diagnostics[0].RelatedInformation[0]
1320 if c.Location.Range != keep.Range {
1321 t.Errorf("locations don't match. Got %v expected %v", c.Location.Range, keep.Range)
1326 func TestNotifyOrphanedFiles(t *testing.T) {
1327 // Need GO111MODULE=on for this test to work with Go 1.12.
1328 testenv.NeedsGo1Point(t, 13)
1350 run(t, files, func(t *testing.T, env *Env) {
1351 env.OpenFile("a/a.go")
1353 env.DiagnosticAtRegexp("a/a.go", "x"),
1355 env.OpenFile("a/a_ignore.go")
1357 DiagnosticAt("a/a_ignore.go", 2, 8),
1362 func TestEnableAllExperiments(t *testing.T) {
1372 func b(c bytes.Buffer) {
1378 AllExperiments: true,
1380 ).run(t, mod, func(t *testing.T, env *Env) {
1381 // Confirm that the setting doesn't cause any warnings.
1382 env.Await(NoShowMessage())
1386 func TestSwig(t *testing.T) {
1387 t.Skipf("skipped until golang/go#37098 is resolved")
1392 -- pkg/simple/export_swig.go --
1395 func ExportSimple(x, y int) int {
1398 -- pkg/simple/simple.swigcxx --
1402 extern int gcd(int x, int y)
1421 run(t, mod, func(t *testing.T, env *Env) {
1424 InitialWorkspaceLoad,
1425 NoDiagnosticWithMessage("illegal character U+0023 '#'"),
1431 // When foo_test.go is opened, gopls will object to the borked package name.
1432 // This test asserts that when the package name is fixed, gopls will soon after
1433 // have no more complaints about it.
1434 // https://github.com/golang/go/issues/41061
1435 func TestRenamePackage(t *testing.T) {
1436 t.Skip("Waiting for the fix that makes this pass: https://github.com/golang/go/issues/41061")
1446 runner.Run(t, contents, func(t *testing.T, env *Env) {
1447 env.OpenFile("foo_test.go")
1448 env.RegexpReplace("foo_test.go", "foo_", "foo_test")
1449 env.SaveBuffer("foo_test.go")
1451 EmptyDiagnostics("foo_test.go"),