internal/lsp: lift the test loops out into the testing framework

The loops are common to all the testing layers, so lift them.
This prepares for more test improvements, without any funcitonal changes.

Change-Id: Ib750c8a7bb4c424a185cb0bd841674a69db1385b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/197717
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Ian Cottrell 2019-09-26 13:56:23 -04:00
parent 69890759d9
commit c7cf430b80
9 changed files with 1238 additions and 1297 deletions

View File

@ -11,15 +11,14 @@ import (
"testing" "testing"
"golang.org/x/tools/internal/lsp/cmd" "golang.org/x/tools/internal/lsp/cmd"
"golang.org/x/tools/internal/lsp/tests" "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/tool" "golang.org/x/tools/internal/tool"
) )
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) { func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnostic) {
for uri, want := range data {
if len(want) == 1 && want[0].Message == "" { if len(want) == 1 && want[0].Message == "" {
continue return
} }
fname := uri.Filename() fname := uri.Filename()
args := []string{"-remote=internal", "check", fname} args := []string{"-remote=internal", "check", fname}
@ -67,4 +66,3 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
t.Errorf("extra diagnostic %q", extra) t.Errorf("extra diagnostic %q", extra)
} }
} }
}

View File

@ -16,7 +16,10 @@ import (
"testing" "testing"
"golang.org/x/tools/go/packages/packagestest" "golang.org/x/tools/go/packages/packagestest"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/tests" "golang.org/x/tools/internal/lsp/tests"
"golang.org/x/tools/internal/span"
) )
type runner struct { type runner struct {
@ -33,67 +36,67 @@ func NewRunner(exporter packagestest.Exporter, data *tests.Data, ctx context.Con
} }
} }
func (r *runner) Completion(t *testing.T, data tests.Completions, items tests.CompletionItems) { func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) CompletionSnippets(t *testing.T, data tests.CompletionSnippets, items tests.CompletionItems) { func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) UnimportedCompletions(t *testing.T, data tests.UnimportedCompletions, items tests.CompletionItems) { func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) DeepCompletions(t *testing.T, data tests.DeepCompletions, items tests.CompletionItems) { func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, items tests.CompletionItems) { func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) { func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) { func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
//TODO: add command line completions tests when it works //TODO: add command line completions tests when it works
} }
func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) { func (r *runner) FoldingRange(t *testing.T, spn span.Span) {
//TODO: add command line folding range tests when it works //TODO: add command line folding range tests when it works
} }
func (r *runner) Highlight(t *testing.T, data tests.Highlights) { func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
//TODO: add command line highlight tests when it works //TODO: add command line highlight tests when it works
} }
func (r *runner) Reference(t *testing.T, data tests.References) { func (r *runner) Reference(t *testing.T, src span.Span, itemList []span.Span) {
//TODO: add command line references tests when it works //TODO: add command line references tests when it works
} }
func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) { func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) {
//TODO: add command line prepare rename tests when it works //TODO: add command line prepare rename tests when it works
} }
func (r *runner) Symbol(t *testing.T, data tests.Symbols) { func (r *runner) Symbol(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) {
//TODO: add command line symbol tests when it works //TODO: add command line symbol tests when it works
} }
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) { func (r *runner) SignatureHelp(t *testing.T, spn span.Span, expectedSignature *source.SignatureInformation) {
//TODO: add command line signature tests when it works //TODO: add command line signature tests when it works
} }
func (r *runner) Link(t *testing.T, data tests.Links) { func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
//TODO: add command line link tests when it works //TODO: add command line link tests when it works
} }
func (r *runner) Import(t *testing.T, data tests.Imports) { func (r *runner) Import(t *testing.T, spn span.Span) {
//TODO: add command line imports tests when it works //TODO: add command line imports tests when it works
} }
func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) { func (r *runner) SuggestedFix(t *testing.T, spn span.Span) {
//TODO: add suggested fix tests when it works //TODO: add suggested fix tests when it works
} }

View File

@ -33,15 +33,14 @@ var godefModes = []godefMode{
jsonGoDef, jsonGoDef,
} }
func (r *runner) Definition(t *testing.T, data tests.Definitions) { func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
// TODO: https://golang.org/issue/32794. // TODO: https://golang.org/issue/32794.
if !*tests.UpdateGolden { if !*tests.UpdateGolden {
t.Skip() t.Skip()
} }
for _, d := range data {
if d.IsType || d.OnlyHover { if d.IsType || d.OnlyHover {
// TODO: support type definition, hover queries // TODO: support type definition, hover queries
continue return
} }
d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{}) d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{})
for _, mode := range godefModes { for _, mode := range godefModes {
@ -70,4 +69,3 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
} }
} }
} }
}

View File

@ -11,7 +11,7 @@ import (
"testing" "testing"
"golang.org/x/tools/internal/lsp/cmd" "golang.org/x/tools/internal/lsp/cmd"
"golang.org/x/tools/internal/lsp/tests" "golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/tool" "golang.org/x/tools/internal/tool"
) )
@ -20,8 +20,7 @@ var formatModes = [][]string{
[]string{"-d"}, []string{"-d"},
} }
func (r *runner) Format(t *testing.T, data tests.Formats) { func (r *runner) Format(t *testing.T, spn span.Span) {
for _, spn := range data {
for _, mode := range formatModes { for _, mode := range formatModes {
tag := "gofmt" + strings.Join(mode, "") tag := "gofmt" + strings.Join(mode, "")
uri := spn.URI() uri := spn.URI()
@ -48,7 +47,6 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
} }
} }
} }
}
var unifiedHeader = regexp.MustCompile(`^diff -u.*\n(---\s+\S+\.go\.orig)\s+[\d-:. ]+(\n\+\+\+\s+\S+\.go)\s+[\d-:. ]+(\n@@)`) var unifiedHeader = regexp.MustCompile(`^diff -u.*\n(---\s+\S+\.go\.orig)\s+[\d-:. ]+(\n\+\+\+\s+\S+\.go)\s+[\d-:. ]+(\n@@)`)

View File

@ -6,12 +6,10 @@ package cmdtest
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
"testing" "testing"
"golang.org/x/tools/internal/lsp/cmd" "golang.org/x/tools/internal/lsp/cmd"
"golang.org/x/tools/internal/lsp/tests"
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/tool" "golang.org/x/tools/internal/tool"
) )
@ -21,20 +19,17 @@ var renameModes = [][]string{
[]string{"-d"}, []string{"-d"},
} }
func (r *runner) Rename(t *testing.T, data tests.Renames) { func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
sortedSpans := sortSpans(data) // run the tests in a repeatable order
for _, spn := range sortedSpans {
tag := data[spn]
filename := spn.URI().Filename() filename := spn.URI().Filename()
for _, mode := range renameModes { for _, mode := range renameModes {
goldenTag := data[spn] + strings.Join(mode, "") + "-rename" goldenTag := newText + strings.Join(mode, "") + "-rename"
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env) app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env)
loc := fmt.Sprintf("%v", spn) loc := fmt.Sprintf("%v", spn)
args := []string{"-remote=internal", "rename"} args := []string{"-remote=internal", "rename"}
if strings.Join(mode, "") != "" { if strings.Join(mode, "") != "" {
args = append(args, strings.Join(mode, "")) args = append(args, strings.Join(mode, ""))
} }
args = append(args, loc, tag) args = append(args, loc, newText)
var err error var err error
got := CaptureStdOut(t, func() { got := CaptureStdOut(t, func() {
err = tool.Run(r.ctx, app, args) err = tool.Run(r.ctx, app, args)
@ -51,15 +46,3 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
} }
} }
} }
}
func sortSpans(data map[span.Span]string) []span.Span {
spans := make([]span.Span, 0, len(data))
for spn, _ := range data {
spans = append(spans, spn)
}
sort.Slice(spans, func(i, j int) bool {
return span.Compare(spans[i], spans[j]) < 0
})
return spans
}

View File

@ -11,8 +11,7 @@ import (
"golang.org/x/tools/internal/span" "golang.org/x/tools/internal/span"
) )
func (r *runner) Completion(t *testing.T, data tests.Completions, items tests.CompletionItems) { func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
Deep: false, Deep: false,
FuzzyMatching: false, FuzzyMatching: false,
@ -26,11 +25,8 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, items tests.Co
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) CompletionSnippets(t *testing.T, data tests.CompletionSnippets, items tests.CompletionItems) { func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
for _, placeholders := range []bool{true, false} {
for src, expected := range data {
list := r.callCompletion(t, src, source.CompletionOptions{ list := r.callCompletion(t, src, source.CompletionOptions{
Placeholders: placeholders, Placeholders: placeholders,
Deep: true, Deep: true,
@ -46,11 +42,8 @@ func (r *runner) CompletionSnippets(t *testing.T, data tests.CompletionSnippets,
t.Errorf("%s: %v", src, diff) t.Errorf("%s: %v", src, diff)
} }
} }
}
}
func (r *runner) UnimportedCompletions(t *testing.T, data tests.UnimportedCompletions, items tests.CompletionItems) { func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
Unimported: true, Unimported: true,
}) })
@ -62,10 +55,8 @@ func (r *runner) UnimportedCompletions(t *testing.T, data tests.UnimportedComple
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) DeepCompletions(t *testing.T, data tests.DeepCompletions, items tests.CompletionItems) { func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
Deep: true, Deep: true,
Budget: 5 * time.Second, Budget: 5 * time.Second,
@ -79,10 +70,8 @@ func (r *runner) DeepCompletions(t *testing.T, data tests.DeepCompletions, items
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, items tests.CompletionItems) { func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
FuzzyMatching: true, FuzzyMatching: true,
Deep: true, Deep: true,
@ -96,10 +85,8 @@ func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, ite
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) { func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
CaseSensitive: true, CaseSensitive: true,
}) })
@ -111,10 +98,8 @@ func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitive
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) { func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
got := r.callCompletion(t, src, source.CompletionOptions{ got := r.callCompletion(t, src, source.CompletionOptions{
FuzzyMatching: true, FuzzyMatching: true,
Deep: true, Deep: true,
@ -125,7 +110,6 @@ func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func expected(t *testing.T, test tests.Completion, items tests.CompletionItems) []protocol.CompletionItem { func expected(t *testing.T, test tests.Completion, items tests.CompletionItems) []protocol.CompletionItem {
t.Helper() t.Helper()

View File

@ -70,9 +70,8 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
} }
// TODO: Actually test the LSP diagnostics function in this test. // TODO: Actually test the LSP diagnostics function in this test.
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) { func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnostic) {
v := r.server.session.View(viewName) v := r.server.session.View(viewName)
for uri, want := range data {
f, err := v.GetFile(r.ctx, uri) f, err := v.GetFile(r.ctx, uri)
if err != nil { if err != nil {
t.Fatalf("no file for %s: %v", f, err) t.Fatalf("no file for %s: %v", f, err)
@ -91,16 +90,14 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
if len(got) != 0 { if len(got) != 0 {
t.Errorf("expected no diagnostics for %s, got %v", uri, got) t.Errorf("expected no diagnostics for %s, got %v", uri, got)
} }
continue return
} }
if diff := tests.DiffDiagnostics(uri, want, got); diff != "" { if diff := tests.DiffDiagnostics(uri, want, got); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) { func (r *runner) FoldingRange(t *testing.T, spn span.Span) {
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
view := r.server.session.ViewOf(uri) view := r.server.session.ViewOf(uri)
original := view.Options() original := view.Options()
@ -116,7 +113,7 @@ func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
}) })
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
r.foldingRanges(t, "foldingRange", uri, ranges) r.foldingRanges(t, "foldingRange", uri, ranges)
@ -130,12 +127,11 @@ func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
}) })
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
r.foldingRanges(t, "foldingRange-lineFolding", uri, ranges) r.foldingRanges(t, "foldingRange-lineFolding", uri, ranges)
view.SetOptions(original) view.SetOptions(original)
} }
}
func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, ranges []protocol.FoldingRange) { func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, ranges []protocol.FoldingRange) {
m, err := r.data.Mapper(uri) m, err := r.data.Mapper(uri)
@ -249,8 +245,7 @@ func foldRanges(m *protocol.ColumnMapper, contents string, ranges []protocol.Fol
return res, nil return res, nil
} }
func (r *runner) Format(t *testing.T, data tests.Formats) { func (r *runner) Format(t *testing.T, spn span.Span) {
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
filename := uri.Filename() filename := uri.Filename()
gofmted := string(r.data.Golden("gofmt", filename, func() ([]byte, error) { gofmted := string(r.data.Golden("gofmt", filename, func() ([]byte, error) {
@ -268,7 +263,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
if gofmted != "" { if gofmted != "" {
t.Error(err) t.Error(err)
} }
continue return
} }
m, err := r.data.Mapper(uri) m, err := r.data.Mapper(uri)
if err != nil { if err != nil {
@ -283,10 +278,8 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
t.Errorf("format failed for %s, expected:\n%v\ngot:\n%v", filename, gofmted, got) t.Errorf("format failed for %s, expected:\n%v\ngot:\n%v", filename, gofmted, got)
} }
} }
}
func (r *runner) Import(t *testing.T, data tests.Imports) { func (r *runner) Import(t *testing.T, spn span.Span) {
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
filename := uri.Filename() filename := uri.Filename()
goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) { goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) {
@ -304,7 +297,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
if goimported != "" { if goimported != "" {
t.Error(err) t.Error(err)
} }
continue return
} }
m, err := r.data.Mapper(uri) m, err := r.data.Mapper(uri)
if err != nil { if err != nil {
@ -325,10 +318,8 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got) t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got)
} }
} }
}
func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) { func (r *runner) SuggestedFix(t *testing.T, spn span.Span) {
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
filename := uri.Filename() filename := uri.Filename()
view := r.server.session.ViewOf(uri) view := r.server.session.ViewOf(uri)
@ -351,7 +342,7 @@ func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) {
}) })
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
m, err := r.data.Mapper(f.URI()) m, err := r.data.Mapper(f.URI())
if err != nil { if err != nil {
@ -375,10 +366,8 @@ func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) {
t.Errorf("suggested fixes failed for %s, expected:\n%v\ngot:\n%v", filename, fixed, got) t.Errorf("suggested fixes failed for %s, expected:\n%v\ngot:\n%v", filename, fixed, got)
} }
} }
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) { func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
for _, d := range data {
sm, err := r.data.Mapper(d.Src.URI()) sm, err := r.data.Mapper(d.Src.URI())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -440,10 +429,8 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
t.Errorf("no tests ran for %s", d.Src.URI()) t.Errorf("no tests ran for %s", d.Src.URI())
} }
} }
}
func (r *runner) Highlight(t *testing.T, data tests.Highlights) { func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
for name, locations := range data {
m, err := r.data.Mapper(locations[0].URI()) m, err := r.data.Mapper(locations[0].URI())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -474,10 +461,8 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
} }
} }
} }
}
func (r *runner) Reference(t *testing.T, data tests.References) { func (r *runner) Reference(t *testing.T, src span.Span, itemList []span.Span) {
for src, itemList := range data {
sm, err := r.data.Mapper(src.URI()) sm, err := r.data.Mapper(src.URI())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -518,10 +503,8 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
} }
} }
} }
}
func (r *runner) Rename(t *testing.T, data tests.Renames) { func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
for spn, newText := range data {
tag := fmt.Sprintf("%s-rename", newText) tag := fmt.Sprintf("%s-rename", newText)
uri := spn.URI() uri := spn.URI()
@ -549,7 +532,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
if err.Error() != renamed { if err.Error() != renamed {
t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v\n", newText, renamed, err) t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v\n", newText, renamed, err)
} }
continue return
} }
var res []string var res []string
@ -589,10 +572,8 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v", newText, renamed, got) t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v", newText, renamed, got)
} }
} }
}
func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) { func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) {
for src, want := range data {
m, err := r.data.Mapper(src.URI()) m, err := r.data.Mapper(src.URI())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -611,19 +592,18 @@ func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) {
got, err := r.server.PrepareRename(context.Background(), params) got, err := r.server.PrepareRename(context.Background(), params)
if err != nil { if err != nil {
t.Errorf("prepare rename failed for %v: got error: %v", src, err) t.Errorf("prepare rename failed for %v: got error: %v", src, err)
continue return
} }
if got == nil { if got == nil {
if want.Text != "" { // expected an ident. if want.Text != "" { // expected an ident.
t.Errorf("prepare rename failed for %v: got nil", src) t.Errorf("prepare rename failed for %v: got nil", src)
} }
continue return
} }
if protocol.CompareRange(*got, want.Range) != 0 { if protocol.CompareRange(*got, want.Range) != 0 {
t.Errorf("prepare rename failed: incorrect range got %v want %v", *got, want.Range) t.Errorf("prepare rename failed: incorrect range got %v want %v", *got, want.Range)
} }
} }
}
func applyEdits(contents string, edits []diff.TextEdit) string { func applyEdits(contents string, edits []diff.TextEdit) string {
res := contents res := contents
@ -640,8 +620,7 @@ func applyEdits(contents string, edits []diff.TextEdit) string {
return res return res
} }
func (r *runner) Symbol(t *testing.T, data tests.Symbols) { func (r *runner) Symbol(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) {
for uri, expectedSymbols := range data {
params := &protocol.DocumentSymbolParams{ params := &protocol.DocumentSymbolParams{
TextDocument: protocol.TextDocumentIdentifier{ TextDocument: protocol.TextDocumentIdentifier{
URI: string(uri), URI: string(uri),
@ -654,13 +633,12 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
if len(symbols) != len(expectedSymbols) { if len(symbols) != len(expectedSymbols) {
t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols)) t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
continue return
} }
if diff := r.diffSymbols(t, uri, expectedSymbols, symbols); diff != "" { if diff := r.diffSymbols(t, uri, expectedSymbols, symbols); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func (r *runner) diffSymbols(t *testing.T, uri span.URI, want []protocol.DocumentSymbol, got []protocol.DocumentSymbol) string { func (r *runner) diffSymbols(t *testing.T, uri span.URI, want []protocol.DocumentSymbol, got []protocol.DocumentSymbol) string {
sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name }) sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name })
@ -705,8 +683,7 @@ func summarizeSymbols(t *testing.T, i int, want, got []protocol.DocumentSymbol,
return msg.String() return msg.String()
} }
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) { func (r *runner) SignatureHelp(t *testing.T, spn span.Span, expectedSignature *source.SignatureInformation) {
for spn, expectedSignatures := range data {
m, err := r.data.Mapper(spn.URI()) m, err := r.data.Mapper(spn.URI())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -727,25 +704,24 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
gotSignatures, err := r.server.SignatureHelp(r.ctx, params) gotSignatures, err := r.server.SignatureHelp(r.ctx, params)
if err != nil { if err != nil {
// Only fail if we got an error we did not expect. // Only fail if we got an error we did not expect.
if expectedSignatures != nil { if expectedSignature != nil {
t.Fatal(err) t.Fatal(err)
} }
continue return
} }
if expectedSignatures == nil { if expectedSignature == nil {
if gotSignatures != nil { if gotSignatures != nil {
t.Errorf("expected no signature, got %v", gotSignatures) t.Errorf("expected no signature, got %v", gotSignatures)
} }
continue return
} }
if gotSignatures == nil { if gotSignatures == nil {
t.Fatalf("expected %v, got nil", expectedSignatures) t.Fatalf("expected %v, got nil", expectedSignature)
} }
if diff := diffSignatures(spn, expectedSignatures, gotSignatures); diff != "" { if diff := diffSignatures(spn, expectedSignature, gotSignatures); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func diffSignatures(spn span.Span, want *source.SignatureInformation, got *protocol.SignatureHelp) string { func diffSignatures(spn span.Span, want *source.SignatureInformation, got *protocol.SignatureHelp) string {
decorate := func(f string, args ...interface{}) string { decorate := func(f string, args ...interface{}) string {
@ -782,8 +758,7 @@ func diffSignatures(spn span.Span, want *source.SignatureInformation, got *proto
return "" return ""
} }
func (r *runner) Link(t *testing.T, data tests.Links) { func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
for uri, wantLinks := range data {
m, err := r.data.Mapper(uri) m, err := r.data.Mapper(uri)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -833,7 +808,6 @@ func (r *runner) Link(t *testing.T, data tests.Links) {
t.Errorf("missing link %v:%v\n", spn, target) t.Errorf("missing link %v:%v\n", spn, target)
} }
} }
}
func TestBytesOffset(t *testing.T) { func TestBytesOffset(t *testing.T) {
tests := []struct { tests := []struct {

View File

@ -63,8 +63,7 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
tests.Run(t, r, data) tests.Run(t, r, data)
} }
func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) { func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnostic) {
for uri, want := range data {
f, err := r.view.GetFile(r.ctx, uri) f, err := r.view.GetFile(r.ctx, uri)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -79,16 +78,14 @@ func (r *runner) Diagnostics(t *testing.T, data tests.Diagnostics) {
if len(got) != 0 { if len(got) != 0 {
t.Errorf("expected no diagnostics for %s, got %v", uri, got) t.Errorf("expected no diagnostics for %s, got %v", uri, got)
} }
continue return
} }
if diff := tests.DiffDiagnostics(uri, want, got); diff != "" { if diff := tests.DiffDiagnostics(uri, want, got); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func (r *runner) Completion(t *testing.T, data tests.Completions, items tests.CompletionItems) { func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -111,11 +108,8 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, items tests.Co
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) CompletionSnippets(t *testing.T, data tests.CompletionSnippets, items tests.CompletionItems) { func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.CompletionSnippet, placeholders bool, items tests.CompletionItems) {
for _, placeholders := range []bool{true, false} {
for src, expected := range data {
_, list := r.callCompletion(t, src, source.CompletionOptions{ _, list := r.callCompletion(t, src, source.CompletionOptions{
Placeholders: placeholders, Placeholders: placeholders,
Deep: true, Deep: true,
@ -130,11 +124,8 @@ func (r *runner) CompletionSnippets(t *testing.T, data tests.CompletionSnippets,
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
}
func (r *runner) UnimportedCompletions(t *testing.T, data tests.UnimportedCompletions, items tests.CompletionItems) { func (r *runner) UnimportedCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -149,10 +140,8 @@ func (r *runner) UnimportedCompletions(t *testing.T, data tests.UnimportedComple
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) DeepCompletions(t *testing.T, data tests.DeepCompletions, items tests.CompletionItems) { func (r *runner) DeepCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -177,10 +166,8 @@ func (r *runner) DeepCompletions(t *testing.T, data tests.DeepCompletions, items
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, items tests.CompletionItems) { func (r *runner) FuzzyCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -208,10 +195,8 @@ func (r *runner) FuzzyCompletions(t *testing.T, data tests.FuzzyCompletions, ite
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitiveCompletions, items tests.CompletionItems) { func (r *runner) CaseSensitiveCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -226,10 +211,8 @@ func (r *runner) CaseSensitiveCompletions(t *testing.T, data tests.CaseSensitive
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items tests.CompletionItems) { func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) {
for src, test := range data {
var want []protocol.CompletionItem var want []protocol.CompletionItem
for _, pos := range test.CompletionItems { for _, pos := range test.CompletionItems {
want = append(want, tests.ToProtocolCompletionItem(*items[pos])) want = append(want, tests.ToProtocolCompletionItem(*items[pos]))
@ -254,7 +237,6 @@ func (r *runner) RankCompletions(t *testing.T, data tests.RankCompletions, items
t.Errorf("%s: %s", src, msg) t.Errorf("%s: %s", src, msg)
} }
} }
}
func (r *runner) callCompletion(t *testing.T, src span.Span, options source.CompletionOptions) (string, []protocol.CompletionItem) { func (r *runner) callCompletion(t *testing.T, src span.Span, options source.CompletionOptions) (string, []protocol.CompletionItem) {
f, err := r.view.GetFile(r.ctx, src.URI()) f, err := r.view.GetFile(r.ctx, src.URI())
@ -295,8 +277,7 @@ func (r *runner) callCompletion(t *testing.T, src span.Span, options source.Comp
return prefix, tests.ToProtocolCompletionItems(items) return prefix, tests.ToProtocolCompletionItems(items)
} }
func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) { func (r *runner) FoldingRange(t *testing.T, spn span.Span) {
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
f, err := r.view.GetFile(r.ctx, uri) f, err := r.view.GetFile(r.ctx, uri)
@ -306,14 +287,14 @@ func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
data, _, err := f.Handle(r.ctx).Read(r.ctx) data, _, err := f.Handle(r.ctx).Read(r.ctx)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
// Test all folding ranges. // Test all folding ranges.
ranges, err := source.FoldingRange(r.ctx, r.view, f.(source.GoFile), false) ranges, err := source.FoldingRange(r.ctx, r.view, f.(source.GoFile), false)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
r.foldingRanges(t, "foldingRange", uri, string(data), ranges) r.foldingRanges(t, "foldingRange", uri, string(data), ranges)
@ -321,11 +302,9 @@ func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
ranges, err = source.FoldingRange(r.ctx, r.view, f.(source.GoFile), true) ranges, err = source.FoldingRange(r.ctx, r.view, f.(source.GoFile), true)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
r.foldingRanges(t, "foldingRange-lineFolding", uri, string(data), ranges) r.foldingRanges(t, "foldingRange-lineFolding", uri, string(data), ranges)
}
} }
func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, data string, ranges []*source.FoldingRangeInfo) { func (r *runner) foldingRanges(t *testing.T, prefix string, uri span.URI, data string, ranges []*source.FoldingRangeInfo) {
@ -435,9 +414,8 @@ func foldRanges(contents string, ranges []*source.FoldingRangeInfo) (string, err
return res, nil return res, nil
} }
func (r *runner) Format(t *testing.T, data tests.Formats) { func (r *runner) Format(t *testing.T, spn span.Span) {
ctx := r.ctx ctx := r.ctx
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
filename := uri.Filename() filename := uri.Filename()
gofmted := string(r.data.Golden("gofmt", filename, func() ([]byte, error) { gofmted := string(r.data.Golden("gofmt", filename, func() ([]byte, error) {
@ -454,7 +432,7 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
if gofmted != "" { if gofmted != "" {
t.Error(err) t.Error(err)
} }
continue return
} }
data, _, err := f.Handle(ctx).Read(ctx) data, _, err := f.Handle(ctx).Read(ctx)
if err != nil { if err != nil {
@ -473,11 +451,9 @@ func (r *runner) Format(t *testing.T, data tests.Formats) {
t.Errorf("format failed for %s, expected:\n%v\ngot:\n%v", filename, gofmted, got) t.Errorf("format failed for %s, expected:\n%v\ngot:\n%v", filename, gofmted, got)
} }
} }
}
func (r *runner) Import(t *testing.T, data tests.Imports) { func (r *runner) Import(t *testing.T, spn span.Span) {
ctx := r.ctx ctx := r.ctx
for _, spn := range data {
uri := spn.URI() uri := spn.URI()
filename := uri.Filename() filename := uri.Filename()
goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) { goimported := string(r.data.Golden("goimports", filename, func() ([]byte, error) {
@ -503,7 +479,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
if goimported != "" { if goimported != "" {
t.Error(err) t.Error(err)
} }
continue return
} }
data, _, err := fh.Read(ctx) data, _, err := fh.Read(ctx)
if err != nil { if err != nil {
@ -522,14 +498,12 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got) t.Errorf("import failed for %s, expected:\n%v\ngot:\n%v", filename, goimported, got)
} }
} }
func (r *runner) SuggestedFix(t *testing.T, spn span.Span) {
} }
func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) { func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
}
func (r *runner) Definition(t *testing.T, data tests.Definitions) {
ctx := r.ctx ctx := r.ctx
for _, d := range data {
f, err := r.view.GetFile(ctx, d.Src.URI()) f, err := r.view.GetFile(ctx, d.Src.URI())
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", d.Src, err) t.Fatalf("failed for %v: %v", d.Src, err)
@ -580,11 +554,9 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
t.Errorf("no tests ran for %s", d.Src.URI()) t.Errorf("no tests ran for %s", d.Src.URI())
} }
} }
}
func (r *runner) Highlight(t *testing.T, data tests.Highlights) { func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
ctx := r.ctx ctx := r.ctx
for name, locations := range data {
src := locations[0] src := locations[0]
m, srcRng, err := spanToRange(r.data, src) m, srcRng, err := spanToRange(r.data, src)
if err != nil { if err != nil {
@ -607,11 +579,9 @@ func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
} }
} }
} }
}
func (r *runner) Reference(t *testing.T, data tests.References) { func (r *runner) Reference(t *testing.T, src span.Span, itemList []span.Span) {
ctx := r.ctx ctx := r.ctx
for src, itemList := range data {
f, err := r.view.GetFile(ctx, src.URI()) f, err := r.view.GetFile(ctx, src.URI())
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
@ -654,11 +624,9 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
} }
} }
} }
}
func (r *runner) Rename(t *testing.T, data tests.Renames) { func (r *runner) Rename(t *testing.T, spn span.Span, newText string) {
ctx := r.ctx ctx := r.ctx
for spn, newText := range data {
tag := fmt.Sprintf("%s-rename", newText) tag := fmt.Sprintf("%s-rename", newText)
f, err := r.view.GetFile(ctx, spn.URI()) f, err := r.view.GetFile(ctx, spn.URI())
@ -672,7 +640,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
ident, err := source.Identifier(r.ctx, r.view, f.(source.GoFile), srcRng.Start) ident, err := source.Identifier(r.ctx, r.view, f.(source.GoFile), srcRng.Start)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue return
} }
changes, err := ident.Rename(r.ctx, r.view, newText) changes, err := ident.Rename(r.ctx, r.view, newText)
if err != nil { if err != nil {
@ -682,7 +650,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
if err.Error() != renamed { if err.Error() != renamed {
t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v\n", newText, renamed, err) t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v\n", newText, renamed, err)
} }
continue return
} }
var res []string var res []string
@ -731,7 +699,6 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v", newText, renamed, got) t.Errorf("rename failed for %s, expected:\n%v\ngot:\n%v", newText, renamed, got)
} }
} }
}
func applyEdits(contents string, edits []diff.TextEdit) string { func applyEdits(contents string, edits []diff.TextEdit) string {
res := contents res := contents
@ -748,9 +715,8 @@ func applyEdits(contents string, edits []diff.TextEdit) string {
return res return res
} }
func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) { func (r *runner) PrepareRename(t *testing.T, src span.Span, want *source.PrepareItem) {
ctx := context.Background() ctx := context.Background()
for src, want := range data {
f, err := r.view.GetFile(ctx, src.URI()) f, err := r.view.GetFile(ctx, src.URI())
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
@ -765,27 +731,25 @@ func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) {
if want.Text != "" { // expected an ident. if want.Text != "" { // expected an ident.
t.Errorf("prepare rename failed for %v: got error: %v", src, err) t.Errorf("prepare rename failed for %v: got error: %v", src, err)
} }
continue return
} }
if item == nil { if item == nil {
if want.Text != "" { if want.Text != "" {
t.Errorf("prepare rename failed for %v: got nil", src) t.Errorf("prepare rename failed for %v: got nil", src)
} }
continue return
} }
if want.Text == "" && item != nil { if want.Text == "" && item != nil {
t.Errorf("prepare rename failed for %v: expected nil, got %v", src, item) t.Errorf("prepare rename failed for %v: expected nil, got %v", src, item)
continue return
} }
if protocol.CompareRange(want.Range, item.Range) != 0 { if protocol.CompareRange(want.Range, item.Range) != 0 {
t.Errorf("prepare rename failed: incorrect range got %v want %v", item.Range, want.Range) t.Errorf("prepare rename failed: incorrect range got %v want %v", item.Range, want.Range)
} }
} }
}
func (r *runner) Symbol(t *testing.T, data tests.Symbols) { func (r *runner) Symbol(t *testing.T, uri span.URI, expectedSymbols []protocol.DocumentSymbol) {
ctx := r.ctx ctx := r.ctx
for uri, expectedSymbols := range data {
f, err := r.view.GetFile(ctx, uri) f, err := r.view.GetFile(ctx, uri)
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", uri, err) t.Fatalf("failed for %v: %v", uri, err)
@ -796,13 +760,12 @@ func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
} }
if len(symbols) != len(expectedSymbols) { if len(symbols) != len(expectedSymbols) {
t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols)) t.Errorf("want %d top-level symbols in %v, got %d", len(expectedSymbols), uri, len(symbols))
continue return
} }
if diff := r.diffSymbols(t, uri, expectedSymbols, symbols); diff != "" { if diff := r.diffSymbols(t, uri, expectedSymbols, symbols); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func (r *runner) diffSymbols(t *testing.T, uri span.URI, want, got []protocol.DocumentSymbol) string { func (r *runner) diffSymbols(t *testing.T, uri span.URI, want, got []protocol.DocumentSymbol) string {
sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name }) sort.Slice(want, func(i, j int) bool { return want[i].Name < want[j].Name })
@ -847,9 +810,8 @@ func summarizeSymbols(t *testing.T, i int, want, got []protocol.DocumentSymbol,
return msg.String() return msg.String()
} }
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) { func (r *runner) SignatureHelp(t *testing.T, spn span.Span, expectedSignature *source.SignatureInformation) {
ctx := r.ctx ctx := r.ctx
for spn, expectedSignature := range data {
f, err := r.view.GetFile(ctx, spn.URI()) f, err := r.view.GetFile(ctx, spn.URI())
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", spn, err) t.Fatalf("failed for %v: %v", spn, err)
@ -869,13 +831,12 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
if gotSignature != nil { if gotSignature != nil {
t.Errorf("expected no signature, got %v", gotSignature) t.Errorf("expected no signature, got %v", gotSignature)
} }
continue return
} }
if diff := diffSignatures(spn, expectedSignature, gotSignature); diff != "" { if diff := diffSignatures(spn, expectedSignature, gotSignature); diff != "" {
t.Error(diff) t.Error(diff)
} }
} }
}
func diffSignatures(spn span.Span, want *source.SignatureInformation, got *source.SignatureInformation) string { func diffSignatures(spn span.Span, want *source.SignatureInformation, got *source.SignatureInformation) string {
decorate := func(f string, args ...interface{}) string { decorate := func(f string, args ...interface{}) string {
@ -898,7 +859,7 @@ func diffSignatures(spn span.Span, want *source.SignatureInformation, got *sourc
return "" return ""
} }
func (r *runner) Link(t *testing.T, data tests.Links) { func (r *runner) Link(t *testing.T, uri span.URI, wantLinks []tests.Link) {
// This is a pure LSP feature, no source level functionality to be tested. // This is a pure LSP feature, no source level functionality to be tested.
} }

View File

@ -96,26 +96,26 @@ type Data struct {
} }
type Tests interface { type Tests interface {
Diagnostics(*testing.T, Diagnostics) Diagnostics(*testing.T, span.URI, []source.Diagnostic)
Completion(*testing.T, Completions, CompletionItems) Completion(*testing.T, span.Span, Completion, CompletionItems)
CompletionSnippets(*testing.T, CompletionSnippets, CompletionItems) CompletionSnippet(*testing.T, span.Span, CompletionSnippet, bool, CompletionItems)
UnimportedCompletions(*testing.T, UnimportedCompletions, CompletionItems) UnimportedCompletion(*testing.T, span.Span, Completion, CompletionItems)
DeepCompletions(*testing.T, DeepCompletions, CompletionItems) DeepCompletion(*testing.T, span.Span, Completion, CompletionItems)
FuzzyCompletions(*testing.T, FuzzyCompletions, CompletionItems) FuzzyCompletion(*testing.T, span.Span, Completion, CompletionItems)
CaseSensitiveCompletions(*testing.T, CaseSensitiveCompletions, CompletionItems) CaseSensitiveCompletion(*testing.T, span.Span, Completion, CompletionItems)
RankCompletions(*testing.T, RankCompletions, CompletionItems) RankCompletion(*testing.T, span.Span, Completion, CompletionItems)
FoldingRange(*testing.T, FoldingRanges) FoldingRange(*testing.T, span.Span)
Format(*testing.T, Formats) Format(*testing.T, span.Span)
Import(*testing.T, Imports) Import(*testing.T, span.Span)
SuggestedFix(*testing.T, SuggestedFixes) SuggestedFix(*testing.T, span.Span)
Definition(*testing.T, Definitions) Definition(*testing.T, span.Span, Definition)
Highlight(*testing.T, Highlights) Highlight(*testing.T, string, []span.Span)
Reference(*testing.T, References) Reference(*testing.T, span.Span, []span.Span)
Rename(*testing.T, Renames) Rename(*testing.T, span.Span, string)
PrepareRename(*testing.T, PrepareRenames) PrepareRename(*testing.T, span.Span, *source.PrepareItem)
Symbol(*testing.T, Symbols) Symbol(*testing.T, span.URI, []protocol.DocumentSymbol)
SignatureHelp(*testing.T, Signatures) SignatureHelp(*testing.T, span.Span, *source.SignatureInformation)
Link(*testing.T, Links) Link(*testing.T, span.URI, []Link)
} }
type Definition struct { type Definition struct {
@ -327,102 +327,144 @@ func Run(t *testing.T, tests Tests, data *Data) {
t.Run("Completion", func(t *testing.T) { t.Run("Completion", func(t *testing.T) {
t.Helper() t.Helper()
tests.Completion(t, data.Completions, data.CompletionItems) for src, test := range data.Completions {
tests.Completion(t, src, test, data.CompletionItems)
}
}) })
t.Run("CompletionSnippets", func(t *testing.T) { t.Run("CompletionSnippets", func(t *testing.T) {
t.Helper() t.Helper()
tests.CompletionSnippets(t, data.CompletionSnippets, data.CompletionItems) for _, placeholders := range []bool{true, false} {
for src, expected := range data.CompletionSnippets {
tests.CompletionSnippet(t, src, expected, placeholders, data.CompletionItems)
}
}
}) })
t.Run("UnimportedCompletion", func(t *testing.T) { t.Run("UnimportedCompletion", func(t *testing.T) {
t.Helper() t.Helper()
tests.UnimportedCompletions(t, data.UnimportedCompletions, data.CompletionItems) for src, test := range data.UnimportedCompletions {
tests.UnimportedCompletion(t, src, test, data.CompletionItems)
}
}) })
t.Run("DeepCompletion", func(t *testing.T) { t.Run("DeepCompletion", func(t *testing.T) {
t.Helper() t.Helper()
tests.DeepCompletions(t, data.DeepCompletions, data.CompletionItems) for src, test := range data.DeepCompletions {
tests.DeepCompletion(t, src, test, data.CompletionItems)
}
}) })
t.Run("FuzzyCompletion", func(t *testing.T) { t.Run("FuzzyCompletion", func(t *testing.T) {
t.Helper() t.Helper()
tests.FuzzyCompletions(t, data.FuzzyCompletions, data.CompletionItems) for src, test := range data.FuzzyCompletions {
tests.FuzzyCompletion(t, src, test, data.CompletionItems)
}
}) })
t.Run("CaseSensitiveCompletion", func(t *testing.T) { t.Run("CaseSensitiveCompletion", func(t *testing.T) {
t.Helper() t.Helper()
tests.CaseSensitiveCompletions(t, data.CaseSensitiveCompletions, data.CompletionItems) for src, test := range data.CaseSensitiveCompletions {
tests.CaseSensitiveCompletion(t, src, test, data.CompletionItems)
}
}) })
t.Run("RankCompletions", func(t *testing.T) { t.Run("RankCompletions", func(t *testing.T) {
t.Helper() t.Helper()
tests.RankCompletions(t, data.RankCompletions, data.CompletionItems) for src, test := range data.RankCompletions {
tests.RankCompletion(t, src, test, data.CompletionItems)
}
}) })
t.Run("Diagnostics", func(t *testing.T) { t.Run("Diagnostics", func(t *testing.T) {
t.Helper() t.Helper()
tests.Diagnostics(t, data.Diagnostics) for uri, want := range data.Diagnostics {
tests.Diagnostics(t, uri, want)
}
}) })
t.Run("FoldingRange", func(t *testing.T) { t.Run("FoldingRange", func(t *testing.T) {
t.Helper() t.Helper()
tests.FoldingRange(t, data.FoldingRanges) for _, spn := range data.FoldingRanges {
tests.FoldingRange(t, spn)
}
}) })
t.Run("Format", func(t *testing.T) { t.Run("Format", func(t *testing.T) {
t.Helper() t.Helper()
tests.Format(t, data.Formats) for _, spn := range data.Formats {
tests.Format(t, spn)
}
}) })
t.Run("Import", func(t *testing.T) { t.Run("Import", func(t *testing.T) {
t.Helper() t.Helper()
tests.Import(t, data.Imports) for _, spn := range data.Imports {
tests.Import(t, spn)
}
}) })
t.Run("SuggestedFix", func(t *testing.T) { t.Run("SuggestedFix", func(t *testing.T) {
t.Helper() t.Helper()
tests.SuggestedFix(t, data.SuggestedFixes) for _, spn := range data.SuggestedFixes {
tests.SuggestedFix(t, spn)
}
}) })
t.Run("Definition", func(t *testing.T) { t.Run("Definition", func(t *testing.T) {
t.Helper() t.Helper()
tests.Definition(t, data.Definitions) for spn, d := range data.Definitions {
tests.Definition(t, spn, d)
}
}) })
t.Run("Highlight", func(t *testing.T) { t.Run("Highlight", func(t *testing.T) {
t.Helper() t.Helper()
tests.Highlight(t, data.Highlights) for name, locations := range data.Highlights {
tests.Highlight(t, name, locations)
}
}) })
t.Run("References", func(t *testing.T) { t.Run("References", func(t *testing.T) {
t.Helper() t.Helper()
tests.Reference(t, data.References) for src, itemList := range data.References {
tests.Reference(t, src, itemList)
}
}) })
t.Run("Renames", func(t *testing.T) { t.Run("Renames", func(t *testing.T) {
t.Helper() t.Helper()
tests.Rename(t, data.Renames) for spn, newText := range data.Renames {
tests.Rename(t, spn, newText)
}
}) })
t.Run("PrepareRenames", func(t *testing.T) { t.Run("PrepareRenames", func(t *testing.T) {
t.Helper() t.Helper()
tests.PrepareRename(t, data.PrepareRenames) for src, want := range data.PrepareRenames {
tests.PrepareRename(t, src, want)
}
}) })
t.Run("Symbols", func(t *testing.T) { t.Run("Symbols", func(t *testing.T) {
t.Helper() t.Helper()
tests.Symbol(t, data.Symbols) for uri, expectedSymbols := range data.Symbols {
tests.Symbol(t, uri, expectedSymbols)
}
}) })
t.Run("SignatureHelp", func(t *testing.T) { t.Run("SignatureHelp", func(t *testing.T) {
t.Helper() t.Helper()
tests.SignatureHelp(t, data.Signatures) for spn, expectedSignature := range data.Signatures {
tests.SignatureHelp(t, spn, expectedSignature)
}
}) })
t.Run("Link", func(t *testing.T) { t.Run("Link", func(t *testing.T) {
t.Helper() t.Helper()
tests.Link(t, data.Links) for uri, wantLinks := range data.Links {
tests.Link(t, uri, wantLinks)
}
}) })
if *UpdateGolden { if *UpdateGolden {