golang.org/x/tools/gopls@v0.15.3/internal/test/integration/workspace/standalone_test.go (about) 1 // Copyright 2022 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 5 package workspace 6 7 import ( 8 "sort" 9 "testing" 10 11 "github.com/google/go-cmp/cmp" 12 "golang.org/x/tools/gopls/internal/protocol" 13 . "golang.org/x/tools/gopls/internal/test/integration" 14 ) 15 16 func TestStandaloneFiles(t *testing.T) { 17 const files = ` 18 -- go.mod -- 19 module mod.test 20 21 go 1.16 22 -- lib/lib.go -- 23 package lib 24 25 const K = 0 26 27 type I interface { 28 M() 29 } 30 -- lib/ignore.go -- 31 //go:build ignore 32 // +build ignore 33 34 package main 35 36 import ( 37 "mod.test/lib" 38 ) 39 40 const K = 1 41 42 type Mer struct{} 43 func (Mer) M() 44 45 func main() { 46 println(lib.K + K) 47 } 48 ` 49 WithOptions( 50 // On Go 1.17 and earlier, this test fails with 51 // experimentalWorkspaceModule. Not investigated, as 52 // experimentalWorkspaceModule will be removed. 53 Modes(Default), 54 ).Run(t, files, func(t *testing.T, env *Env) { 55 // Initially, gopls should not know about the standalone file as it hasn't 56 // been opened. Therefore, we should only find one symbol 'K'. 57 // 58 // (The choice of "K" is a little sleazy: it was originally "C" until 59 // we started adding "unsafe" to the workspace unconditionally, which 60 // caused a spurious match of "unsafe.Slice". But in practice every 61 // workspace depends on unsafe.) 62 syms := env.Symbol("K") 63 if got, want := len(syms), 1; got != want { 64 t.Errorf("got %d symbols, want %d (%+v)", got, want, syms) 65 } 66 67 // Similarly, we should only find one reference to "K", and no 68 // implementations of I. 69 checkLocations := func(method string, gotLocations []protocol.Location, wantFiles ...string) { 70 var gotFiles []string 71 for _, l := range gotLocations { 72 gotFiles = append(gotFiles, env.Sandbox.Workdir.URIToPath(l.URI)) 73 } 74 sort.Strings(gotFiles) 75 sort.Strings(wantFiles) 76 if diff := cmp.Diff(wantFiles, gotFiles); diff != "" { 77 t.Errorf("%s(...): unexpected locations (-want +got):\n%s", method, diff) 78 } 79 } 80 81 env.OpenFile("lib/lib.go") 82 env.AfterChange(NoDiagnostics()) 83 84 // Replacing K with D should not cause any workspace diagnostics, since we 85 // haven't yet opened the standalone file. 86 env.RegexpReplace("lib/lib.go", "K", "D") 87 env.AfterChange(NoDiagnostics()) 88 env.RegexpReplace("lib/lib.go", "D", "K") 89 env.AfterChange(NoDiagnostics()) 90 91 refs := env.References(env.RegexpSearch("lib/lib.go", "K")) 92 checkLocations("References", refs, "lib/lib.go") 93 94 impls := env.Implementations(env.RegexpSearch("lib/lib.go", "I")) 95 checkLocations("Implementations", impls) // no implementations 96 97 // Opening the standalone file should not result in any diagnostics. 98 env.OpenFile("lib/ignore.go") 99 env.AfterChange(NoDiagnostics()) 100 101 // Having opened the standalone file, we should find its symbols in the 102 // workspace. 103 syms = env.Symbol("K") 104 if got, want := len(syms), 2; got != want { 105 t.Fatalf("got %d symbols, want %d", got, want) 106 } 107 108 foundMainK := false 109 var symNames []string 110 for _, sym := range syms { 111 symNames = append(symNames, sym.Name) 112 if sym.Name == "main.K" { 113 foundMainK = true 114 } 115 } 116 if !foundMainK { 117 t.Errorf("WorkspaceSymbol(\"K\") = %v, want containing main.K", symNames) 118 } 119 120 // We should resolve workspace definitions in the standalone file. 121 fileLoc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "lib.(K)")) 122 file := env.Sandbox.Workdir.URIToPath(fileLoc.URI) 123 if got, want := file, "lib/lib.go"; got != want { 124 t.Errorf("GoToDefinition(lib.K) = %v, want %v", got, want) 125 } 126 127 // ...as well as intra-file definitions 128 loc := env.GoToDefinition(env.RegexpSearch("lib/ignore.go", "\\+ (K)")) 129 wantLoc := env.RegexpSearch("lib/ignore.go", "const (K)") 130 if loc != wantLoc { 131 t.Errorf("GoToDefinition(K) = %v, want %v", loc, wantLoc) 132 } 133 134 // Renaming "lib.K" to "lib.D" should cause a diagnostic in the standalone 135 // file. 136 env.RegexpReplace("lib/lib.go", "K", "D") 137 env.AfterChange(Diagnostics(env.AtRegexp("lib/ignore.go", "lib.(K)"))) 138 139 // Undoing the replacement should fix diagnostics 140 env.RegexpReplace("lib/lib.go", "D", "K") 141 env.AfterChange(NoDiagnostics()) 142 143 // Now that our workspace has no errors, we should be able to find 144 // references and rename. 145 refs = env.References(env.RegexpSearch("lib/lib.go", "K")) 146 checkLocations("References", refs, "lib/lib.go", "lib/ignore.go") 147 148 impls = env.Implementations(env.RegexpSearch("lib/lib.go", "I")) 149 checkLocations("Implementations", impls, "lib/ignore.go") 150 151 // Renaming should rename in the standalone package. 152 env.Rename(env.RegexpSearch("lib/lib.go", "K"), "D") 153 env.RegexpSearch("lib/ignore.go", "lib.D") 154 }) 155 } 156 157 func TestStandaloneFiles_Configuration(t *testing.T) { 158 const files = ` 159 -- go.mod -- 160 module mod.test 161 162 go 1.18 163 -- lib.go -- 164 package lib // without this package, files are loaded as command-line-arguments 165 -- ignore.go -- 166 //go:build ignore 167 // +build ignore 168 169 package main 170 171 // An arbitrary comment. 172 173 func main() {} 174 -- standalone.go -- 175 //go:build standalone 176 // +build standalone 177 178 package main 179 180 func main() {} 181 ` 182 183 WithOptions( 184 Settings{ 185 "standaloneTags": []string{"standalone", "script"}, 186 }, 187 ).Run(t, files, func(t *testing.T, env *Env) { 188 env.OpenFile("ignore.go") 189 env.OpenFile("standalone.go") 190 191 env.AfterChange( 192 Diagnostics(env.AtRegexp("ignore.go", "package (main)")), 193 NoDiagnostics(ForFile("standalone.go")), 194 ) 195 196 cfg := env.Editor.Config() 197 cfg.Settings = map[string]interface{}{ 198 "standaloneTags": []string{"ignore"}, 199 } 200 env.ChangeConfiguration(cfg) 201 env.AfterChange( 202 NoDiagnostics(ForFile("ignore.go")), 203 Diagnostics(env.AtRegexp("standalone.go", "package (main)")), 204 ) 205 }) 206 }