.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / lsp / cache / view_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 package cache
5
6 import (
7         "context"
8         "io/ioutil"
9         "os"
10         "path/filepath"
11         "strings"
12         "testing"
13
14         "golang.org/x/mod/modfile"
15         "golang.org/x/tools/internal/lsp/fake"
16         "golang.org/x/tools/internal/lsp/protocol"
17         "golang.org/x/tools/internal/lsp/source"
18         "golang.org/x/tools/internal/span"
19 )
20
21 func TestCaseInsensitiveFilesystem(t *testing.T) {
22         base, err := ioutil.TempDir("", t.Name())
23         if err != nil {
24                 t.Fatal(err)
25         }
26
27         inner := filepath.Join(base, "a/B/c/DEFgh")
28         if err := os.MkdirAll(inner, 0777); err != nil {
29                 t.Fatal(err)
30         }
31         file := filepath.Join(inner, "f.go")
32         if err := ioutil.WriteFile(file, []byte("hi"), 0777); err != nil {
33                 t.Fatal(err)
34         }
35         if _, err := os.Stat(filepath.Join(inner, "F.go")); err != nil {
36                 t.Skip("filesystem is case-sensitive")
37         }
38
39         tests := []struct {
40                 path string
41                 err  bool
42         }{
43                 {file, false},
44                 {filepath.Join(inner, "F.go"), true},
45                 {filepath.Join(base, "a/b/c/defgh/f.go"), true},
46         }
47         for _, tt := range tests {
48                 err := checkPathCase(tt.path)
49                 if err != nil != tt.err {
50                         t.Errorf("checkPathCase(%q) = %v, wanted error: %v", tt.path, err, tt.err)
51                 }
52         }
53 }
54
55 func TestFindWorkspaceRoot(t *testing.T) {
56         workspace := `
57 -- a/go.mod --
58 module a
59 -- a/x/x.go
60 package x
61 -- b/go.mod --
62 module b
63 -- b/c/go.mod --
64 module bc
65 -- d/gopls.mod --
66 module d-goplsworkspace
67 -- d/e/go.mod --
68 module de
69 -- f/g/go.mod --
70 module fg
71 `
72         dir, err := fake.Tempdir(workspace)
73         if err != nil {
74                 t.Fatal(err)
75         }
76         defer os.RemoveAll(dir)
77
78         tests := []struct {
79                 folder, want string
80                 experimental bool
81         }{
82                 {"", "", false}, // no module at root, and more than one nested module
83                 {"a", "a", false},
84                 {"a/x", "a", false},
85                 {"b/c", "b/c", false},
86                 {"d", "d/e", false},
87                 {"d", "d", true},
88                 {"d/e", "d/e", false},
89                 {"d/e", "d", true},
90                 {"f", "f/g", false},
91                 {"f", "f", true},
92         }
93
94         for _, test := range tests {
95                 ctx := context.Background()
96                 rel := fake.RelativeTo(dir)
97                 folderURI := span.URIFromPath(rel.AbsPath(test.folder))
98                 excludeNothing := func(string) bool { return false }
99                 got, err := findWorkspaceRoot(ctx, folderURI, &osFileSource{}, excludeNothing, test.experimental)
100                 if err != nil {
101                         t.Fatal(err)
102                 }
103                 if gotf, wantf := filepath.Clean(got.Filename()), rel.AbsPath(test.want); gotf != wantf {
104                         t.Errorf("findWorkspaceRoot(%q, %t) = %q, want %q", test.folder, test.experimental, gotf, wantf)
105                 }
106         }
107 }
108
109 // This tests the logic used to extract positions from parse and other Go
110 // command errors.
111 func TestExtractPositionFromError(t *testing.T) {
112         workspace := `
113 -- a/go.mod --
114 modul a.com
115 -- b/go.mod --
116 module b.com
117
118 go 1.12.hello
119 -- c/go.mod --
120 module c.com
121
122 require a.com master
123 `
124         dir, err := fake.Tempdir(workspace)
125         if err != nil {
126                 t.Fatal(err)
127         }
128         defer os.RemoveAll(dir)
129
130         tests := []struct {
131                 filename string
132                 wantRng  protocol.Range
133         }{
134                 {
135                         filename: "a/go.mod",
136                         wantRng:  protocol.Range{},
137                 },
138                 {
139                         filename: "b/go.mod",
140                         wantRng: protocol.Range{
141                                 Start: protocol.Position{Line: 2},
142                                 End:   protocol.Position{Line: 2},
143                         },
144                 },
145                 {
146                         filename: "c/go.mod",
147                         wantRng: protocol.Range{
148                                 Start: protocol.Position{Line: 2},
149                                 End:   protocol.Position{Line: 2},
150                         },
151                 },
152         }
153         for _, test := range tests {
154                 ctx := context.Background()
155                 rel := fake.RelativeTo(dir)
156                 uri := span.URIFromPath(rel.AbsPath(test.filename))
157                 if source.DetectLanguage("", uri.Filename()) != source.Mod {
158                         t.Fatalf("expected only go.mod files")
159                 }
160                 // Try directly parsing the given, invalid go.mod file. Then, extract a
161                 // position from the error message.
162                 src := &osFileSource{}
163                 modFH, err := src.GetFile(ctx, uri)
164                 if err != nil {
165                         t.Fatal(err)
166                 }
167                 content, err := modFH.Read()
168                 if err != nil {
169                         t.Fatal(err)
170                 }
171                 _, parseErr := modfile.Parse(uri.Filename(), content, nil)
172                 if parseErr == nil {
173                         t.Fatalf("%s: expected an unparseable go.mod file", uri.Filename())
174                 }
175                 srcErr := extractErrorWithPosition(ctx, parseErr.Error(), src)
176                 if srcErr == nil {
177                         t.Fatalf("unable to extract positions from %v", parseErr.Error())
178                 }
179                 if srcErr.URI != uri {
180                         t.Errorf("unexpected URI: got %s, wanted %s", srcErr.URI, uri)
181                 }
182                 if protocol.CompareRange(test.wantRng, srcErr.Range) != 0 {
183                         t.Errorf("unexpected range: got %s, wanted %s", srcErr.Range, test.wantRng)
184                 }
185                 if !strings.HasSuffix(parseErr.Error(), srcErr.Message) {
186                         t.Errorf("unexpected message: got %s, wanted %s", srcErr.Message, parseErr)
187                 }
188         }
189 }
190
191 func TestInVendor(t *testing.T) {
192         for _, tt := range []struct {
193                 path     string
194                 inVendor bool
195         }{
196                 {
197                         path:     "foo/vendor/x.go",
198                         inVendor: false,
199                 },
200                 {
201                         path:     "foo/vendor/x/x.go",
202                         inVendor: true,
203                 },
204                 {
205                         path:     "foo/x.go",
206                         inVendor: false,
207                 },
208         } {
209                 if got := inVendor(span.URIFromPath(tt.path)); got != tt.inVendor {
210                         t.Errorf("expected %s inVendor %v, got %v", tt.path, tt.inVendor, got)
211                 }
212         }
213 }
214
215 func TestFilters(t *testing.T) {
216         tests := []struct {
217                 filters  []string
218                 included []string
219                 excluded []string
220         }{
221                 {
222                         included: []string{"x"},
223                 },
224                 {
225                         filters:  []string{"-"},
226                         excluded: []string{"x", "x/a"},
227                 },
228                 {
229                         filters:  []string{"-x", "+y"},
230                         included: []string{"y", "y/a", "z"},
231                         excluded: []string{"x", "x/a"},
232                 },
233                 {
234                         filters:  []string{"-x", "+x/y", "-x/y/z"},
235                         included: []string{"x/y", "x/y/a", "a"},
236                         excluded: []string{"x", "x/a", "x/y/z/a"},
237                 },
238                 {
239                         filters:  []string{"+foobar", "-foo"},
240                         included: []string{"foobar", "foobar/a"},
241                         excluded: []string{"foo", "foo/a"},
242                 },
243         }
244
245         for _, tt := range tests {
246                 opts := &source.Options{}
247                 opts.DirectoryFilters = tt.filters
248                 for _, inc := range tt.included {
249                         if pathExcludedByFilter(inc, opts) {
250                                 t.Errorf("filters %q excluded %v, wanted included", tt.filters, inc)
251                         }
252                 }
253                 for _, exc := range tt.excluded {
254                         if !pathExcludedByFilter(exc, opts) {
255                                 t.Errorf("filters %q included %v, wanted excluded", tt.filters, exc)
256                         }
257                 }
258         }
259 }