Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / lsp / cache / workspace_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 cache
6
7 import (
8         "context"
9         "os"
10         "testing"
11
12         "golang.org/x/tools/internal/lsp/fake"
13         "golang.org/x/tools/internal/lsp/source"
14         "golang.org/x/tools/internal/span"
15 )
16
17 // osFileSource is a fileSource that just reads from the operating system.
18 type osFileSource struct{}
19
20 func (s osFileSource) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
21         fi, statErr := os.Stat(uri.Filename())
22         if statErr != nil {
23                 return &fileHandle{
24                         err: statErr,
25                         uri: uri,
26                 }, nil
27         }
28         fh, err := readFile(ctx, uri, fi.ModTime())
29         if err != nil {
30                 return nil, err
31         }
32         return fh, nil
33 }
34
35 func TestWorkspaceModule(t *testing.T) {
36         tests := []struct {
37                 desc           string
38                 initial        string // txtar-encoded
39                 legacyMode     bool
40                 initialSource  workspaceSource
41                 initialModules []string
42                 initialDirs    []string
43                 updates        map[string]string
44                 finalSource    workspaceSource
45                 finalModules   []string
46                 finalDirs      []string
47         }{
48                 {
49                         desc: "legacy mode",
50                         initial: `
51 -- go.mod --
52 module mod.com
53 -- a/go.mod --
54 module moda.com`,
55                         legacyMode:     true,
56                         initialModules: []string{"./go.mod"},
57                         initialSource:  legacyWorkspace,
58                         initialDirs:    []string{"."},
59                 },
60                 {
61                         desc: "nested module",
62                         initial: `
63 -- go.mod --
64 module mod.com
65 -- a/go.mod --
66 module moda.com`,
67                         initialModules: []string{"./go.mod", "a/go.mod"},
68                         initialSource:  fileSystemWorkspace,
69                         initialDirs:    []string{".", "a"},
70                 },
71                 {
72                         desc: "removing module",
73                         initial: `
74 -- a/go.mod --
75 module moda.com
76 -- b/go.mod --
77 module modb.com`,
78                         initialModules: []string{"a/go.mod", "b/go.mod"},
79                         initialSource:  fileSystemWorkspace,
80                         initialDirs:    []string{".", "a", "b"},
81                         updates: map[string]string{
82                                 "gopls.mod": `module gopls-workspace
83
84 require moda.com v0.0.0-goplsworkspace
85 replace moda.com => $SANDBOX_WORKDIR/a`,
86                         },
87                         finalModules: []string{"a/go.mod"},
88                         finalSource:  goplsModWorkspace,
89                         finalDirs:    []string{".", "a"},
90                 },
91                 {
92                         desc: "adding module",
93                         initial: `
94 -- gopls.mod --
95 require moda.com v0.0.0-goplsworkspace
96 replace moda.com => $SANDBOX_WORKDIR/a
97 -- a/go.mod --
98 module moda.com
99 -- b/go.mod --
100 module modb.com`,
101                         initialModules: []string{"a/go.mod"},
102                         initialSource:  goplsModWorkspace,
103                         initialDirs:    []string{".", "a"},
104                         updates: map[string]string{
105                                 "gopls.mod": `module gopls-workspace
106
107 require moda.com v0.0.0-goplsworkspace
108 require modb.com v0.0.0-goplsworkspace
109
110 replace moda.com => $SANDBOX_WORKDIR/a
111 replace modb.com => $SANDBOX_WORKDIR/b`,
112                         },
113                         finalModules: []string{"a/go.mod", "b/go.mod"},
114                         finalSource:  goplsModWorkspace,
115                         finalDirs:    []string{".", "a", "b"},
116                 },
117                 {
118                         desc: "deleting gopls.mod",
119                         initial: `
120 -- gopls.mod --
121 module gopls-workspace
122
123 require moda.com v0.0.0-goplsworkspace
124 replace moda.com => $SANDBOX_WORKDIR/a
125 -- a/go.mod --
126 module moda.com
127 -- b/go.mod --
128 module modb.com`,
129                         initialModules: []string{"a/go.mod"},
130                         initialSource:  goplsModWorkspace,
131                         initialDirs:    []string{".", "a"},
132                         updates: map[string]string{
133                                 "gopls.mod": "",
134                         },
135                         finalModules: []string{"a/go.mod", "b/go.mod"},
136                         finalSource:  fileSystemWorkspace,
137                         finalDirs:    []string{".", "a", "b"},
138                 },
139                 {
140                         desc: "broken module parsing",
141                         initial: `
142 -- a/go.mod --
143 module moda.com
144
145 require gopls.test v0.0.0-goplsworkspace
146 replace gopls.test => ../../gopls.test // (this path shouldn't matter)
147 -- b/go.mod --
148 module modb.com`,
149                         initialModules: []string{"a/go.mod", "b/go.mod"},
150                         initialSource:  fileSystemWorkspace,
151                         initialDirs:    []string{".", "a", "b", "../gopls.test"},
152                         updates: map[string]string{
153                                 "a/go.mod": `modul moda.com
154
155 require gopls.test v0.0.0-goplsworkspace
156 replace gopls.test => ../../gopls.test2`,
157                         },
158                         finalModules: []string{"a/go.mod", "b/go.mod"},
159                         finalSource:  fileSystemWorkspace,
160                         // finalDirs should be unchanged: we should preserve dirs in the presence
161                         // of a broken modfile.
162                         finalDirs: []string{".", "a", "b", "../gopls.test"},
163                 },
164         }
165
166         for _, test := range tests {
167                 t.Run(test.desc, func(t *testing.T) {
168                         ctx := context.Background()
169                         dir, err := fake.Tempdir(test.initial)
170                         if err != nil {
171                                 t.Fatal(err)
172                         }
173                         defer os.RemoveAll(dir)
174                         root := span.URIFromPath(dir)
175
176                         fs := osFileSource{}
177                         wm, err := newWorkspace(ctx, root, fs, !test.legacyMode)
178                         if err != nil {
179                                 t.Fatal(err)
180                         }
181                         rel := fake.RelativeTo(dir)
182                         checkWorkspaceModule(t, rel, wm, test.initialSource, test.initialModules)
183                         gotDirs := wm.dirs(ctx, fs)
184                         checkWorkspaceDirs(t, rel, gotDirs, test.initialDirs)
185                         if test.updates != nil {
186                                 changes := make(map[span.URI]*fileChange)
187                                 for k, v := range test.updates {
188                                         if v == "" {
189                                                 // for convenience, use this to signal a deletion. TODO: more doc
190                                                 err := os.Remove(rel.AbsPath(k))
191                                                 if err != nil {
192                                                         t.Fatal(err)
193                                                 }
194                                         } else {
195                                                 fake.WriteFileData(k, []byte(v), rel)
196                                         }
197                                         uri := span.URIFromPath(rel.AbsPath(k))
198                                         fh, err := fs.GetFile(ctx, uri)
199                                         if err != nil {
200                                                 t.Fatal(err)
201                                         }
202                                         content, err := fh.Read()
203                                         changes[uri] = &fileChange{
204                                                 content:    content,
205                                                 exists:     err == nil,
206                                                 fileHandle: &closedFile{fh},
207                                         }
208                                 }
209                                 wm, _ := wm.invalidate(ctx, changes)
210                                 checkWorkspaceModule(t, rel, wm, test.finalSource, test.finalModules)
211                                 gotDirs := wm.dirs(ctx, fs)
212                                 checkWorkspaceDirs(t, rel, gotDirs, test.finalDirs)
213                         }
214                 })
215         }
216 }
217
218 func checkWorkspaceModule(t *testing.T, rel fake.RelativeTo, got *workspace, wantSource workspaceSource, want []string) {
219         t.Helper()
220         if got.moduleSource != wantSource {
221                 t.Errorf("module source = %v, want %v", got.moduleSource, wantSource)
222         }
223         modules := make(map[span.URI]struct{})
224         for k := range got.activeModFiles() {
225                 modules[k] = struct{}{}
226         }
227         for _, modPath := range want {
228                 path := rel.AbsPath(modPath)
229                 uri := span.URIFromPath(path)
230                 if _, ok := modules[uri]; !ok {
231                         t.Errorf("missing module %q", uri)
232                 }
233                 delete(modules, uri)
234         }
235         for remaining := range modules {
236                 t.Errorf("unexpected module %q", remaining)
237         }
238 }
239
240 func checkWorkspaceDirs(t *testing.T, rel fake.RelativeTo, got []span.URI, want []string) {
241         t.Helper()
242         gotM := make(map[span.URI]bool)
243         for _, dir := range got {
244                 gotM[dir] = true
245         }
246         for _, dir := range want {
247                 path := rel.AbsPath(dir)
248                 uri := span.URIFromPath(path)
249                 if !gotM[uri] {
250                         t.Errorf("missing dir %q", uri)
251                 }
252                 delete(gotM, uri)
253         }
254         for remaining := range gotM {
255                 t.Errorf("unexpected dir %q", remaining)
256         }
257 }