-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gopls/internal/golang: add source code action for add test
This CL is some glue code which build the connection between the LSP "code action request" with second call which compute the actual DocumentChange. AddTest source code action will create a test file if not already exist and insert a random function at the end of the test file. For testing, an internal boolean option "addTestSourceCodeAction" is created and only effective if set explicitly in marker test. For golang/vscode-go#1594 Change-Id: Ie3d9279ea2858805254181608a0d5103afd3a4c6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/621056 Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
- Loading branch information
Showing
11 changed files
with
266 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright 2019 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 golang | ||
|
||
// This file defines the behavior of the "Add test for FUNC" command. | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"errors" | ||
"fmt" | ||
"go/token" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"golang.org/x/tools/gopls/internal/cache" | ||
"golang.org/x/tools/gopls/internal/cache/parsego" | ||
"golang.org/x/tools/gopls/internal/protocol" | ||
) | ||
|
||
// AddTestForFunc adds a test for the function enclosing the given input range. | ||
// It creates a _test.go file if one does not already exist. | ||
func AddTestForFunc(ctx context.Context, snapshot *cache.Snapshot, loc protocol.Location) (changes []protocol.DocumentChange, _ error) { | ||
pkg, pgf, err := NarrowestPackageForFile(ctx, snapshot, loc.URI) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
testBase := strings.TrimSuffix(filepath.Base(loc.URI.Path()), ".go") + "_test.go" | ||
goTestFileURI := protocol.URIFromPath(filepath.Join(loc.URI.Dir().Path(), testBase)) | ||
|
||
testFH, err := snapshot.ReadFile(ctx, goTestFileURI) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// TODO(hxjiang): use a fresh name if the same test function name already | ||
// exist. | ||
|
||
var ( | ||
// edits contains all the text edits to be applied to the test file. | ||
edits []protocol.TextEdit | ||
// header is the buffer containing the text edit to the beginning of the file. | ||
header bytes.Buffer | ||
) | ||
|
||
testPgf, err := snapshot.ParseGo(ctx, testFH, parsego.Header) | ||
if err != nil { | ||
if !errors.Is(err, os.ErrNotExist) { | ||
return nil, err | ||
} | ||
|
||
changes = append(changes, protocol.DocumentChangeCreate(goTestFileURI)) | ||
|
||
// If this test file was created by the gopls, add a copyright header based | ||
// on the originating file. | ||
// Search for something that looks like a copyright header, to replicate | ||
// in the new file. | ||
// TODO(hxjiang): should we refine this heuristic, for example by checking for | ||
// the word 'copyright'? | ||
if groups := pgf.File.Comments; len(groups) > 0 { | ||
// Copyright should appear before package decl and must be the first | ||
// comment group. | ||
// Avoid copying any other comment like package doc or directive comment. | ||
if c := groups[0]; c.Pos() < pgf.File.Package && c != pgf.File.Doc && | ||
!isDirective(groups[0].List[0].Text) { | ||
start, end, err := pgf.NodeOffsets(c) | ||
if err != nil { | ||
return nil, err | ||
} | ||
header.Write(pgf.Src[start:end]) | ||
// One empty line between copyright header and package decl. | ||
header.WriteString("\n\n") | ||
} | ||
} | ||
} | ||
|
||
// If the test file does not have package decl, use the originating file to | ||
// determine a package decl for the new file. Prefer xtest package.s | ||
if testPgf == nil || testPgf.File == nil || testPgf.File.Package == token.NoPos { | ||
// One empty line between package decl and rest of the file. | ||
fmt.Fprintf(&header, "package %s_test\n\n", pkg.Types().Name()) | ||
} | ||
|
||
// Write the copyright and package decl to the beginning of the file. | ||
if text := header.String(); len(text) != 0 { | ||
edits = append(edits, protocol.TextEdit{ | ||
Range: protocol.Range{}, | ||
NewText: text, | ||
}) | ||
} | ||
|
||
// TODO(hxjiang): reject if the function/method is unexported. | ||
// TODO(hxjiang): modify existing imports or add new imports. | ||
|
||
// If the parse go file is missing, the fileEnd is the file start (zero value). | ||
fileEnd := protocol.Range{} | ||
if testPgf != nil { | ||
fileEnd, err = testPgf.PosRange(testPgf.File.FileEnd, testPgf.File.FileEnd) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
// test is the buffer containing the text edit to the test function. | ||
var test bytes.Buffer | ||
// TODO(hxjiang): replace test foo function with table-driven test. | ||
test.WriteString("\nfunc TestFoo(*testing.T) {}") | ||
edits = append(edits, protocol.TextEdit{ | ||
Range: fileEnd, | ||
NewText: test.String(), | ||
}) | ||
return append(changes, protocol.DocumentChangeEdit(testFH, edits)), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.