1
0
mirror of https://github.com/golang/go synced 2024-10-01 10:38:33 -06:00
go/internal/lsp/cmd/definition_test.go
Ian Cottrell 2f43c6d1a2 internal/span: change to private fields
Change span to hide its fields and have validating accessors
This catches the cases where either the offset or the position is being used
when it was not set.
It also normalizes the forms as the API now controls them, and allows us to
simplify some of the logic.
The converters are now allowed to return an error, which lets us cleanly
propagate bad cases.
The lsp was then converted to the new format, and also had some error checking
of its own added on the top.
All this allowed me to find and fix a few issues, most notably a case where the
wrong column mapper was being used during the conversion of definition results.

Change-Id: Iebdf8901e8269b28aaef60caf76574baa25c46d4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/167858
Run-TryBot: Ian Cottrell <iancottrell@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
2019-03-15 18:05:47 +00:00

163 lines
4.2 KiB
Go

// Copyright 2019 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 cmd_test
import (
"context"
"flag"
"fmt"
"go/token"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
"golang.org/x/tools/go/packages/packagestest"
"golang.org/x/tools/internal/lsp/cmd"
"golang.org/x/tools/internal/span"
"golang.org/x/tools/internal/tool"
)
var verifyGuru = flag.Bool("verify-guru", false, "Check that the guru compatability matches")
func TestDefinitionHelpExample(t *testing.T) {
dir, err := os.Getwd()
if err != nil {
t.Errorf("could not get wd: %v", err)
return
}
thisFile := filepath.Join(dir, "definition.go")
args := []string{"query", "definition", fmt.Sprintf("%v:#%v", thisFile, cmd.ExampleOffset)}
expect := regexp.MustCompile(`^[\w/\\:_]+flag[/\\]flag.go:\d+:\d+-\d+: defined here as type flag.FlagSet struct{.*}$`)
got := captureStdOut(t, func() {
tool.Main(context.Background(), &cmd.Application{}, args)
})
if !expect.MatchString(got) {
t.Errorf("test with %v\nexpected:\n%s\ngot:\n%s", args, expect, got)
}
}
func TestDefinition(t *testing.T) {
exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
Name: "golang.org/fake",
Files: packagestest.MustCopyFileTree("testdata"),
}})
defer exported.Cleanup()
count := 0
if err := exported.Expect(map[string]interface{}{
"definition": func(fset *token.FileSet, src token.Pos, flags string, def packagestest.Range, match string) {
count++
args := []string{"query"}
if flags != "" {
args = append(args, strings.Split(flags, " ")...)
}
args = append(args, "definition")
f := fset.File(src)
spn := span.New(span.FileURI(f.Name()), span.NewPoint(0, 0, f.Offset(src)), span.Point{})
args = append(args, fmt.Sprint(spn))
app := &cmd.Application{}
app.Config = *exported.Config
got := captureStdOut(t, func() {
tool.Main(context.Background(), app, args)
})
start := fset.Position(def.Start)
end := fset.Position(def.End)
expect := os.Expand(match, func(name string) string {
switch name {
case "file":
return start.Filename
case "efile":
qfile := strconv.Quote(start.Filename)
return qfile[1 : len(qfile)-1]
case "euri":
uri := span.FileURI(start.Filename)
quri := strconv.Quote(string(uri))
return quri[1 : len(quri)-1]
case "line":
return fmt.Sprint(start.Line)
case "col":
return fmt.Sprint(start.Column)
case "offset":
return fmt.Sprint(start.Offset)
case "eline":
return fmt.Sprint(end.Line)
case "ecol":
return fmt.Sprint(end.Column)
case "eoffset":
return fmt.Sprint(end.Offset)
default:
return name
}
})
if *verifyGuru {
var guruArgs []string
runGuru := false
for _, arg := range args {
switch {
case arg == "query":
// just ignore this one
case arg == "-json":
guruArgs = append(guruArgs, arg)
case arg == "-emulate=guru":
// if we don't see this one we should not run guru
runGuru = true
case strings.HasPrefix(arg, "-"):
// unknown flag, ignore it
break
default:
guruArgs = append(guruArgs, arg)
}
}
if runGuru {
cmd := exec.Command("guru", guruArgs...)
cmd.Env = exported.Config.Env
out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("Could not run guru %v: %v\n%s", guruArgs, err, out)
} else {
guru := strings.TrimSpace(string(out))
if !strings.HasPrefix(expect, guru) {
t.Errorf("definition %v\nexpected:\n%s\nguru gave:\n%s", args, expect, guru)
}
}
}
}
if expect != got {
t.Errorf("definition %v\nexpected:\n%s\ngot:\n%s", args, expect, got)
}
},
}); err != nil {
t.Fatal(err)
}
if count == 0 {
t.Fatalf("No tests were run")
}
}
func captureStdOut(t testing.TB, f func()) string {
r, out, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
old := os.Stdout
defer func() {
os.Stdout = old
out.Close()
r.Close()
}()
os.Stdout = out
f()
out.Close()
data, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal(err)
}
return strings.TrimSpace(string(data))
}