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/command"
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 func TestMain(m *testing.M) {
26 func TestDisablingCodeLens(t *testing.T) {
43 //go:generate stringer -type=Number
47 enabled map[string]bool
55 label: "generate disabled",
56 enabled: map[string]bool{string(command.Generate): false},
60 for _, test := range tests {
61 t.Run(test.label, func(t *testing.T) {
64 CodeLenses: test.enabled,
66 ).Run(t, workspace, func(t *testing.T, env *Env) {
67 env.OpenFile("lib.go")
68 lens := env.CodeLens("lib.go")
69 if gotCodeLens := len(lens) > 0; gotCodeLens != test.wantCodeLens {
70 t.Errorf("got codeLens: %t, want %t", gotCodeLens, test.wantCodeLens)
77 // This test confirms the full functionality of the code lenses for updating
78 // dependencies in a go.mod file. It checks for the code lens that suggests
79 // an update and then executes the command associated with that code lens. A
80 // regression test for golang/go#39446.
81 func TestUpgradeCodelens(t *testing.T) {
82 const proxyWithLatest = `
83 -- golang.org/x/hello@v1.3.3/go.mod --
84 module golang.org/x/hello
87 -- golang.org/x/hello@v1.3.3/hi/hi.go --
91 -- golang.org/x/hello@v1.2.3/go.mod --
92 module golang.org/x/hello
95 -- golang.org/x/hello@v1.2.3/hi/hi.go --
101 const shouldUpdateDep = `
107 require golang.org/x/hello v1.2.3
109 golang.org/x/hello v1.2.3 h1:jOtNXLsiCuLzU6KM3wRHidpc29IxcKpofHZiOW1hYKA=
110 golang.org/x/hello v1.2.3/go.mod h1:X79D30QqR94cGK8aIhQNhCZLq4mIr5Gimj5qekF08rY=
114 import "golang.org/x/hello/hi"
121 const wantGoMod = `module mod.com
125 require golang.org/x/hello v1.3.3
128 for _, commandTitle := range []string{
129 "Upgrade transitive dependencies",
130 "Upgrade direct dependencies",
132 t.Run(commandTitle, func(t *testing.T) {
134 ProxyFiles(proxyWithLatest),
135 ).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
136 env.OpenFile("go.mod")
137 var lens protocol.CodeLens
139 for _, l := range env.CodeLens("go.mod") {
140 if l.Command.Title == commandTitle {
146 t.Fatalf("found no command with the title %s", commandTitle)
148 if _, err := env.Editor.ExecuteCommand(env.Ctx, &protocol.ExecuteCommandParams{
149 Command: lens.Command.Command,
150 Arguments: lens.Command.Arguments,
154 env.Await(env.DoneWithChangeWatchedFiles())
155 if got := env.Editor.BufferText("go.mod"); got != wantGoMod {
156 t.Fatalf("go.mod upgrade failed:\n%s", tests.Diff(t, wantGoMod, got))
161 t.Run("Upgrade individual dependency", func(t *testing.T) {
162 WithOptions(ProxyFiles(proxyWithLatest)).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) {
163 env.OpenFile("go.mod")
164 env.ExecuteCodeLensCommand("go.mod", command.CheckUpgrades)
165 d := &protocol.PublishDiagnosticsParams{}
166 env.Await(OnceMet(env.DiagnosticAtRegexpWithMessage("go.mod", `require`, "can be upgraded"),
167 ReadDiagnostics("go.mod", d)))
168 env.ApplyQuickFixes("go.mod", d.Diagnostics)
169 env.Await(env.DoneWithChangeWatchedFiles())
170 if got := env.Editor.BufferText("go.mod"); got != wantGoMod {
171 t.Fatalf("go.mod upgrade failed:\n%s", tests.Diff(t, wantGoMod, got))
177 func TestUnusedDependenciesCodelens(t *testing.T) {
178 testenv.NeedsGo1Point(t, 14)
180 -- golang.org/x/hello@v1.0.0/go.mod --
181 module golang.org/x/hello
184 -- golang.org/x/hello@v1.0.0/hi/hi.go --
188 -- golang.org/x/unused@v1.0.0/go.mod --
189 module golang.org/x/unused
192 -- golang.org/x/unused@v1.0.0/nouse/nouse.go --
198 const shouldRemoveDep = `
204 require golang.org/x/hello v1.0.0
205 require golang.org/x/unused v1.0.0
207 golang.org/x/hello v1.0.0 h1:qbzE1/qT0/zojAMd/JcPsO2Vb9K4Bkeyq0vB2JGMmsw=
208 golang.org/x/hello v1.0.0/go.mod h1:WW7ER2MRNXWA6c8/4bDIek4Hc/+DofTrMaQQitGXcco=
209 golang.org/x/unused v1.0.0 h1:LecSbCn5P3vTcxubungSt1Pn4D/WocCaiWOPDC0y0rw=
210 golang.org/x/unused v1.0.0/go.mod h1:ihoW8SgWzugwwj0N2SfLfPZCxTB1QOVfhMfB5PWTQ8U=
214 import "golang.org/x/hello/hi"
220 WithOptions(ProxyFiles(proxy)).Run(t, shouldRemoveDep, func(t *testing.T, env *Env) {
221 env.OpenFile("go.mod")
222 env.ExecuteCodeLensCommand("go.mod", command.Tidy)
223 env.Await(env.DoneWithChangeWatchedFiles())
224 got := env.Editor.BufferText("go.mod")
225 const wantGoMod = `module mod.com
229 require golang.org/x/hello v1.0.0
231 if got != wantGoMod {
232 t.Fatalf("go.mod tidy failed:\n%s", tests.Diff(t, wantGoMod, got))
237 func TestRegenerateCgo(t *testing.T) {
238 testenv.NeedsTool(t, "cgo")
239 testenv.NeedsGo1Point(t, 15)
250 int fortythree() { return 42; }
258 Run(t, workspace, func(t *testing.T, env *Env) {
259 // Open the file. We have a nonexistant symbol that will break cgo processing.
260 env.OpenFile("cgo.go")
261 env.Await(env.DiagnosticAtRegexpWithMessage("cgo.go", ``, "go list failed to return CompiledGoFiles"))
263 // Fix the C function name. We haven't regenerated cgo, so nothing should be fixed.
264 env.RegexpReplace("cgo.go", `int fortythree`, "int fortytwo")
265 env.SaveBuffer("cgo.go")
268 env.DiagnosticAtRegexpWithMessage("cgo.go", ``, "go list failed to return CompiledGoFiles"),
271 // Regenerate cgo, fixing the diagnostic.
272 env.ExecuteCodeLensCommand("cgo.go", command.RegenerateCgo)
273 env.Await(EmptyDiagnostics("cgo.go"))
277 func TestGCDetails(t *testing.T) {
279 t.Skip("Flaky test -- see golang.org/issue/44099")
281 testenv.NeedsGo1Point(t, 15)
282 if runtime.GOOS == "android" {
283 t.Skipf("the gc details code lens doesn't work on Android")
303 CodeLenses: map[string]bool{
306 // TestGCDetails seems to suffer from poor performance on certain builders. Give it some more time to complete.
307 Timeout(60*time.Second),
308 ).Run(t, mod, func(t *testing.T, env *Env) {
309 env.OpenFile("main.go")
310 env.ExecuteCodeLensCommand("main.go", command.GCDetails)
311 d := &protocol.PublishDiagnosticsParams{}
314 DiagnosticAt("main.go", 6, 12),
315 ReadDiagnostics("main.go", d),
318 // Confirm that the diagnostics come from the gc details code lens.
320 for _, d := range d.Diagnostics {
321 if d.Severity != protocol.SeverityInformation {
322 t.Fatalf("unexpected diagnostic severity %v, wanted Information", d.Severity)
324 if strings.Contains(d.Message, "x escapes") {
329 t.Fatalf(`expected to find diagnostic with message "escape(x escapes to heap)", found none`)
332 // Editing a buffer should cause gc_details diagnostics to disappear, since
333 // they only apply to saved buffers.
334 env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, "\n\n"))
335 env.Await(EmptyDiagnostics("main.go"))
337 // Saving a buffer should re-format back to the original state, and
338 // re-enable the gc_details diagnostics.
339 env.SaveBuffer("main.go")
340 env.Await(DiagnosticAt("main.go", 6, 12))
342 // Toggle the GC details code lens again so now it should be off.
343 env.ExecuteCodeLensCommand("main.go", command.GCDetails)
345 EmptyDiagnostics("main.go"),