mirror of
https://github.com/golang/go.git
synced 2025-05-28 02:41:30 +00:00
This walks the list produced by the MustCopyFileTree call instead of scanning the file system It also removes the .in file from the copies, so only the trimmed version will be present in the exported data set. Change-Id: I95b0298ab49021a09f6b26e08158ce162b5a99e6 Reviewed-on: https://go-review.googlesource.com/c/149614 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
200 lines
5.4 KiB
Go
200 lines
5.4 KiB
Go
// Copyright 2018 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 lsp
|
|
|
|
import (
|
|
"context"
|
|
"go/token"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/tools/go/packages"
|
|
"golang.org/x/tools/go/packages/packagestest"
|
|
"golang.org/x/tools/internal/lsp/protocol"
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
)
|
|
|
|
func TestLSP(t *testing.T) {
|
|
packagestest.TestAll(t, testLSP)
|
|
}
|
|
|
|
func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|
const dir = "testdata"
|
|
|
|
files := packagestest.MustCopyFileTree(dir)
|
|
for fragment, operation := range files {
|
|
if trimmed := strings.TrimSuffix(fragment, ".in"); trimmed != fragment {
|
|
delete(files, fragment)
|
|
files[trimmed] = operation
|
|
}
|
|
}
|
|
modules := []packagestest.Module{
|
|
{
|
|
Name: "golang.org/x/tools/internal/lsp",
|
|
Files: files,
|
|
},
|
|
}
|
|
exported := packagestest.Export(t, exporter, modules)
|
|
defer exported.Cleanup()
|
|
|
|
dirs := make(map[string]bool)
|
|
|
|
// collect results for certain tests
|
|
expectedDiagnostics := make(map[string][]protocol.Diagnostic)
|
|
expectedCompletions := make(map[token.Position]*protocol.CompletionItem)
|
|
|
|
s := &server{
|
|
view: source.NewView(),
|
|
}
|
|
// merge the config objects
|
|
cfg := *exported.Config
|
|
cfg.Fset = s.view.Config.Fset
|
|
cfg.Mode = packages.LoadSyntax
|
|
s.view.Config = &cfg
|
|
|
|
for _, module := range modules {
|
|
for fragment := range module.Files {
|
|
if !strings.HasSuffix(fragment, ".go") {
|
|
continue
|
|
}
|
|
filename := exporter.Filename(exported, module.Name, fragment)
|
|
expectedDiagnostics[filename] = []protocol.Diagnostic{}
|
|
dirs[filepath.Dir(filename)] = true
|
|
}
|
|
}
|
|
// Do a first pass to collect special markers
|
|
if err := exported.Expect(map[string]interface{}{
|
|
"item": func(name string, r packagestest.Range, _, _ string) {
|
|
exported.Mark(name, r)
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Collect any data that needs to be used by subsequent tests.
|
|
if err := exported.Expect(map[string]interface{}{
|
|
"diag": func(pos token.Position, msg string) {
|
|
line := float64(pos.Line - 1)
|
|
col := float64(pos.Column - 1)
|
|
want := protocol.Diagnostic{
|
|
Range: protocol.Range{
|
|
Start: protocol.Position{
|
|
Line: line,
|
|
Character: col,
|
|
},
|
|
End: protocol.Position{
|
|
Line: line,
|
|
Character: col,
|
|
},
|
|
},
|
|
Severity: protocol.SeverityError,
|
|
Source: "LSP",
|
|
Message: msg,
|
|
}
|
|
if _, ok := expectedDiagnostics[pos.Filename]; ok {
|
|
expectedDiagnostics[pos.Filename] = append(expectedDiagnostics[pos.Filename], want)
|
|
} else {
|
|
t.Errorf("unexpected filename: %v", pos.Filename)
|
|
}
|
|
},
|
|
"item": func(pos token.Position, label, detail, kind string) {
|
|
var k protocol.CompletionItemKind
|
|
switch kind {
|
|
case "struct":
|
|
k = protocol.StructCompletion
|
|
case "func":
|
|
k = protocol.FunctionCompletion
|
|
case "var":
|
|
k = protocol.VariableCompletion
|
|
case "type":
|
|
k = protocol.TypeParameterCompletion
|
|
case "field":
|
|
k = protocol.FieldCompletion
|
|
case "interface":
|
|
k = protocol.InterfaceCompletion
|
|
case "const":
|
|
k = protocol.ConstantCompletion
|
|
case "method":
|
|
k = protocol.MethodCompletion
|
|
}
|
|
expectedCompletions[pos] = &protocol.CompletionItem{
|
|
Label: label,
|
|
Detail: detail,
|
|
Kind: float64(k),
|
|
}
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// test completion
|
|
testCompletion(t, exported, s, expectedCompletions)
|
|
|
|
// test diagnostics
|
|
var dirList []string
|
|
for dir := range dirs {
|
|
dirList = append(dirList, dir)
|
|
}
|
|
exported.Config.Mode = packages.LoadFiles
|
|
pkgs, err := packages.Load(exported.Config, dirList...)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
testDiagnostics(t, s.view, pkgs, expectedDiagnostics)
|
|
}
|
|
|
|
func testDiagnostics(t *testing.T, v *source.View, pkgs []*packages.Package, wants map[string][]protocol.Diagnostic) {
|
|
for _, pkg := range pkgs {
|
|
for _, filename := range pkg.GoFiles {
|
|
f := v.GetFile(source.ToURI(filename))
|
|
diagnostics, err := source.Diagnostics(context.Background(), v, f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := toProtocolDiagnostics(v, diagnostics[filename])
|
|
sort.Slice(got, func(i int, j int) bool {
|
|
return got[i].Range.Start.Line < got[j].Range.Start.Line
|
|
})
|
|
want := wants[filename]
|
|
if equal := reflect.DeepEqual(want, got); !equal {
|
|
t.Errorf("diagnostics failed for %s: (expected: %v), (got: %v)", filepath.Base(filename), want, got)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func testCompletion(t *testing.T, exported *packagestest.Exported, s *server, wants map[token.Position]*protocol.CompletionItem) {
|
|
if err := exported.Expect(map[string]interface{}{
|
|
"complete": func(src token.Position, expected []token.Position) {
|
|
var want []protocol.CompletionItem
|
|
for _, pos := range expected {
|
|
want = append(want, *wants[pos])
|
|
}
|
|
list, err := s.Completion(context.Background(), &protocol.CompletionParams{
|
|
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
|
|
TextDocument: protocol.TextDocumentIdentifier{
|
|
URI: protocol.DocumentURI(source.ToURI(src.Filename)),
|
|
},
|
|
Position: protocol.Position{
|
|
Line: float64(src.Line - 1),
|
|
Character: float64(src.Column - 1),
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := list.Items
|
|
if equal := reflect.DeepEqual(want, got); !equal {
|
|
t.Errorf("completion failed for %s:%v:%v: (expected: %v), (got: %v)", filepath.Base(src.Filename), src.Line, src.Column, want, got)
|
|
}
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|