| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package misc | |
| import ( | |
| "testing" | |
| "golang.org/x/tools/gopls/internal/settings" | |
| "golang.org/x/tools/gopls/internal/test/compare" | |
| . "golang.org/x/tools/gopls/internal/test/integration" | |
| "golang.org/x/tools/gopls/internal/protocol" | |
| ) | |
| // A basic test for fillstruct, now that it uses a command and supports resolve edits. | |
| func TestFillStruct(t *testing.T) { | |
| tc := []struct { | |
| name string | |
| capabilities string | |
| wantCommand bool | |
| }{ | |
| {"default", "{}", false}, | |
| {"no data support", `{"textDocument": {"codeAction": {"dataSupport": false, "resolveSupport": {"properties": ["edit"]}}}}`, true}, | |
| {"no resolve support", `{"textDocument": {"codeAction": {"dataSupport": true, "resolveSupport": {"properties": []}}}}`, true}, | |
| {"data and resolve support", `{"textDocument": {"codeAction": {"dataSupport": true, "resolveSupport": {"properties": ["edit"]}}}}`, false}, | |
| } | |
| const basic = ` | |
| -- go.mod -- | |
| module mod.com | |
| go 1.14 | |
| -- main.go -- | |
| package main | |
| type Info struct { | |
| WordCounts map[string]int | |
| Words []string | |
| } | |
| func Foo() { | |
| _ = Info{} | |
| } | |
| ` | |
| for _, tt := range tc { | |
| t.Run(tt.name, func(t *testing.T) { | |
| runner := WithOptions(CapabilitiesJSON([]byte(tt.capabilities))) | |
| runner.Run(t, basic, func(t *testing.T, env *Env) { | |
| env.OpenFile("main.go") | |
| fixes, err := env.Editor.CodeActions(env.Ctx, env.RegexpSearch("main.go", "Info{}"), nil, settings.RefactorRewriteFillStruct) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| if len(fixes) != 1 { | |
| t.Fatalf("expected 1 code action, got %v", len(fixes)) | |
| } | |
| if tt.wantCommand { | |
| if fixes[0].Command == nil || fixes[0].Data != nil { | |
| t.Errorf("expected code action to have command not data, got %v", fixes[0]) | |
| } | |
| } else { | |
| if fixes[0].Command != nil || fixes[0].Data == nil { | |
| t.Errorf("expected code action to have command not data, got %v", fixes[0]) | |
| } | |
| } | |
| // Apply the code action (handles resolving the code action), and check that the result is correct. | |
| if err := env.Editor.RefactorRewrite(env.Ctx, env.RegexpSearch("main.go", "Info{}")); err != nil { | |
| t.Fatal(err) | |
| } | |
| want := `package main | |
| type Info struct { | |
| WordCounts map[string]int | |
| Words []string | |
| } | |
| func Foo() { | |
| _ = Info{ | |
| WordCounts: map[string]int{}, | |
| Words: []string{}, | |
| } | |
| } | |
| ` | |
| if got := env.BufferText("main.go"); got != want { | |
| t.Fatalf("TestFillStruct failed:\n%s", compare.Text(want, got)) | |
| } | |
| }) | |
| }) | |
| } | |
| } | |
| func TestFillReturns(t *testing.T) { | |
| const files = ` | |
| -- go.mod -- | |
| module mod.com | |
| go 1.12 | |
| -- main.go -- | |
| package main | |
| func Foo() error { | |
| return | |
| } | |
| ` | |
| Run(t, files, func(t *testing.T, env *Env) { | |
| env.OpenFile("main.go") | |
| var d protocol.PublishDiagnosticsParams | |
| env.AfterChange( | |
| // The error message here changed in 1.18; "return values" covers both forms. | |
| Diagnostics(env.AtRegexp("main.go", `return`), WithMessage("return values")), | |
| ReadDiagnostics("main.go", &d), | |
| ) | |
| var quickFixes []*protocol.CodeAction | |
| for _, act := range env.CodeActionForFile("main.go", d.Diagnostics) { | |
| if act.Kind == protocol.QuickFix { | |
| act := act // remove in go1.22 | |
| quickFixes = append(quickFixes, &act) | |
| } | |
| } | |
| if len(quickFixes) != 1 { | |
| t.Fatalf("expected 1 quick fix, got %d:\n%v", len(quickFixes), quickFixes) | |
| } | |
| env.ApplyQuickFixes("main.go", d.Diagnostics) | |
| env.AfterChange(NoDiagnostics(ForFile("main.go"))) | |
| }) | |
| } | |
| func TestUnusedParameter_Issue63755(t *testing.T) { | |
| // This test verifies the fix for #63755, where codeActions panicked on parameters | |
| // of functions with no function body. | |
| // We should not detect parameters as unused for external functions. | |
| const files = ` | |
| -- go.mod -- | |
| module unused.mod | |
| go 1.18 | |
| -- external.go -- | |
| package external | |
| func External(z int) | |
| func _() { | |
| External(1) | |
| } | |
| ` | |
| Run(t, files, func(t *testing.T, env *Env) { | |
| env.OpenFile("external.go") | |
| _, err := env.Editor.CodeAction(env.Ctx, env.RegexpSearch("external.go", "z"), nil, protocol.CodeActionUnknownTrigger) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| // yay, no panic | |
| }) | |
| } |