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,60 +11,58 @@ 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 == "" { return
}
fname := uri.Filename()
args := []string{"-remote=internal", "check", fname}
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env)
out := CaptureStdOut(t, func() {
_ = tool.Run(r.ctx, app, args)
})
// parse got into a collection of reports
got := map[string]struct{}{}
for _, l := range strings.Split(out, "\n") {
if len(l) == 0 {
continue continue
} }
fname := uri.Filename() // parse and reprint to normalize the span
args := []string{"-remote=internal", "check", fname} bits := strings.SplitN(l, ": ", 2)
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env) if len(bits) == 2 {
out := CaptureStdOut(t, func() { spn := span.Parse(strings.TrimSpace(bits[0]))
_ = tool.Run(r.ctx, app, args) spn = span.New(spn.URI(), spn.Start(), span.Point{})
}) data, err := ioutil.ReadFile(fname)
// parse got into a collection of reports if err != nil {
got := map[string]struct{}{} t.Fatal(err)
for _, l := range strings.Split(out, "\n") {
if len(l) == 0 {
continue
} }
// parse and reprint to normalize the span converter := span.NewContentConverter(fname, data)
bits := strings.SplitN(l, ": ", 2) s, err := spn.WithPosition(converter)
if len(bits) == 2 { if err != nil {
spn := span.Parse(strings.TrimSpace(bits[0])) t.Fatal(err)
spn = span.New(spn.URI(), spn.Start(), span.Point{})
data, err := ioutil.ReadFile(fname)
if err != nil {
t.Fatal(err)
}
converter := span.NewContentConverter(fname, data)
s, err := spn.WithPosition(converter)
if err != nil {
t.Fatal(err)
}
l = fmt.Sprintf("%s: %s", s, strings.TrimSpace(bits[1]))
} }
got[l] = struct{}{} l = fmt.Sprintf("%s: %s", s, strings.TrimSpace(bits[1]))
} }
for _, diag := range want { got[l] = struct{}{}
expect := fmt.Sprintf("%v:%v:%v: %v", diag.URI.Filename(), diag.Range.Start.Line+1, diag.Range.Start.Character+1, diag.Message) }
if diag.Range.Start.Character == 0 { for _, diag := range want {
expect = fmt.Sprintf("%v:%v: %v", diag.URI.Filename(), diag.Range.Start.Line+1, diag.Message) expect := fmt.Sprintf("%v:%v:%v: %v", diag.URI.Filename(), diag.Range.Start.Line+1, diag.Range.Start.Character+1, diag.Message)
} if diag.Range.Start.Character == 0 {
_, found := got[expect] expect = fmt.Sprintf("%v:%v: %v", diag.URI.Filename(), diag.Range.Start.Line+1, diag.Message)
if !found {
t.Errorf("missing diagnostic %q", expect)
} else {
delete(got, expect)
}
} }
for extra, _ := range got { _, found := got[expect]
t.Errorf("extra diagnostic %q", extra) if !found {
t.Errorf("missing diagnostic %q", expect)
} else {
delete(got, expect)
} }
} }
for extra, _ := range got {
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,41 +33,39 @@ 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 return
continue }
d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{})
for _, mode := range godefModes {
args := []string{"-remote=internal", "query"}
tag := d.Name + "-definition"
if mode&jsonGoDef != 0 {
tag += "-json"
args = append(args, "-json")
} }
d.Src = span.New(d.Src.URI(), span.NewPoint(0, 0, d.Src.Start().Offset()), span.Point{}) args = append(args, "definition")
for _, mode := range godefModes { uri := d.Src.URI()
args := []string{"-remote=internal", "query"} args = append(args, fmt.Sprint(d.Src))
tag := d.Name + "-definition" got := CaptureStdOut(t, func() {
if mode&jsonGoDef != 0 { app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env)
tag += "-json" _ = tool.Run(r.ctx, app, args)
args = append(args, "-json") })
} got = normalizePaths(r.data, got)
args = append(args, "definition") if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
uri := d.Src.URI() got = strings.Replace(got, "file:///", "file://", -1)
args = append(args, fmt.Sprint(d.Src)) }
got := CaptureStdOut(t, func() { expect := strings.TrimSpace(string(r.data.Golden(tag, uri.Filename(), func() ([]byte, error) {
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Exported.Config.Env) return []byte(got), nil
_ = tool.Run(r.ctx, app, args) })))
}) if expect != "" && !strings.HasPrefix(got, expect) {
got = normalizePaths(r.data, got) t.Errorf("definition %v failed with %#v expected:\n%q\ngot:\n%q", tag, args, expect, got)
if mode&jsonGoDef != 0 && runtime.GOOS == "windows" {
got = strings.Replace(got, "file:///", "file://", -1)
}
expect := strings.TrimSpace(string(r.data.Golden(tag, uri.Filename(), func() ([]byte, error) {
return []byte(got), nil
})))
if expect != "" && !strings.HasPrefix(got, expect) {
t.Errorf("definition %v failed with %#v expected:\n%q\ngot:\n%q", tag, args, expect, got)
}
} }
} }
} }

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,32 +20,30 @@ 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() filename := uri.Filename()
filename := uri.Filename() args := append(mode, filename)
args := append(mode, filename) expect := string(r.data.Golden(tag, filename, func() ([]byte, error) {
expect := string(r.data.Golden(tag, filename, func() ([]byte, error) { cmd := exec.Command("gofmt", args...)
cmd := exec.Command("gofmt", args...) contents, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files
contents, _ := cmd.Output() // ignore error, sometimes we have intentionally ungofmt-able files contents = []byte(normalizePaths(r.data, fixFileHeader(string(contents))))
contents = []byte(normalizePaths(r.data, fixFileHeader(string(contents)))) return contents, nil
return contents, nil }))
})) if expect == "" {
if expect == "" { //TODO: our error handling differs, for now just skip unformattable files
//TODO: our error handling differs, for now just skip unformattable files continue
continue }
} 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) got := CaptureStdOut(t, func() {
got := CaptureStdOut(t, func() { _ = tool.Run(r.ctx, app, append([]string{"-remote=internal", "format"}, args...))
_ = tool.Run(r.ctx, app, append([]string{"-remote=internal", "format"}, args...)) })
}) got = normalizePaths(r.data, got)
got = normalizePaths(r.data, got) // check the first two lines are the expected file header
// check the first two lines are the expected file header if expect != got {
if expect != got { t.Errorf("format failed with %#v expected:\n%s\ngot:\n%s", args, expect, got)
t.Errorf("format failed with %#v expected:\n%s\ngot:\n%s", args, expect, got)
}
} }
} }
} }

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,45 +19,30 @@ 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 filename := spn.URI().Filename()
for _, spn := range sortedSpans { for _, mode := range renameModes {
tag := data[spn] goldenTag := newText + strings.Join(mode, "") + "-rename"
filename := spn.URI().Filename() app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env)
for _, mode := range renameModes { loc := fmt.Sprintf("%v", spn)
goldenTag := data[spn] + strings.Join(mode, "") + "-rename" args := []string{"-remote=internal", "rename"}
app := cmd.New("gopls-test", r.data.Config.Dir, r.data.Config.Env) if strings.Join(mode, "") != "" {
loc := fmt.Sprintf("%v", spn) args = append(args, strings.Join(mode, ""))
args := []string{"-remote=internal", "rename"} }
if strings.Join(mode, "") != "" { args = append(args, loc, newText)
args = append(args, strings.Join(mode, "")) var err error
} got := CaptureStdOut(t, func() {
args = append(args, loc, tag) err = tool.Run(r.ctx, app, args)
var err error })
got := CaptureStdOut(t, func() { if err != nil {
err = tool.Run(r.ctx, app, args) got = err.Error()
}) }
if err != nil { got = normalizePaths(r.data, got)
got = err.Error() expect := string(r.data.Golden(goldenTag, filename, func() ([]byte, error) {
} return []byte(got), nil
got = normalizePaths(r.data, got) }))
expect := string(r.data.Golden(goldenTag, filename, func() ([]byte, error) { if expect != got {
return []byte(got), nil t.Errorf("rename failed with %#v expected:\n%s\ngot:\n%s", args, expect, got)
}))
if expect != got {
t.Errorf("rename failed with %#v expected:\n%s\ngot:\n%s", args, expect, got)
}
} }
} }
} }
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,119 +11,103 @@ 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, Documentation: true,
Documentation: true, })
}) if !strings.Contains(string(src.URI()), "builtins") {
if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got)
got = tests.FilterBuiltins(got) }
} want := expected(t, test, items)
want := expected(t, test, items) if diff := tests.DiffCompletionItems(want, got); diff != "" {
if diff := tests.DiffCompletionItems(want, got); diff != "" { 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} { list := r.callCompletion(t, src, source.CompletionOptions{
for src, expected := range data { Placeholders: placeholders,
list := r.callCompletion(t, src, source.CompletionOptions{ Deep: true,
Placeholders: placeholders, Budget: 5 * time.Second,
Deep: true, FuzzyMatching: true,
Budget: 5 * time.Second, })
FuzzyMatching: true, got := tests.FindItem(list, *items[expected.CompletionItem])
}) want := expected.PlainSnippet
got := tests.FindItem(list, *items[expected.CompletionItem]) if placeholders {
want := expected.PlainSnippet want = expected.PlaceholderSnippet
if placeholders { }
want = expected.PlaceholderSnippet if diff := tests.DiffSnippets(want, got); diff != "" {
} t.Errorf("%s: %v", src, diff)
if diff := tests.DiffSnippets(want, got); 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, })
}) if !strings.Contains(string(src.URI()), "builtins") {
if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got)
got = tests.FilterBuiltins(got) }
} want := expected(t, test, items)
want := expected(t, test, items) if diff := tests.DiffCompletionItems(want, got); diff != "" {
if diff := tests.DiffCompletionItems(want, got); diff != "" { 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, Documentation: true,
Documentation: true, })
}) if !strings.Contains(string(src.URI()), "builtins") {
if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got)
got = tests.FilterBuiltins(got) }
} want := expected(t, test, items)
want := expected(t, test, items) if msg := tests.DiffCompletionItems(want, got); msg != "" {
if msg := tests.DiffCompletionItems(want, got); msg != "" { 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, Budget: 5 * time.Second,
Budget: 5 * time.Second, })
}) if !strings.Contains(string(src.URI()), "builtins") {
if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got)
got = tests.FilterBuiltins(got) }
} want := expected(t, test, items)
want := expected(t, test, items) if msg := tests.DiffCompletionItems(want, got); msg != "" {
if msg := tests.DiffCompletionItems(want, got); msg != "" { 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, })
}) if !strings.Contains(string(src.URI()), "builtins") {
if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got)
got = tests.FilterBuiltins(got) }
} want := expected(t, test, items)
want := expected(t, test, items) if msg := tests.DiffCompletionItems(want, got); msg != "" {
if msg := tests.DiffCompletionItems(want, got); msg != "" { 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, Budget: 5 * time.Second,
Budget: 5 * time.Second, })
}) want := expected(t, test, items)
want := expected(t, test, items) if msg := tests.CheckCompletionOrder(want, got); msg != "" {
if msg := tests.CheckCompletionOrder(want, got); msg != "" { t.Errorf("%s: %s", src, msg)
t.Errorf("%s: %s", src, msg)
}
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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 {