.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / internal / regtest / wrappers.go
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
5 package regtest
6
7 import (
8         "io"
9         "path"
10         "testing"
11
12         "golang.org/x/tools/internal/lsp/command"
13         "golang.org/x/tools/internal/lsp/fake"
14         "golang.org/x/tools/internal/lsp/protocol"
15         errors "golang.org/x/xerrors"
16 )
17
18 func (e *Env) ChangeFilesOnDisk(events []fake.FileEvent) {
19         e.T.Helper()
20         if err := e.Sandbox.Workdir.ChangeFilesOnDisk(e.Ctx, events); err != nil {
21                 e.T.Fatal(err)
22         }
23 }
24
25 // RemoveWorkspaceFile deletes a file on disk but does nothing in the
26 // editor. It calls t.Fatal on any error.
27 func (e *Env) RemoveWorkspaceFile(name string) {
28         e.T.Helper()
29         if err := e.Sandbox.Workdir.RemoveFile(e.Ctx, name); err != nil {
30                 e.T.Fatal(err)
31         }
32 }
33
34 // ReadWorkspaceFile reads a file from the workspace, calling t.Fatal on any
35 // error.
36 func (e *Env) ReadWorkspaceFile(name string) string {
37         e.T.Helper()
38         content, err := e.Sandbox.Workdir.ReadFile(name)
39         if err != nil {
40                 e.T.Fatal(err)
41         }
42         return content
43 }
44
45 // WriteWorkspaceFile writes a file to disk but does nothing in the editor.
46 // It calls t.Fatal on any error.
47 func (e *Env) WriteWorkspaceFile(name, content string) {
48         e.T.Helper()
49         if err := e.Sandbox.Workdir.WriteFile(e.Ctx, name, content); err != nil {
50                 e.T.Fatal(err)
51         }
52 }
53
54 // WriteWorkspaceFiles deletes a file on disk but does nothing in the
55 // editor. It calls t.Fatal on any error.
56 func (e *Env) WriteWorkspaceFiles(files map[string]string) {
57         e.T.Helper()
58         if err := e.Sandbox.Workdir.WriteFiles(e.Ctx, files); err != nil {
59                 e.T.Fatal(err)
60         }
61 }
62
63 // OpenFile opens a file in the editor, calling t.Fatal on any error.
64 func (e *Env) OpenFile(name string) {
65         e.T.Helper()
66         if err := e.Editor.OpenFile(e.Ctx, name); err != nil {
67                 e.T.Fatal(err)
68         }
69 }
70
71 // CreateBuffer creates a buffer in the editor, calling t.Fatal on any error.
72 func (e *Env) CreateBuffer(name string, content string) {
73         e.T.Helper()
74         if err := e.Editor.CreateBuffer(e.Ctx, name, content); err != nil {
75                 e.T.Fatal(err)
76         }
77 }
78
79 // CloseBuffer closes an editor buffer without saving, calling t.Fatal on any
80 // error.
81 func (e *Env) CloseBuffer(name string) {
82         e.T.Helper()
83         if err := e.Editor.CloseBuffer(e.Ctx, name); err != nil {
84                 e.T.Fatal(err)
85         }
86 }
87
88 // EditBuffer applies edits to an editor buffer, calling t.Fatal on any error.
89 func (e *Env) EditBuffer(name string, edits ...fake.Edit) {
90         e.T.Helper()
91         if err := e.Editor.EditBuffer(e.Ctx, name, edits); err != nil {
92                 e.T.Fatal(err)
93         }
94 }
95
96 func (e *Env) SetBufferContent(name string, content string) {
97         e.T.Helper()
98         if err := e.Editor.SetBufferContent(e.Ctx, name, content); err != nil {
99                 e.T.Fatal(err)
100         }
101 }
102
103 // RegexpRange returns the range of the first match for re in the buffer
104 // specified by name, calling t.Fatal on any error. It first searches for the
105 // position in open buffers, then in workspace files.
106 func (e *Env) RegexpRange(name, re string) (fake.Pos, fake.Pos) {
107         e.T.Helper()
108         start, end, err := e.Editor.RegexpRange(name, re)
109         if err == fake.ErrUnknownBuffer {
110                 start, end, err = e.Sandbox.Workdir.RegexpRange(name, re)
111         }
112         if err != nil {
113                 e.T.Fatalf("RegexpRange: %v, %v", name, err)
114         }
115         return start, end
116 }
117
118 // RegexpSearch returns the starting position of the first match for re in the
119 // buffer specified by name, calling t.Fatal on any error. It first searches
120 // for the position in open buffers, then in workspace files.
121 func (e *Env) RegexpSearch(name, re string) fake.Pos {
122         e.T.Helper()
123         pos, err := e.Editor.RegexpSearch(name, re)
124         if err == fake.ErrUnknownBuffer {
125                 pos, err = e.Sandbox.Workdir.RegexpSearch(name, re)
126         }
127         if err != nil {
128                 e.T.Fatalf("RegexpSearch: %v, %v", name, err)
129         }
130         return pos
131 }
132
133 // RegexpReplace replaces the first group in the first match of regexpStr with
134 // the replace text, calling t.Fatal on any error.
135 func (e *Env) RegexpReplace(name, regexpStr, replace string) {
136         e.T.Helper()
137         if err := e.Editor.RegexpReplace(e.Ctx, name, regexpStr, replace); err != nil {
138                 e.T.Fatalf("RegexpReplace: %v", err)
139         }
140 }
141
142 // SaveBuffer saves an editor buffer, calling t.Fatal on any error.
143 func (e *Env) SaveBuffer(name string) {
144         e.T.Helper()
145         if err := e.Editor.SaveBuffer(e.Ctx, name); err != nil {
146                 e.T.Fatal(err)
147         }
148 }
149
150 func (e *Env) SaveBufferWithoutActions(name string) {
151         e.T.Helper()
152         if err := e.Editor.SaveBufferWithoutActions(e.Ctx, name); err != nil {
153                 e.T.Fatal(err)
154         }
155 }
156
157 // GoToDefinition goes to definition in the editor, calling t.Fatal on any
158 // error.
159 func (e *Env) GoToDefinition(name string, pos fake.Pos) (string, fake.Pos) {
160         e.T.Helper()
161         n, p, err := e.Editor.GoToDefinition(e.Ctx, name, pos)
162         if err != nil {
163                 e.T.Fatal(err)
164         }
165         return n, p
166 }
167
168 // Symbol returns symbols matching query
169 func (e *Env) Symbol(query string) []fake.SymbolInformation {
170         e.T.Helper()
171         r, err := e.Editor.Symbol(e.Ctx, query)
172         if err != nil {
173                 e.T.Fatal(err)
174         }
175         return r
176 }
177
178 // FormatBuffer formats the editor buffer, calling t.Fatal on any error.
179 func (e *Env) FormatBuffer(name string) {
180         e.T.Helper()
181         if err := e.Editor.FormatBuffer(e.Ctx, name); err != nil {
182                 e.T.Fatal(err)
183         }
184 }
185
186 // OrganizeImports processes the source.organizeImports codeAction, calling
187 // t.Fatal on any error.
188 func (e *Env) OrganizeImports(name string) {
189         e.T.Helper()
190         if err := e.Editor.OrganizeImports(e.Ctx, name); err != nil {
191                 e.T.Fatal(err)
192         }
193 }
194
195 // ApplyQuickFixes processes the quickfix codeAction, calling t.Fatal on any error.
196 func (e *Env) ApplyQuickFixes(path string, diagnostics []protocol.Diagnostic) {
197         e.T.Helper()
198         if err := e.Editor.ApplyQuickFixes(e.Ctx, path, nil, diagnostics); err != nil {
199                 e.T.Fatal(err)
200         }
201 }
202
203 // GetQuickFixes returns the available quick fix code actions.
204 func (e *Env) GetQuickFixes(path string, diagnostics []protocol.Diagnostic) []protocol.CodeAction {
205         e.T.Helper()
206         actions, err := e.Editor.GetQuickFixes(e.Ctx, path, nil, diagnostics)
207         if err != nil {
208                 e.T.Fatal(err)
209         }
210         return actions
211 }
212
213 // Hover in the editor, calling t.Fatal on any error.
214 func (e *Env) Hover(name string, pos fake.Pos) (*protocol.MarkupContent, fake.Pos) {
215         e.T.Helper()
216         c, p, err := e.Editor.Hover(e.Ctx, name, pos)
217         if err != nil {
218                 e.T.Fatal(err)
219         }
220         return c, p
221 }
222
223 func (e *Env) DocumentLink(name string) []protocol.DocumentLink {
224         e.T.Helper()
225         links, err := e.Editor.DocumentLink(e.Ctx, name)
226         if err != nil {
227                 e.T.Fatal(err)
228         }
229         return links
230 }
231
232 func checkIsFatal(t *testing.T, err error) {
233         t.Helper()
234         if err != nil && !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrClosedPipe) {
235                 t.Fatal(err)
236         }
237 }
238
239 // CloseEditor shuts down the editor, calling t.Fatal on any error.
240 func (e *Env) CloseEditor() {
241         e.T.Helper()
242         checkIsFatal(e.T, e.Editor.Close(e.Ctx))
243 }
244
245 // RunGenerate runs go:generate on the given dir, calling t.Fatal on any error.
246 // It waits for the generate command to complete and checks for file changes
247 // before returning.
248 func (e *Env) RunGenerate(dir string) {
249         e.T.Helper()
250         if err := e.Editor.RunGenerate(e.Ctx, dir); err != nil {
251                 e.T.Fatal(err)
252         }
253         e.Await(NoOutstandingWork())
254         // Ideally the fake.Workspace would handle all synthetic file watching, but
255         // we help it out here as we need to wait for the generate command to
256         // complete before checking the filesystem.
257         e.CheckForFileChanges()
258 }
259
260 // RunGoCommand runs the given command in the sandbox's default working
261 // directory.
262 func (e *Env) RunGoCommand(verb string, args ...string) {
263         e.T.Helper()
264         if err := e.Sandbox.RunGoCommand(e.Ctx, "", verb, args); err != nil {
265                 e.T.Fatal(err)
266         }
267 }
268
269 // RunGoCommandInDir is like RunGoCommand, but executes in the given
270 // relative directory of the sandbox.
271 func (e *Env) RunGoCommandInDir(dir, verb string, args ...string) {
272         e.T.Helper()
273         if err := e.Sandbox.RunGoCommand(e.Ctx, dir, verb, args); err != nil {
274                 e.T.Fatal(err)
275         }
276 }
277
278 // DumpGoSum prints the correct go.sum contents for dir in txtar format,
279 // for use in creating regtests.
280 func (e *Env) DumpGoSum(dir string) {
281         e.T.Helper()
282
283         if err := e.Sandbox.RunGoCommand(e.Ctx, dir, "list", []string{"-mod=mod", "..."}); err != nil {
284                 e.T.Fatal(err)
285         }
286         sumFile := path.Join(dir, "/go.sum")
287         e.T.Log("\n\n-- " + sumFile + " --\n" + e.ReadWorkspaceFile(sumFile))
288         e.T.Fatal("see contents above")
289 }
290
291 // CheckForFileChanges triggers a manual poll of the workspace for any file
292 // changes since creation, or since last polling. It is a workaround for the
293 // lack of true file watching support in the fake workspace.
294 func (e *Env) CheckForFileChanges() {
295         e.T.Helper()
296         if err := e.Sandbox.Workdir.CheckForFileChanges(e.Ctx); err != nil {
297                 e.T.Fatal(err)
298         }
299 }
300
301 // CodeLens calls textDocument/codeLens for the given path, calling t.Fatal on
302 // any error.
303 func (e *Env) CodeLens(path string) []protocol.CodeLens {
304         e.T.Helper()
305         lens, err := e.Editor.CodeLens(e.Ctx, path)
306         if err != nil {
307                 e.T.Fatal(err)
308         }
309         return lens
310 }
311
312 // ExecuteCodeLensCommand executes the command for the code lens matching the
313 // given command name.
314 func (e *Env) ExecuteCodeLensCommand(path string, cmd command.Command) {
315         lenses := e.CodeLens(path)
316         var lens protocol.CodeLens
317         var found bool
318         for _, l := range lenses {
319                 if l.Command.Command == cmd.ID() {
320                         lens = l
321                         found = true
322                 }
323         }
324         if !found {
325                 e.T.Fatalf("found no command with the ID %s", cmd.ID())
326         }
327         if _, err := e.Editor.ExecuteCommand(e.Ctx, &protocol.ExecuteCommandParams{
328                 Command:   lens.Command.Command,
329                 Arguments: lens.Command.Arguments,
330         }); err != nil {
331                 e.T.Fatal(err)
332         }
333 }
334
335 // References calls textDocument/references for the given path at the given
336 // position.
337 func (e *Env) References(path string, pos fake.Pos) []protocol.Location {
338         e.T.Helper()
339         locations, err := e.Editor.References(e.Ctx, path, pos)
340         if err != nil {
341                 e.T.Fatal(err)
342         }
343         return locations
344 }
345
346 // Completion executes a completion request on the server.
347 func (e *Env) Completion(path string, pos fake.Pos) *protocol.CompletionList {
348         e.T.Helper()
349         completions, err := e.Editor.Completion(e.Ctx, path, pos)
350         if err != nil {
351                 e.T.Fatal(err)
352         }
353         return completions
354 }
355
356 // AcceptCompletion accepts a completion for the given item at the given
357 // position.
358 func (e *Env) AcceptCompletion(path string, pos fake.Pos, item protocol.CompletionItem) {
359         e.T.Helper()
360         if err := e.Editor.AcceptCompletion(e.Ctx, path, pos, item); err != nil {
361                 e.T.Fatal(err)
362         }
363 }
364
365 // CodeAction calls testDocument/codeAction for the given path, and calls
366 // t.Fatal if there are errors.
367 func (e *Env) CodeAction(path string) []protocol.CodeAction {
368         e.T.Helper()
369         actions, err := e.Editor.CodeAction(e.Ctx, path, nil)
370         if err != nil {
371                 e.T.Fatal(err)
372         }
373         return actions
374 }
375
376 func (e *Env) ChangeConfiguration(t *testing.T, config *fake.EditorConfig) {
377         e.Editor.Config = *config
378         if err := e.Editor.Server.DidChangeConfiguration(e.Ctx, &protocol.DidChangeConfigurationParams{
379                 // gopls currently ignores the Settings field
380         }); err != nil {
381                 t.Fatal(err)
382         }
383 }
384
385 // ChangeEnv modifies the editor environment and reconfigures the LSP client.
386 // TODO: extend this to "ChangeConfiguration", once we refactor the way editor
387 // configuration is defined.
388 func (e *Env) ChangeEnv(overlay map[string]string) {
389         e.T.Helper()
390         // TODO: to be correct, this should probably be synchronized, but right now
391         // configuration is only ever modified synchronously in a regtest, so this
392         // correctness can wait for the previously mentioned refactoring.
393         if e.Editor.Config.Env == nil {
394                 e.Editor.Config.Env = make(map[string]string)
395         }
396         for k, v := range overlay {
397                 e.Editor.Config.Env[k] = v
398         }
399         var params protocol.DidChangeConfigurationParams
400         if err := e.Editor.Server.DidChangeConfiguration(e.Ctx, &params); err != nil {
401                 e.T.Fatal(err)
402         }
403 }