1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:44:43 -07:00

internal/lsp: add some basic tests for imports

This change adds a few simple tests for the goimports behavior of gopls.
There are still missing cases for non-standard library, but this is a
good start.

Change-Id: I2f9bc2cc876dcabf81413384b83fa3508517adf0
Reviewed-on: https://go-review.googlesource.com/c/tools/+/179918
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Rebecca Stambler 2019-05-31 22:42:59 -04:00
parent 70bf279967
commit 8aaa1484dc
9 changed files with 161 additions and 11 deletions

View File

@ -61,6 +61,10 @@ func (r *runner) Link(t *testing.T, data tests.Links) {
//TODO: add command line link tests when it works
}
func (r *runner) Import(t *testing.T, data tests.Imports) {
//TODO: add command line imports tests when it works
}
func captureStdOut(t testing.TB, f func()) string {
r, out, err := os.Pipe()
if err != nil {

View File

@ -322,6 +322,53 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
}
}
func (r *runner) Import(t *testing.T, data tests.Imports) {
ctx := context.Background()
for _, spn := range data {
uri := spn.URI()
filename, err := uri.Filename()
if err != nil {
t.Fatal(err)
}
goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) {
cmd := exec.Command("goimports", filename)
out, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files
return out, nil
}))
actions, err := r.server.CodeAction(context.Background(), &protocol.CodeActionParams{
TextDocument: protocol.TextDocumentIdentifier{
URI: protocol.NewURI(uri),
},
})
if err != nil {
if goimported != "" {
t.Error(err)
}
continue
}
_, m, err := getSourceFile(ctx, r.server.session.ViewOf(uri), uri)
if err != nil {
t.Error(err)
}
var edits []protocol.TextEdit
for _, a := range actions {
if a.Title == "Organize Imports" {
edits = (*a.Edit.Changes)[string(uri)]
}
}
sedits, err := FromProtocolEdits(m, edits)
if err != nil {
t.Error(err)
}
ops := source.EditsToDiff(sedits)
got := strings.Join(diff.ApplyEdits(diff.SplitLines(string(m.Content)), ops), "")
if goimported != got {
t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got)
}
}
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
for _, d := range data {
sm, err := r.mapper(d.Src.URI())

View File

@ -64,7 +64,7 @@ func Imports(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error)
if tok == nil {
return nil, fmt.Errorf("no token file for %s", f.URI())
}
formatted, err := imports.Process(f.GetToken(ctx).Name(), fc.Data, nil)
formatted, err := imports.Process(tok.Name(), fc.Data, nil)
if err != nil {
return nil, err
}

View File

@ -308,6 +308,47 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
}
}
func (r *runner) Import(t *testing.T, data tests.Imports) {
ctx := context.Background()
for _, spn := range data {
uri := spn.URI()
filename, err := uri.Filename()
if err != nil {
t.Fatal(err)
}
goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) {
cmd := exec.Command("goimports", filename)
out, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files
return out, nil
}))
f, err := r.view.GetFile(ctx, uri)
if err != nil {
t.Fatalf("failed for %v: %v", spn, err)
}
rng, err := spn.Range(span.NewTokenConverter(f.FileSet(), f.GetToken(ctx)))
if err != nil {
t.Fatalf("failed for %v: %v", spn, err)
}
edits, err := source.Imports(ctx, f.(source.GoFile), rng)
if err != nil {
if goimported != "" {
t.Error(err)
}
continue
}
ops := source.EditsToDiff(edits)
fc := f.Content(ctx)
if fc.Error != nil {
t.Error(err)
continue
}
got := strings.Join(diff.ApplyEdits(diff.SplitLines(string(fc.Data)), ops), "")
if goimported != got {
t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got)
}
}
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
ctx := context.Background()
for _, d := range data {

View File

@ -0,0 +1,7 @@
package imports //@import("package")
import "fmt"
func _() {
fmt.Println("")
}

View File

@ -0,0 +1,11 @@
-- goimports --
package imports //@import("package")
import "fmt"
func _() {
fmt.Println("")
}
-- goimports-d --

View File

@ -0,0 +1,6 @@
package imports //@import("package")
func goodbye() {
fmt.Printf("HI")
log.Printf("byeeeee")
}

View File

@ -0,0 +1,27 @@
-- goimports --
package imports //@import("package")
import (
"fmt"
"log"
)
func goodbye() {
fmt.Printf("HI")
log.Printf("byeeeee")
}
-- goimports-d --
--- imports/needs_imports.go.orig
+++ imports/needs_imports.go
@@ -1,5 +1,10 @@
package imports //@import("package")
+import (
+ "fmt"
+ "log"
+)
+
func goodbye() {
fmt.Printf("HI")
log.Printf("byeeeee")

View File

@ -11,9 +11,7 @@ import (
"go/parser"
"go/token"
"io/ioutil"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"
@ -32,6 +30,7 @@ const (
ExpectedCompletionSnippetCount = 14
ExpectedDiagnosticsCount = 17
ExpectedFormatCount = 5
ExpectedImportCount = 2
ExpectedDefinitionsCount = 35
ExpectedTypeDefinitionsCount = 2
ExpectedHighlightsCount = 2
@ -54,6 +53,7 @@ type CompletionItems map[token.Pos]*source.CompletionItem
type Completions map[span.Span][]token.Pos
type CompletionSnippets map[span.Span]CompletionSnippet
type Formats []span.Span
type Imports []span.Span
type Definitions map[span.Span]Definition
type Highlights map[string][]span.Span
type Symbols map[span.URI][]source.Symbol
@ -69,6 +69,7 @@ type Data struct {
Completions Completions
CompletionSnippets CompletionSnippets
Formats Formats
Imports Imports
Definitions Definitions
Highlights Highlights
Symbols Symbols
@ -86,6 +87,7 @@ type Tests interface {
Diagnostics(*testing.T, Diagnostics)
Completion(*testing.T, Completions, CompletionSnippets, CompletionItems)
Format(*testing.T, Formats)
Import(*testing.T, Imports)
Definition(*testing.T, Definitions)
Highlight(*testing.T, Highlights)
Symbol(*testing.T, Symbols)
@ -202,6 +204,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
"item": data.collectCompletionItems,
"complete": data.collectCompletions,
"format": data.collectFormats,
"import": data.collectImports,
"godef": data.collectDefinitions,
"typdef": data.collectTypeDefinitions,
"hover": data.collectHoverDefinitions,
@ -256,20 +259,20 @@ func Run(t *testing.T, tests Tests, data *Data) {
t.Run("Format", func(t *testing.T) {
t.Helper()
if _, err := exec.LookPath("gofmt"); err != nil {
switch runtime.GOOS {
case "android":
t.Skip("gofmt is not installed")
default:
t.Fatal(err)
}
}
if len(data.Formats) != ExpectedFormatCount {
t.Errorf("got %v formats expected %v", len(data.Formats), ExpectedFormatCount)
}
tests.Format(t, data.Formats)
})
t.Run("Import", func(t *testing.T) {
t.Helper()
if len(data.Imports) != ExpectedImportCount {
t.Errorf("got %v imports expected %v", len(data.Imports), ExpectedImportCount)
}
tests.Import(t, data.Imports)
})
t.Run("Definition", func(t *testing.T) {
t.Helper()
if len(data.Definitions) != ExpectedDefinitionsCount {
@ -416,6 +419,10 @@ func (data *Data) collectFormats(spn span.Span) {
data.Formats = append(data.Formats, spn)
}
func (data *Data) collectImports(spn span.Span) {
data.Imports = append(data.Imports, spn)
}
func (data *Data) collectDefinitions(src, target span.Span) {
data.Definitions[src] = Definition{
Src: src,