2019-03-25 16:30:55 -06:00
|
|
|
// 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 (
|
2019-04-26 10:45:14 -06:00
|
|
|
"bytes"
|
2019-07-10 19:11:23 -06:00
|
|
|
"context"
|
2019-03-25 16:30:55 -06:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2019-04-29 12:57:27 -06:00
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
2019-04-26 10:45:14 -06:00
|
|
|
"strings"
|
2019-03-25 16:30:55 -06:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"golang.org/x/tools/go/packages/packagestest"
|
2019-04-16 13:47:48 -06:00
|
|
|
"golang.org/x/tools/internal/lsp/tests"
|
2019-08-30 10:02:01 -06:00
|
|
|
"golang.org/x/tools/internal/testenv"
|
2019-03-25 16:30:55 -06:00
|
|
|
)
|
|
|
|
|
2019-08-29 13:24:41 -06:00
|
|
|
func TestMain(m *testing.M) {
|
2019-08-30 10:02:01 -06:00
|
|
|
testenv.ExitIfSmallMachine()
|
2019-08-29 13:24:41 -06:00
|
|
|
os.Exit(m.Run())
|
|
|
|
}
|
|
|
|
|
2019-04-16 13:47:48 -06:00
|
|
|
type runner struct {
|
2019-04-29 12:57:27 -06:00
|
|
|
exporter packagestest.Exporter
|
|
|
|
data *tests.Data
|
2019-07-10 19:11:23 -06:00
|
|
|
ctx context.Context
|
2019-04-16 13:47:48 -06:00
|
|
|
}
|
2019-03-25 16:30:55 -06:00
|
|
|
|
|
|
|
func TestCommandLine(t *testing.T) {
|
|
|
|
packagestest.TestAll(t, testCommandLine)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCommandLine(t *testing.T, exporter packagestest.Exporter) {
|
2019-04-16 13:47:48 -06:00
|
|
|
data := tests.Load(t, exporter, "../testdata")
|
|
|
|
defer data.Exported.Cleanup()
|
2019-03-25 16:30:55 -06:00
|
|
|
|
2019-04-16 13:47:48 -06:00
|
|
|
r := &runner{
|
2019-04-29 12:57:27 -06:00
|
|
|
exporter: exporter,
|
|
|
|
data: data,
|
2019-07-10 19:11:23 -06:00
|
|
|
ctx: tests.Context(t),
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
2019-04-16 13:47:48 -06:00
|
|
|
tests.Run(t, r, data)
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
|
|
|
|
2019-04-28 21:19:54 -06:00
|
|
|
func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests.CompletionSnippets, items tests.CompletionItems) {
|
2019-04-16 13:47:48 -06:00
|
|
|
//TODO: add command line completions tests when it works
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
|
|
|
|
2019-08-28 19:48:29 -06:00
|
|
|
func (r *runner) FoldingRange(t *testing.T, data tests.FoldingRanges) {
|
|
|
|
//TODO: add command line folding range tests when it works
|
|
|
|
}
|
|
|
|
|
2019-04-16 13:47:48 -06:00
|
|
|
func (r *runner) Highlight(t *testing.T, data tests.Highlights) {
|
|
|
|
//TODO: add command line highlight tests when it works
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
2019-06-07 08:04:22 -06:00
|
|
|
|
|
|
|
func (r *runner) Reference(t *testing.T, data tests.References) {
|
|
|
|
//TODO: add command line references tests when it works
|
|
|
|
}
|
|
|
|
|
2019-06-18 08:23:37 -06:00
|
|
|
func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
|
|
|
//TODO: add command line rename tests when it works
|
|
|
|
}
|
|
|
|
|
2019-08-22 11:31:03 -06:00
|
|
|
func (r *runner) PrepareRename(t *testing.T, data tests.PrepareRenames) {
|
|
|
|
//TODO: add command line prepare rename tests when it works
|
|
|
|
}
|
|
|
|
|
2019-04-16 13:47:48 -06:00
|
|
|
func (r *runner) Symbol(t *testing.T, data tests.Symbols) {
|
|
|
|
//TODO: add command line symbol tests when it works
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
|
|
|
|
2019-05-14 19:20:41 -06:00
|
|
|
func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
2019-04-16 13:47:48 -06:00
|
|
|
//TODO: add command line signature tests when it works
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
|
|
|
|
2019-04-24 09:33:45 -06:00
|
|
|
func (r *runner) Link(t *testing.T, data tests.Links) {
|
|
|
|
//TODO: add command line link tests when it works
|
|
|
|
}
|
|
|
|
|
2019-05-31 20:42:59 -06:00
|
|
|
func (r *runner) Import(t *testing.T, data tests.Imports) {
|
|
|
|
//TODO: add command line imports tests when it works
|
|
|
|
}
|
|
|
|
|
2019-09-04 11:16:09 -06:00
|
|
|
func (r *runner) SuggestedFix(t *testing.T, data tests.SuggestedFixes) {
|
|
|
|
//TODO: add suggested fix tests when it works
|
|
|
|
}
|
|
|
|
|
2019-03-25 16:30:55 -06:00
|
|
|
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)
|
|
|
|
}
|
2019-04-07 21:08:47 -06:00
|
|
|
return string(data)
|
2019-03-25 16:30:55 -06:00
|
|
|
}
|
2019-04-26 10:45:14 -06:00
|
|
|
|
|
|
|
// normalizePaths replaces all paths present in s with just the fragment portion
|
|
|
|
// this is used to make golden files not depend on the temporary paths of the files
|
2019-04-29 12:57:27 -06:00
|
|
|
func normalizePaths(data *tests.Data, s string) string {
|
2019-04-26 10:45:14 -06:00
|
|
|
type entry struct {
|
2019-04-29 12:57:27 -06:00
|
|
|
path string
|
|
|
|
index int
|
|
|
|
fragment string
|
2019-04-26 10:45:14 -06:00
|
|
|
}
|
2019-04-29 12:57:27 -06:00
|
|
|
match := make([]entry, 0, len(data.Exported.Modules))
|
2019-04-26 10:45:14 -06:00
|
|
|
// collect the initial state of all the matchers
|
2019-04-29 12:57:27 -06:00
|
|
|
for _, m := range data.Exported.Modules {
|
|
|
|
for fragment := range m.Files {
|
|
|
|
filename := data.Exported.File(m.Name, fragment)
|
|
|
|
index := strings.Index(s, filename)
|
|
|
|
if index >= 0 {
|
|
|
|
match = append(match, entry{filename, index, fragment})
|
|
|
|
}
|
|
|
|
if slash := filepath.ToSlash(filename); slash != filename {
|
|
|
|
index := strings.Index(s, slash)
|
|
|
|
if index >= 0 {
|
|
|
|
match = append(match, entry{slash, index, fragment})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
quoted := strconv.Quote(filename)
|
|
|
|
if escaped := quoted[1 : len(quoted)-1]; escaped != filename {
|
|
|
|
index := strings.Index(s, escaped)
|
|
|
|
if index >= 0 {
|
|
|
|
match = append(match, entry{escaped, index, fragment})
|
|
|
|
}
|
|
|
|
}
|
2019-04-26 10:45:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// result should be the same or shorter than the input
|
|
|
|
buf := bytes.NewBuffer(make([]byte, 0, len(s)))
|
|
|
|
last := 0
|
|
|
|
for {
|
|
|
|
// find the nearest path match to the start of the buffer
|
|
|
|
next := -1
|
|
|
|
nearest := len(s)
|
|
|
|
for i, c := range match {
|
|
|
|
if c.index >= 0 && nearest > c.index {
|
|
|
|
nearest = c.index
|
|
|
|
next = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// if there are no matches, we copy the rest of the string and are done
|
|
|
|
if next < 0 {
|
|
|
|
buf.WriteString(s[last:])
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
// we have a match
|
|
|
|
n := &match[next]
|
|
|
|
// copy up to the start of the match
|
|
|
|
buf.WriteString(s[last:n.index])
|
2019-04-29 12:57:27 -06:00
|
|
|
// skip over the filename
|
2019-04-26 10:45:14 -06:00
|
|
|
last = n.index + len(n.path)
|
2019-04-29 12:57:27 -06:00
|
|
|
// add in the fragment instead
|
|
|
|
buf.WriteString(n.fragment)
|
2019-04-26 10:45:14 -06:00
|
|
|
// see what the next match for this path is
|
|
|
|
n.index = strings.Index(s[last:], n.path)
|
|
|
|
if n.index >= 0 {
|
|
|
|
n.index += last
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|