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.
12 "golang.org/x/tools/internal/lsp/protocol"
13 "golang.org/x/tools/internal/lsp/source"
14 "golang.org/x/tools/internal/lsp/tests"
15 "golang.org/x/tools/internal/testenv"
18 func TestDisablingCodeLens(t *testing.T) {
33 //go:generate stringer -type=Number
37 enabled map[string]bool
45 label: "generate disabled",
46 enabled: map[string]bool{source.CommandGenerate.Name: false},
50 for _, test := range tests {
51 t.Run(test.label, func(t *testing.T) {
54 CodeLens: test.enabled,
56 ).run(t, workspace, func(t *testing.T, env *Env) {
57 env.OpenFile("lib.go")
58 lens := env.CodeLens("lib.go")
59 if gotCodeLens := len(lens) > 0; gotCodeLens != test.wantCodeLens {
60 t.Errorf("got codeLens: %t, want %t", gotCodeLens, test.wantCodeLens)
67 // This test confirms the full functionality of the code lenses for updating
68 // dependencies in a go.mod file. It checks for the code lens that suggests
69 // an update and then executes the command associated with that code lens. A
70 // regression test for golang/go#39446.
71 func TestUpdateCodelens(t *testing.T) {
72 const proxyWithLatest = `
73 -- golang.org/x/hello@v1.3.3/go.mod --
74 module golang.org/x/hello
77 -- golang.org/x/hello@v1.3.3/hi/hi.go --
81 -- golang.org/x/hello@v1.2.3/go.mod --
82 module golang.org/x/hello
85 -- golang.org/x/hello@v1.2.3/hi/hi.go --
91 const shouldUpdateDep = `
97 require golang.org/x/hello v1.2.3
99 golang.org/x/hello v1.2.3 h1:jOtNXLsiCuLzU6KM3wRHidpc29IxcKpofHZiOW1hYKA=
100 golang.org/x/hello v1.2.3/go.mod h1:X79D30QqR94cGK8aIhQNhCZLq4mIr5Gimj5qekF08rY=
104 import "golang.org/x/hello/hi"
110 runner.Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
111 env.OpenFile("go.mod")
112 lenses := env.CodeLens("go.mod")
113 want := "Upgrade dependency to v1.3.3"
114 var found protocol.CodeLens
115 for _, lens := range lenses {
116 if lens.Command.Title == want {
121 if found.Command.Command == "" {
122 t.Fatalf("did not find lens %q, got %v", want, lenses)
124 if _, err := env.Editor.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
125 Command: found.Command.Command,
126 Arguments: found.Command.Arguments,
130 env.Await(NoOutstandingWork())
131 got := env.ReadWorkspaceFile("go.mod")
132 const wantGoMod = `module mod.com
136 require golang.org/x/hello v1.3.3
138 if got != wantGoMod {
139 t.Fatalf("go.mod upgrade failed:\n%s", tests.Diff(wantGoMod, got))
141 }, WithProxyFiles(proxyWithLatest))
144 func TestUnusedDependenciesCodelens(t *testing.T) {
145 testenv.NeedsGo1Point(t, 14)
147 -- golang.org/x/hello@v1.0.0/go.mod --
148 module golang.org/x/hello
151 -- golang.org/x/hello@v1.0.0/hi/hi.go --
155 -- golang.org/x/unused@v1.0.0/go.mod --
156 module golang.org/x/unused
159 -- golang.org/x/unused@v1.0.0/nouse/nouse.go --
165 const shouldRemoveDep = `
171 require golang.org/x/hello v1.0.0
172 require golang.org/x/unused v1.0.0
176 import "golang.org/x/hello/hi"
182 runner.Run(t, shouldRemoveDep, func(t *testing.T, env *Env) {
183 env.OpenFile("go.mod")
184 env.ExecuteCodeLensCommand("go.mod", source.CommandTidy)
185 env.Await(NoOutstandingWork())
186 got := env.ReadWorkspaceFile("go.mod")
187 const wantGoMod = `module mod.com
191 require golang.org/x/hello v1.0.0
193 if got != wantGoMod {
194 t.Fatalf("go.mod tidy failed:\n%s", tests.Diff(wantGoMod, got))
196 }, WithProxyFiles(proxy))
199 func TestRegenerateCgo(t *testing.T) {
200 testenv.NeedsTool(t, "cgo")
201 testenv.NeedsGo1Point(t, 15)
210 int fortythree() { return 42; }
218 runner.Run(t, workspace, func(t *testing.T, env *Env) {
219 // Open the file. We should have a nonexistant symbol.
220 env.OpenFile("cgo.go")
221 env.Await(env.DiagnosticAtRegexp("cgo.go", `C\.(fortytwo)`)) // could not determine kind of name for C.fortytwo
223 // Fix the C function name. We haven't regenerated cgo, so nothing should be fixed.
224 env.RegexpReplace("cgo.go", `int fortythree`, "int fortytwo")
225 env.SaveBuffer("cgo.go")
226 env.Await(env.DiagnosticAtRegexp("cgo.go", `C\.(fortytwo)`))
228 // Regenerate cgo, fixing the diagnostic.
229 env.ExecuteCodeLensCommand("cgo.go", source.CommandRegenerateCgo)
230 env.Await(EmptyDiagnostics("cgo.go"))
234 func TestGCDetails(t *testing.T) {
235 testenv.NeedsGo1Point(t, 15)
236 if runtime.GOOS == "android" {
237 t.Skipf("the gc details code lens doesn't work on Android")
257 CodeLens: map[string]bool{
260 ).run(t, mod, func(t *testing.T, env *Env) {
261 env.OpenFile("main.go")
262 env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
263 d := &protocol.PublishDiagnosticsParams{}
266 DiagnosticAt("main.go", 6, 12),
267 ReadDiagnostics("main.go", d),
270 // Confirm that the diagnostics come from the gc details code lens.
272 for _, d := range d.Diagnostics {
273 if d.Severity != protocol.SeverityInformation {
274 t.Fatalf("unexpected diagnostic severity %v, wanted Information", d.Severity)
276 if strings.Contains(d.Message, "x escapes") {
281 t.Fatalf(`expected to find diagnostic with message "escape(x escapes to heap)", found none`)
283 // Toggle the GC details code lens again so now it should be off.
284 env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails)
286 EmptyDiagnostics("main.go"),