Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / lsp / cmd / capabilities_test.go
1 package cmd
2
3 import (
4         "context"
5         "io/ioutil"
6         "os"
7         "path/filepath"
8         "testing"
9
10         "golang.org/x/tools/internal/lsp"
11         "golang.org/x/tools/internal/lsp/cache"
12         "golang.org/x/tools/internal/lsp/protocol"
13         errors "golang.org/x/xerrors"
14 )
15
16 // TestCapabilities does some minimal validation of the server's adherence to the LSP.
17 // The checks in the test are added as changes are made and errors noticed.
18 func TestCapabilities(t *testing.T) {
19         tmpDir, err := ioutil.TempDir("", "fake")
20         if err != nil {
21                 t.Fatal(err)
22         }
23         tmpFile := filepath.Join(tmpDir, "fake.go")
24         if err := ioutil.WriteFile(tmpFile, []byte(""), 0775); err != nil {
25                 t.Fatal(err)
26         }
27         if err := ioutil.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte(`module fake`), 0775); err != nil {
28                 t.Fatal(err)
29         }
30         defer os.RemoveAll(tmpDir)
31
32         app := New("gopls-test", tmpDir, os.Environ(), nil)
33         c := newConnection(app)
34         ctx := context.Background()
35         defer c.terminate(ctx)
36
37         params := &protocol.ParamInitialize{}
38         params.RootURI = protocol.URIFromPath(c.Client.app.wd)
39         params.Capabilities.Workspace.Configuration = true
40
41         // Send an initialize request to the server.
42         c.Server = lsp.NewServer(cache.New(ctx, app.options).NewSession(ctx), c.Client)
43         result, err := c.Server.Initialize(ctx, params)
44         if err != nil {
45                 t.Fatal(err)
46         }
47         // Validate initialization result.
48         if err := validateCapabilities(result); err != nil {
49                 t.Error(err)
50         }
51         // Complete initialization of server.
52         if err := c.Server.Initialized(ctx, &protocol.InitializedParams{}); err != nil {
53                 t.Fatal(err)
54         }
55
56         // Open the file on the server side.
57         uri := protocol.URIFromPath(tmpFile)
58         if err := c.Server.DidOpen(ctx, &protocol.DidOpenTextDocumentParams{
59                 TextDocument: protocol.TextDocumentItem{
60                         URI:        uri,
61                         LanguageID: "go",
62                         Version:    1,
63                         Text:       `package main; func main() {};`,
64                 },
65         }); err != nil {
66                 t.Fatal(err)
67         }
68
69         // If we are sending a full text change, the change.Range must be nil.
70         // It is not enough for the Change to be empty, as that is ambiguous.
71         if err := c.Server.DidChange(ctx, &protocol.DidChangeTextDocumentParams{
72                 TextDocument: protocol.VersionedTextDocumentIdentifier{
73                         TextDocumentIdentifier: protocol.TextDocumentIdentifier{
74                                 URI: uri,
75                         },
76                         Version: 2,
77                 },
78                 ContentChanges: []protocol.TextDocumentContentChangeEvent{
79                         {
80                                 Range: nil,
81                                 Text:  `package main; func main() { fmt.Println("") }`,
82                         },
83                 },
84         }); err != nil {
85                 t.Fatal(err)
86         }
87
88         // Send a code action request to validate expected types.
89         actions, err := c.Server.CodeAction(ctx, &protocol.CodeActionParams{
90                 TextDocument: protocol.TextDocumentIdentifier{
91                         URI: uri,
92                 },
93         })
94         if err != nil {
95                 t.Fatal(err)
96         }
97         for _, action := range actions {
98                 // Validate that an empty command is sent along with import organization responses.
99                 if action.Kind == protocol.SourceOrganizeImports && action.Command != nil {
100                         t.Errorf("unexpected command for import organization")
101                 }
102         }
103
104         if err := c.Server.DidSave(ctx, &protocol.DidSaveTextDocumentParams{
105                 TextDocument: protocol.VersionedTextDocumentIdentifier{
106                         Version: 2,
107                         TextDocumentIdentifier: protocol.TextDocumentIdentifier{
108                                 URI: uri,
109                         },
110                 },
111                 // LSP specifies that a file can be saved with optional text, so this field must be nil.
112                 Text: nil,
113         }); err != nil {
114                 t.Fatal(err)
115         }
116
117         // Send a completion request to validate expected types.
118         list, err := c.Server.Completion(ctx, &protocol.CompletionParams{
119                 TextDocumentPositionParams: protocol.TextDocumentPositionParams{
120                         TextDocument: protocol.TextDocumentIdentifier{
121                                 URI: uri,
122                         },
123                         Position: protocol.Position{
124                                 Line:      0,
125                                 Character: 28,
126                         },
127                 },
128         })
129         if err != nil {
130                 t.Fatal(err)
131         }
132         for _, item := range list.Items {
133                 // All other completion items should have nil commands.
134                 // An empty command will be treated as a command with the name '' by VS Code.
135                 // This causes VS Code to report errors to users about invalid commands.
136                 if item.Command != nil {
137                         t.Errorf("unexpected command for completion item")
138                 }
139                 // The item's TextEdit must be a pointer, as VS Code considers TextEdits
140                 // that don't contain the cursor position to be invalid.
141                 var textEdit interface{} = item.TextEdit
142                 if _, ok := textEdit.(*protocol.TextEdit); !ok {
143                         t.Errorf("textEdit is not a *protocol.TextEdit, instead it is %T", textEdit)
144                 }
145         }
146         if err := c.Server.Shutdown(ctx); err != nil {
147                 t.Fatal(err)
148         }
149         if err := c.Server.Exit(ctx); err != nil {
150                 t.Fatal(err)
151         }
152 }
153
154 func validateCapabilities(result *protocol.InitializeResult) error {
155         // If the client sends "false" for RenameProvider.PrepareSupport,
156         // the server must respond with a boolean.
157         if v, ok := result.Capabilities.RenameProvider.(bool); !ok {
158                 return errors.Errorf("RenameProvider must be a boolean if PrepareSupport is false (got %T)", v)
159         }
160         // The same goes for CodeActionKind.ValueSet.
161         if v, ok := result.Capabilities.CodeActionProvider.(bool); !ok {
162                 return errors.Errorf("CodeActionSupport must be a boolean if CodeActionKind.ValueSet has length 0 (got %T)", v)
163         }
164         return nil
165 }