1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package regtest 6 7import ( 8 "path" 9 "strings" 10 "testing" 11 12 "golang.org/x/tools/internal/lsp/tests" 13) 14 15const internalDefinition = ` 16-- go.mod -- 17module mod.com 18 19go 1.12 20-- main.go -- 21package main 22 23import "fmt" 24 25func main() { 26 fmt.Println(message) 27} 28-- const.go -- 29package main 30 31const message = "Hello World." 32` 33 34func TestGoToInternalDefinition(t *testing.T) { 35 runner.Run(t, internalDefinition, func(t *testing.T, env *Env) { 36 env.OpenFile("main.go") 37 name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", "message")) 38 if want := "const.go"; name != want { 39 t.Errorf("GoToDefinition: got file %q, want %q", name, want) 40 } 41 if want := env.RegexpSearch("const.go", "message"); pos != want { 42 t.Errorf("GoToDefinition: got position %v, want %v", pos, want) 43 } 44 }) 45} 46 47const stdlibDefinition = ` 48-- go.mod -- 49module mod.com 50 51go 1.12 52-- main.go -- 53package main 54 55import "fmt" 56 57func main() { 58 fmt.Printf() 59}` 60 61func TestGoToStdlibDefinition_Issue37045(t *testing.T) { 62 runner.Run(t, stdlibDefinition, func(t *testing.T, env *Env) { 63 env.OpenFile("main.go") 64 name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`)) 65 if got, want := path.Base(name), "print.go"; got != want { 66 t.Errorf("GoToDefinition: got file %q, want %q", name, want) 67 } 68 69 // Test that we can jump to definition from outside our workspace. 70 // See golang.org/issues/37045. 71 newName, newPos := env.GoToDefinition(name, pos) 72 if newName != name { 73 t.Errorf("GoToDefinition is not idempotent: got %q, want %q", newName, name) 74 } 75 if newPos != pos { 76 t.Errorf("GoToDefinition is not idempotent: got %v, want %v", newPos, pos) 77 } 78 }) 79} 80 81func TestUnexportedStdlib_Issue40809(t *testing.T) { 82 runner.Run(t, stdlibDefinition, func(t *testing.T, env *Env) { 83 env.OpenFile("main.go") 84 name, _ := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`)) 85 env.OpenFile(name) 86 87 pos := env.RegexpSearch(name, `:=\s*(newPrinter)\(\)`) 88 89 // Check that we can find references on a reference 90 refs := env.References(name, pos) 91 if len(refs) < 5 { 92 t.Errorf("expected 5+ references to newPrinter, found: %#v", refs) 93 } 94 95 name, pos = env.GoToDefinition(name, pos) 96 content, _ := env.Hover(name, pos) 97 if !strings.Contains(content.Value, "newPrinter") { 98 t.Fatal("definition of newPrinter went to the incorrect place") 99 } 100 // And on the definition too. 101 refs = env.References(name, pos) 102 if len(refs) < 5 { 103 t.Errorf("expected 5+ references to newPrinter, found: %#v", refs) 104 } 105 }) 106} 107 108// Test the hover on an error's Error function. 109// This can't be done via the marker tests because Error is a builtin. 110func TestHoverOnError(t *testing.T) { 111 const mod = ` 112-- go.mod -- 113module mod.com 114 115go 1.12 116-- main.go -- 117package main 118 119func main() { 120 var err error 121 err.Error() 122}` 123 run(t, mod, func(t *testing.T, env *Env) { 124 env.OpenFile("main.go") 125 content, _ := env.Hover("main.go", env.RegexpSearch("main.go", "Error")) 126 if content == nil { 127 t.Fatalf("nil hover content for Error") 128 } 129 want := "```go\nfunc (error).Error() string\n```" 130 if content.Value != want { 131 t.Fatalf("hover failed:\n%s", tests.Diff(t, want, content.Value)) 132 } 133 }) 134} 135