mirror of
https://github.com/golang/go
synced 2024-11-18 20:44:45 -07:00
4471d52094
With this change (finally, after a lot of detours) if you run the lsp tests with `-race -pipe` then you can reliably reproduce the race in golang/go#30091 Change-Id: Ibd9fda5e07409a15d1bc8d14cb46fde41155aa6e Reviewed-on: https://go-review.googlesource.com/c/tools/+/169999 Run-TryBot: Ian Cottrell <iancottrell@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
182 lines
4.5 KiB
Go
182 lines
4.5 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 (
|
|
"flag"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/tools/go/packages/packagestest"
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
// We hardcode the expected number of test cases to ensure that all tests
|
|
// are being executed. If a test is added, this number must be changed.
|
|
const (
|
|
expectedCompletionsCount = 64
|
|
expectedDiagnosticsCount = 16
|
|
expectedFormatCount = 4
|
|
)
|
|
|
|
var internalPipe = flag.Bool("pipe", false, "connect the command line client to a server through a pipe")
|
|
|
|
func TestCommandLine(t *testing.T) {
|
|
packagestest.TestAll(t, testCommandLine)
|
|
}
|
|
|
|
func testCommandLine(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()
|
|
|
|
// Do a first pass to collect special markers for completion.
|
|
if err := exported.Expect(map[string]interface{}{
|
|
"item": func(name string, r packagestest.Range, _, _ string) {
|
|
exported.Mark(name, r)
|
|
},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedDiagnostics := make(diagnostics)
|
|
completionItems := make(completionItems)
|
|
expectedCompletions := make(completions)
|
|
expectedFormat := make(formats)
|
|
expectedDefinitions := make(definitions)
|
|
expectedTypeDefinitions := make(definitions)
|
|
|
|
// Collect any data that needs to be used by subsequent tests.
|
|
if err := exported.Expect(map[string]interface{}{
|
|
"diag": expectedDiagnostics.collect,
|
|
"item": completionItems.collect,
|
|
"complete": expectedCompletions.collect,
|
|
"format": expectedFormat.collect,
|
|
"godef": expectedDefinitions.godef,
|
|
"definition": expectedDefinitions.definition,
|
|
"typdef": expectedTypeDefinitions.typdef,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
t.Run("Completion", func(t *testing.T) {
|
|
t.Helper()
|
|
expectedCompletions.test(t, exported, completionItems)
|
|
})
|
|
|
|
t.Run("Diagnostics", func(t *testing.T) {
|
|
t.Helper()
|
|
expectedDiagnostics.test(t, exported)
|
|
})
|
|
|
|
t.Run("Format", func(t *testing.T) {
|
|
t.Helper()
|
|
expectedFormat.test(t, exported)
|
|
})
|
|
|
|
t.Run("Definitions", func(t *testing.T) {
|
|
t.Helper()
|
|
expectedDefinitions.testDefinitions(t, exported)
|
|
})
|
|
|
|
t.Run("TypeDefinitions", func(t *testing.T) {
|
|
t.Helper()
|
|
expectedTypeDefinitions.testTypeDefinitions(t, exported)
|
|
})
|
|
}
|
|
|
|
type completionItems map[span.Range]*source.CompletionItem
|
|
type completions map[span.Span][]span.Span
|
|
type formats map[span.URI]span.Span
|
|
|
|
func (l completionItems) collect(spn span.Range, label, detail, kind string) {
|
|
var k source.CompletionItemKind
|
|
switch kind {
|
|
case "struct":
|
|
k = source.StructCompletionItem
|
|
case "func":
|
|
k = source.FunctionCompletionItem
|
|
case "var":
|
|
k = source.VariableCompletionItem
|
|
case "type":
|
|
k = source.TypeCompletionItem
|
|
case "field":
|
|
k = source.FieldCompletionItem
|
|
case "interface":
|
|
k = source.InterfaceCompletionItem
|
|
case "const":
|
|
k = source.ConstantCompletionItem
|
|
case "method":
|
|
k = source.MethodCompletionItem
|
|
case "package":
|
|
k = source.PackageCompletionItem
|
|
}
|
|
l[spn] = &source.CompletionItem{
|
|
Label: label,
|
|
Detail: detail,
|
|
Kind: k,
|
|
}
|
|
}
|
|
|
|
func (l completions) collect(src span.Span, expected []span.Span) {
|
|
l[src] = expected
|
|
}
|
|
|
|
func (l completions) test(t *testing.T, e *packagestest.Exported, items completionItems) {
|
|
if len(l) != expectedCompletionsCount {
|
|
t.Errorf("got %v completions expected %v", len(l), expectedCompletionsCount)
|
|
}
|
|
//TODO: add command line completions tests when it works
|
|
}
|
|
|
|
func (l formats) collect(src span.Span) {
|
|
l[src.URI()] = src
|
|
}
|
|
|
|
func (l formats) test(t *testing.T, e *packagestest.Exported) {
|
|
if len(l) != expectedFormatCount {
|
|
t.Errorf("got %v formats expected %v", len(l), expectedFormatCount)
|
|
}
|
|
//TODO: add command line formatting tests when it works
|
|
}
|
|
|
|
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))
|
|
}
|