1
0
mirror of https://github.com/golang/go synced 2024-11-18 14:24:44 -07:00
go/internal/lsp/regtest/symbol_test.go
Rob Findley aa94e735be internal/lsp/source: add a new symbolStyle configuration option
Add a symbolStyle configuration option, and use it to parameterize the
following behavior when computing workspace symbols:

 + package (default): include package name in the workspace symbol.
 + full: fully qualify the symbol by import path
 + dynamic: use as the symbol the shortest suffix of the full path that
   contains the match.

To implement this, expose package name in the source.Package interface.
To be consistent with other handling in the cache package, define a new
cache.packageName named string type, to avoid confusion with packageID
or packagePath (if confusing those two identifiers was a problem, surely
it is a potential problem for package name as well).

Change-Id: Ic8ed6ba5473b0523b97e677878e5e6bddfff10a7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/236842
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
2020-06-26 17:13:37 +00:00

212 lines
4.4 KiB
Go

// Copyright 2020 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 regtest
import (
"testing"
"golang.org/x/tools/internal/lsp/fake"
"golang.org/x/tools/internal/lsp/protocol"
)
const symbolSetup = `
-- go.mod --
module mod.com
go 1.12
-- main.go --
package main
import (
"encoding/json"
"fmt"
)
func main() { // function
fmt.Println("Hello")
}
var myvar int // variable
type myType string // basic type
type myDecoder json.Decoder // to use the encoding/json import
func (m *myType) Blahblah() {} // method
type myStruct struct { // struct type
myStructField int // struct field
}
type myInterface interface { // interface
DoSomeCoolStuff() string // interface method
}
-- p/p.go --
package p
const Message = "Hello World." // constant
`
var caseSensitiveSymbolChecks = map[string]*expSymbolInformation{
"main": {
Name: pString("main.main"),
Kind: pKind(protocol.Function),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(7),
Column: pInt(5),
},
},
},
},
"Message": {
Name: pString("p.Message"),
Kind: pKind(protocol.Constant),
Location: &expLocation{
Path: pString("p/p.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(2),
Column: pInt(6),
},
},
},
},
"myvar": {
Name: pString("main.myvar"),
Kind: pKind(protocol.Variable),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(11),
Column: pInt(4),
},
},
},
},
"myType": {
Name: pString("main.myType"),
Kind: pKind(protocol.String),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(13),
Column: pInt(5),
},
},
},
},
"Blahblah": {
Name: pString("main.myType.Blahblah"),
Kind: pKind(protocol.Method),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(17),
Column: pInt(17),
},
},
},
},
"NewEncoder": {
Name: pString("json.NewEncoder"),
Kind: pKind(protocol.Function),
},
"myStruct": {
Name: pString("main.myStruct"),
Kind: pKind(protocol.Struct),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(19),
Column: pInt(5),
},
},
},
},
// TODO: not sure we should be returning struct fields
"myStructField": {
Name: pString("main.myStruct.myStructField"),
Kind: pKind(protocol.Field),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(20),
Column: pInt(1),
},
},
},
},
"myInterface": {
Name: pString("main.myInterface"),
Kind: pKind(protocol.Interface),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(23),
Column: pInt(5),
},
},
},
},
// TODO: not sure we should be returning interface methods
"DoSomeCoolStuff": {
Name: pString("main.myInterface.DoSomeCoolStuff"),
Kind: pKind(protocol.Method),
Location: &expLocation{
Path: pString("main.go"),
Range: &expRange{
Start: &expPos{
Line: pInt(24),
Column: pInt(1),
},
},
},
},
}
var caseInsensitiveSymbolChecks = map[string]*expSymbolInformation{
"Main": caseSensitiveSymbolChecks["main"],
}
var fuzzySymbolChecks = map[string]*expSymbolInformation{
"Mn": caseSensitiveSymbolChecks["main"],
}
// TestSymbolPos tests that, at a basic level, we get the correct position
// information for symbols matches that are returned.
func TestSymbolPos(t *testing.T) {
checkChecks(t, "caseSensitive", caseSensitiveSymbolChecks)
checkChecks(t, "caseInsensitive", caseInsensitiveSymbolChecks)
checkChecks(t, "fuzzy", fuzzySymbolChecks)
}
func checkChecks(t *testing.T, matcher string, checks map[string]*expSymbolInformation) {
t.Helper()
opts := []RunOption{
WithEditorConfig(fake.EditorConfig{SymbolMatcher: &matcher}),
}
runner.Run(t, symbolSetup, func(t *testing.T, env *Env) {
t.Run(matcher, func(t *testing.T) {
for query, exp := range checks {
t.Run(query, func(t *testing.T) {
res := env.Symbol(query)
if !exp.matchAgainst(res) {
t.Fatalf("failed to find a match against query %q for %v,\ngot: %v", query, exp, res)
}
})
}
})
}, opts...)
}