.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / internal / regtest / bench / completion_bench_test.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 bench
6
7 import (
8         "flag"
9         "fmt"
10         "runtime"
11         "strings"
12         "testing"
13
14         . "golang.org/x/tools/gopls/internal/regtest"
15
16         "golang.org/x/tools/internal/lsp/fake"
17 )
18
19 // dummyCompletionFunction to test manually configured completion using CLI.
20 func dummyCompletionFunction() { const s = "placeholder"; fmt.Printf("%s", s) }
21
22 type completionBenchOptions struct {
23         workdir, file, locationRegexp string
24         printResults                  bool
25         // hook to run edits before initial completion, not supported for manually
26         // configured completions.
27         preCompletionEdits func(*Env)
28 }
29
30 var completionOptions = completionBenchOptions{}
31
32 func init() {
33         flag.StringVar(&completionOptions.workdir, "completion_workdir", "", "directory to run completion benchmarks in")
34         flag.StringVar(&completionOptions.file, "completion_file", "", "relative path to the file to complete in")
35         flag.StringVar(&completionOptions.locationRegexp, "completion_regexp", "", "regexp location to complete at")
36         flag.BoolVar(&completionOptions.printResults, "completion_print_results", false, "whether to print completion results")
37 }
38
39 func benchmarkCompletion(options completionBenchOptions, t *testing.T) {
40         if completionOptions.workdir == "" {
41                 t.Skip("-completion_workdir not configured, skipping benchmark")
42         }
43
44         opts := stressTestOptions(options.workdir)
45
46         // Completion gives bad results if IWL is not yet complete, so we must await
47         // it first (and therefore need hooks).
48         opts = append(opts, SkipHooks(false))
49
50         WithOptions(opts...).Run(t, "", func(t *testing.T, env *Env) {
51                 env.OpenFile(options.file)
52
53                 // Run edits required for this completion.
54                 if options.preCompletionEdits != nil {
55                         options.preCompletionEdits(env)
56                 }
57
58                 // Add a comment as a marker at the start of the file, we'll replace
59                 // this in every iteration to trigger type checking and hence emulate
60                 // a more real world scenario.
61                 env.EditBuffer(options.file, fake.Edit{Text: "// 0\n"})
62
63                 // Run a completion to make sure the system is warm.
64                 pos := env.RegexpSearch(options.file, options.locationRegexp)
65                 completions := env.Completion(options.file, pos)
66
67                 if options.printResults {
68                         fmt.Println("Results:")
69                         for i := 0; i < len(completions.Items); i++ {
70                                 fmt.Printf("\t%d. %v\n", i, completions.Items[i])
71                         }
72                 }
73
74                 results := testing.Benchmark(func(b *testing.B) {
75                         for i := 0; i < b.N; i++ {
76                                 b.StopTimer()
77                                 env.RegexpReplace(options.file, `\/\/ \d*`, fmt.Sprintf("// %d", i))
78
79                                 // explicitly garbage collect since we don't want to count this
80                                 // time in completion benchmarks.
81                                 if i%10 == 0 {
82                                         runtime.GC()
83                                 }
84                                 b.StartTimer()
85
86                                 env.Completion(options.file, pos)
87                         }
88                 })
89
90                 printBenchmarkResults(results)
91         })
92 }
93
94 // endPosInBuffer returns the position for last character in the buffer for
95 // the given file.
96 func endPosInBuffer(env *Env, name string) fake.Pos {
97         buffer := env.Editor.BufferText(name)
98         lines := strings.Split(buffer, "\n")
99         numLines := len(lines)
100
101         return fake.Pos{
102                 Line:   numLines - 1,
103                 Column: len([]rune(lines[numLines-1])),
104         }
105 }
106
107 // Benchmark completion at a specified file and location. When no CLI options
108 // are specified, this test is skipped.
109 // To Run (from x/tools/gopls) against the dummy function above:
110 //      go test -v ./internal/regtest -run=TestBenchmarkConfiguredCompletion
111 //      -completion_workdir="$HOME/Developer/tools"
112 //      -completion_file="gopls/internal/regtest/completion_bench_test.go"
113 //      -completion_regexp="dummyCompletionFunction.*fmt\.Printf\(\"%s\", s(\))"
114 func TestBenchmarkConfiguredCompletion(t *testing.T) {
115         benchmarkCompletion(completionOptions, t)
116 }
117
118 // To run (from x/tools/gopls):
119 //      go test -v ./internal/regtest -run TestBenchmark<>Completion
120 //      -completion_workdir="$HOME/Developer/tools"
121 // where <> is one of the tests below. completion_workdir should be path to
122 // x/tools on your system.
123
124 // Benchmark struct completion in tools codebase.
125 func TestBenchmarkStructCompletion(t *testing.T) {
126         file := "internal/lsp/cache/session.go"
127
128         preCompletionEdits := func(env *Env) {
129                 env.OpenFile(file)
130                 originalBuffer := env.Editor.BufferText(file)
131                 env.EditBuffer(file, fake.Edit{
132                         End:  endPosInBuffer(env, file),
133                         Text: originalBuffer + "\nvar testVariable map[string]bool = Session{}.\n",
134                 })
135         }
136
137         benchmarkCompletion(completionBenchOptions{
138                 workdir:            completionOptions.workdir,
139                 file:               file,
140                 locationRegexp:     `var testVariable map\[string\]bool = Session{}(\.)`,
141                 preCompletionEdits: preCompletionEdits,
142                 printResults:       completionOptions.printResults,
143         }, t)
144 }
145
146 // Benchmark import completion in tools codebase.
147 func TestBenchmarkImportCompletion(t *testing.T) {
148         benchmarkCompletion(completionBenchOptions{
149                 workdir:        completionOptions.workdir,
150                 file:           "internal/lsp/source/completion/completion.go",
151                 locationRegexp: `go\/()`,
152                 printResults:   completionOptions.printResults,
153         }, t)
154 }
155
156 // Benchmark slice completion in tools codebase.
157 func TestBenchmarkSliceCompletion(t *testing.T) {
158         file := "internal/lsp/cache/session.go"
159
160         preCompletionEdits := func(env *Env) {
161                 env.OpenFile(file)
162                 originalBuffer := env.Editor.BufferText(file)
163                 env.EditBuffer(file, fake.Edit{
164                         End:  endPosInBuffer(env, file),
165                         Text: originalBuffer + "\nvar testVariable []byte = \n",
166                 })
167         }
168
169         benchmarkCompletion(completionBenchOptions{
170                 workdir:            completionOptions.workdir,
171                 file:               file,
172                 locationRegexp:     `var testVariable \[\]byte (=)`,
173                 preCompletionEdits: preCompletionEdits,
174                 printResults:       completionOptions.printResults,
175         }, t)
176 }
177
178 // Benchmark deep completion in function call in tools codebase.
179 func TestBenchmarkFuncDeepCompletion(t *testing.T) {
180         file := "internal/lsp/source/completion/completion.go"
181         fileContent := `
182 func (c *completer) _() {
183         c.inference.kindMatches(c.)
184 }
185 `
186         preCompletionEdits := func(env *Env) {
187                 env.OpenFile(file)
188                 originalBuffer := env.Editor.BufferText(file)
189                 env.EditBuffer(file, fake.Edit{
190                         End:  endPosInBuffer(env, file),
191                         Text: originalBuffer + fileContent,
192                 })
193         }
194
195         benchmarkCompletion(completionBenchOptions{
196                 workdir:            completionOptions.workdir,
197                 file:               file,
198                 locationRegexp:     `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)`,
199                 preCompletionEdits: preCompletionEdits,
200                 printResults:       completionOptions.printResults,
201         }, t)
202 }