Skip to content

Commit c7ca526

Browse files
mcjcloudfindleyr
authored andcommitted
internal/lsp: add "run file benchmarks" code lens
This CL adds a code lens to run all benchmarks in a file. Additionally, it updates the test command handler to better support both tests and benchmarks. Updates golang/go#36787 Change-Id: I6e90460f7d97607f96c263be0754537764bd0052 Reviewed-on: https://go-review.googlesource.com/c/tools/+/246017 Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 3986990 commit c7ca526

File tree

4 files changed

+86
-18
lines changed

4 files changed

+86
-18
lines changed

internal/lsp/command.go

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"fmt"
1010
"io"
1111
"path"
12-
"strings"
1312

1413
"golang.org/x/tools/internal/event"
1514
"golang.org/x/tools/internal/lsp/debug/tag"
@@ -97,17 +96,16 @@ func (s *Server) executeCommand(ctx context.Context, params *protocol.ExecuteCom
9796
switch command {
9897
case source.CommandTest:
9998
var uri protocol.DocumentURI
100-
var flag string
101-
var funcName string
102-
if err := source.UnmarshalArgs(params.Arguments, &uri, &flag, &funcName); err != nil {
99+
var tests, benchmarks []string
100+
if err := source.UnmarshalArgs(params.Arguments, &uri, &tests, &benchmarks); err != nil {
103101
return nil, err
104102
}
105103
snapshot, _, ok, release, err := s.beginFileRequest(ctx, uri, source.UnknownKind)
106104
defer release()
107105
if !ok {
108106
return nil, err
109107
}
110-
go s.runTest(ctx, snapshot, []string{flag, funcName}, params.WorkDoneToken)
108+
go s.runTests(ctx, snapshot, uri, params.WorkDoneToken, tests, benchmarks)
111109
case source.CommandGenerate:
112110
var uri protocol.DocumentURI
113111
var recursive bool
@@ -193,26 +191,74 @@ func (s *Server) directGoModCommand(ctx context.Context, uri protocol.DocumentUR
193191
return snapshot.RunGoCommandDirect(ctx, verb, args)
194192
}
195193

196-
func (s *Server) runTest(ctx context.Context, snapshot source.Snapshot, args []string, token protocol.ProgressToken) error {
194+
func (s *Server) runTests(ctx context.Context, snapshot source.Snapshot, uri protocol.DocumentURI, token protocol.ProgressToken, tests, benchmarks []string) error {
197195
ctx, cancel := context.WithCancel(ctx)
198196
defer cancel()
199197

198+
pkgs, err := snapshot.PackagesForFile(ctx, uri.SpanURI())
199+
if err != nil {
200+
return err
201+
}
202+
if len(pkgs) == 0 {
203+
return fmt.Errorf("package could not be found for file: %s", uri.SpanURI().Filename())
204+
}
205+
pkgPath := pkgs[0].PkgPath()
206+
207+
// create output
200208
ew := &eventWriter{ctx: ctx, operation: "test"}
201-
msg := fmt.Sprintf("running `go test %s`", strings.Join(args, " "))
202-
wc := s.progress.newWriter(ctx, "test", msg, msg, token, cancel)
209+
var title string
210+
if len(tests) > 0 && len(benchmarks) > 0 {
211+
title = "tests and benchmarks"
212+
} else if len(tests) > 0 {
213+
title = "tests"
214+
} else if len(benchmarks) > 0 {
215+
title = "benchmarks"
216+
} else {
217+
return errors.New("No functions were provided")
218+
}
219+
msg := fmt.Sprintf("Running %s...", title)
220+
wc := s.progress.newWriter(ctx, title, msg, msg, token, cancel)
203221
defer wc.Close()
204222

205-
messageType := protocol.Info
206-
message := "test passed"
207223
stderr := io.MultiWriter(ew, wc)
208224

209-
if err := snapshot.RunGoCommandPiped(ctx, "test", args, ew, stderr); err != nil {
210-
if errors.Is(err, context.Canceled) {
211-
return err
225+
// run `go test -run Func` on each test
226+
var failedTests int
227+
for _, funcName := range tests {
228+
args := []string{pkgPath, "-run", fmt.Sprintf("^%s$", funcName)}
229+
if err := snapshot.RunGoCommandPiped(ctx, "test", args, ew, stderr); err != nil {
230+
if errors.Is(err, context.Canceled) {
231+
return err
232+
}
233+
failedTests++
212234
}
235+
}
236+
237+
// run `go test -run=^$ -bench Func` on each test
238+
var failedBenchmarks int
239+
for _, funcName := range tests {
240+
args := []string{pkgPath, "-run=^$", "-bench", fmt.Sprintf("^%s$", funcName)}
241+
if err := snapshot.RunGoCommandPiped(ctx, "test", args, ew, stderr); err != nil {
242+
if errors.Is(err, context.Canceled) {
243+
return err
244+
}
245+
failedBenchmarks++
246+
}
247+
}
248+
249+
messageType := protocol.Info
250+
message := fmt.Sprintf("all %s passed", title)
251+
if failedTests > 0 || failedBenchmarks > 0 {
213252
messageType = protocol.Error
214-
message = "test failed"
215253
}
254+
if failedTests > 0 && failedBenchmarks > 0 {
255+
message = fmt.Sprintf("%d / %d tests failed and %d / %d benchmarks failed", failedTests, len(tests), failedBenchmarks, len(benchmarks))
256+
} else if failedTests > 0 {
257+
message = fmt.Sprintf("%d / %d tests failed", failedTests, len(tests))
258+
} else if failedBenchmarks > 0 {
259+
message = fmt.Sprintf("%d / %d benchmarks failed", failedBenchmarks, len(benchmarks))
260+
}
261+
216262
return s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
217263
Type: messageType,
218264
Message: message,

internal/lsp/source/code_lens.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,23 @@ func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]p
5757
if err != nil {
5858
return nil, err
5959
}
60+
61+
var benchFns []string
6062
for _, d := range pgf.File.Decls {
6163
fn, ok := d.(*ast.FuncDecl)
6264
if !ok {
6365
continue
6466
}
67+
if benchmarkRe.MatchString(fn.Name.Name) {
68+
benchFns = append(benchFns, fn.Name.Name)
69+
}
6570
rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, d.Pos(), d.Pos()).Range()
6671
if err != nil {
6772
return nil, err
6873
}
6974

7075
if matchTestFunc(fn, pkg, testRe, "T") {
71-
jsonArgs, err := MarshalArgs(fh.URI(), "-run", fn.Name.Name)
76+
jsonArgs, err := MarshalArgs(fh.URI(), []string{fn.Name.Name}, nil)
7277
if err != nil {
7378
return nil, err
7479
}
@@ -83,7 +88,7 @@ func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]p
8388
}
8489

8590
if matchTestFunc(fn, pkg, benchmarkRe, "B") {
86-
jsonArgs, err := MarshalArgs(fh.URI(), "-bench", fn.Name.Name)
91+
jsonArgs, err := MarshalArgs(fh.URI(), nil, []string{fn.Name.Name})
8792
if err != nil {
8893
return nil, err
8994
}
@@ -97,6 +102,23 @@ func runTestCodeLens(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]p
97102
})
98103
}
99104
}
105+
// add a code lens to the top of the file which runs all benchmarks in the file
106+
rng, err := newMappedRange(snapshot.FileSet(), pgf.Mapper, pgf.File.Package, pgf.File.Package).Range()
107+
if err != nil {
108+
return nil, err
109+
}
110+
args, err := MarshalArgs(fh.URI(), []string{}, benchFns)
111+
if err != nil {
112+
return nil, err
113+
}
114+
codeLens = append(codeLens, protocol.CodeLens{
115+
Range: rng,
116+
Command: protocol.Command{
117+
Title: "run file benchmarks",
118+
Command: CommandTest.Name,
119+
Arguments: args,
120+
},
121+
})
100122
return codeLens, nil
101123
}
102124

internal/lsp/testdata/lsp/primarymod/codelens/codelens_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package codelens
1+
package codelens //@codelens("package codelens", "run file benchmarks", "test")
22

33
import "testing"
44

internal/lsp/testdata/lsp/summary.txt.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- summary --
22
CallHierarchyCount = 1
3-
CodeLensCount = 4
3+
CodeLensCount = 5
44
CompletionsCount = 239
55
CompletionSnippetCount = 81
66
UnimportedCompletionsCount = 6

0 commit comments

Comments
 (0)