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.
12 "golang.org/x/tools/internal/lsp"
13 "golang.org/x/tools/internal/lsp/fake"
14 "golang.org/x/tools/internal/lsp/protocol"
15 "golang.org/x/tools/internal/testenv"
18 func TestPackageCompletion(t *testing.T) {
19 testenv.NeedsGo1Point(t, 14)
31 -- fruits/testfile.go --
35 this is a multiline comment
42 -- fruits/testfile2.go --
45 -- fruits/testfile3.go --
50 testfile5 = "/*a comment*/ "
51 testfile6 = "/*a comment*/\n"
53 for _, tc := range []struct {
62 name: "package completion at valid position",
63 filename: "fruits/testfile.go",
64 triggerRegexp: "\n()",
65 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
69 name: "package completion in a comment",
70 filename: "fruits/testfile.go",
71 triggerRegexp: "th(i)s",
75 name: "package completion in a multiline comment",
76 filename: "fruits/testfile.go",
77 triggerRegexp: `\/\*\n()`,
81 name: "package completion at invalid position",
82 filename: "fruits/testfile.go",
83 triggerRegexp: "import \"fmt\"\n()",
87 name: "package completion after keyword 'package'",
88 filename: "fruits/testfile2.go",
89 triggerRegexp: "package()",
90 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
91 editRegexp: "package\n",
94 name: "package completion with 'pac' prefix",
95 filename: "fruits/testfile3.go",
96 triggerRegexp: "pac()",
97 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
101 name: "package completion for empty file",
102 filename: "fruits/testfile4.go",
105 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
109 name: "package completion without terminal newline",
110 filename: "fruits/testfile5.go",
111 triggerRegexp: `\*\/ ()`,
113 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
114 editRegexp: `\*\/ ()`,
117 name: "package completion on terminal newline",
118 filename: "fruits/testfile6.go",
119 triggerRegexp: `\*\/\n()`,
121 want: []string{"package apple", "package apple_test", "package fruits", "package fruits_test", "package main"},
122 editRegexp: `\*\/\n()`,
125 t.Run(tc.name, func(t *testing.T) {
126 run(t, files, func(t *testing.T, env *Env) {
127 if tc.content != nil {
128 env.WriteWorkspaceFile(tc.filename, *tc.content)
130 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
133 env.OpenFile(tc.filename)
134 completions := env.Completion(tc.filename, env.RegexpSearch(tc.filename, tc.triggerRegexp))
136 // Check that the completion item suggestions are in the range
138 lineCount := len(strings.Split(env.Editor.BufferText(tc.filename), "\n"))
139 for _, item := range completions.Items {
140 if start := int(item.TextEdit.Range.Start.Line); start >= lineCount {
141 t.Fatalf("unexpected text edit range start line number: got %d, want less than %d", start, lineCount)
143 if end := int(item.TextEdit.Range.End.Line); end >= lineCount {
144 t.Fatalf("unexpected text edit range end line number: got %d, want less than %d", end, lineCount)
149 start, end := env.RegexpRange(tc.filename, tc.editRegexp)
150 expectedRng := protocol.Range{
151 Start: fake.Pos.ToProtocolPosition(start),
152 End: fake.Pos.ToProtocolPosition(end),
154 for _, item := range completions.Items {
155 gotRng := item.TextEdit.Range
156 if expectedRng != gotRng {
157 t.Errorf("unexpected completion range for completion item %s: got %v, want %v",
158 item.Label, gotRng, expectedRng)
163 diff := compareCompletionResults(tc.want, completions.Items)
172 func TestPackageNameCompletion(t *testing.T) {
181 want := []string{"ma", "ma_test", "main", "math", "math_test"}
182 run(t, files, func(t *testing.T, env *Env) {
183 env.OpenFile("math/add.go")
184 completions := env.Completion("math/add.go", fake.Pos{
189 diff := compareCompletionResults(want, completions.Items)
196 func compareCompletionResults(want []string, gotItems []protocol.CompletionItem) string {
197 if len(gotItems) != len(want) {
198 return fmt.Sprintf("got %v completion(s), want %v", len(gotItems), len(want))
202 for _, item := range gotItems {
203 got = append(got, item.Label)
206 for i, v := range got {
208 return fmt.Sprintf("completion results are not the same: got %v, want %v", got, want)