go/internal/lsp/diagnostics_test.go
Ian Cottrell d0600fd9f1 internal/lsp: make source independent of protocol
I realized this was a mistake, we should try to keep the source
directory independent of the LSP protocol itself, and adapt in
the outer layer.
This will keep us honest about capabilities, let us add the
caching and conversion layers easily, and also allow for a future
where we expose the source directory as a supported API for other
tools.
The outer lsp package then becomes the adapter from the core
features to the specifics of the LSP protocol.

Change-Id: I68fd089f1b9f2fd38decc1cbc13c6f0f86157b94
Reviewed-on: https://go-review.googlesource.com/c/148157
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2018-11-07 18:42:35 +00:00

111 lines
2.9 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 (
"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 TestDiagnostics(t *testing.T) {
packagestest.TestAll(t, testDiagnostics)
}
func testDiagnostics(t *testing.T, exporter packagestest.Exporter) {
files := packagestest.MustCopyFileTree("testdata/diagnostics")
// TODO(rstambler): Stop hardcoding this if we have more files that don't parse.
files["noparse/noparse.go"] = packagestest.Copy("testdata/diagnostics/noparse/noparse.go.in")
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)
wants := make(map[string][]protocol.Diagnostic)
for _, module := range modules {
for fragment := range module.Files {
if !strings.HasSuffix(fragment, ".go") {
continue
}
filename := exporter.Filename(exported, module.Name, fragment)
wants[filename] = []protocol.Diagnostic{}
dirs[filepath.Dir(filename)] = true
}
}
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: Go compiler",
Message: msg,
}
if _, ok := wants[pos.Filename]; ok {
wants[pos.Filename] = append(wants[pos.Filename], want)
} else {
t.Errorf("unexpected filename: %v", pos.Filename)
}
},
})
if err != nil {
t.Fatal(err)
}
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)
}
v := source.NewView()
// merge the config objects
cfg := *exported.Config
cfg.Fset = v.Config.Fset
cfg.Mode = packages.LoadSyntax
v.Config = &cfg
for _, pkg := range pkgs {
for _, filename := range pkg.GoFiles {
diagnostics, err := diagnostics(v, source.ToURI(filename))
if err != nil {
t.Fatal(err)
}
got := 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)", filename, want, got)
}
}
}
}