1
15
16 package repo
17
18 import (
19 "errors"
20 "os"
21 "path/filepath"
22 "testing"
23
24 "golang.org/x/tools/go/vcs"
25 )
26
27 func TestRootSpecialCases(t *testing.T) {
28 for _, tc := range []struct {
29 in, wantRoot, wantName string
30 repos []Repo
31 wantError bool
32 }{
33 {in: "golang.org/x/net/context", wantRoot: "golang.org/x/net", wantName: "org_golang_x_net"},
34 {in: "golang.org/x/tools/go/vcs", wantRoot: "golang.org/x/tools", wantName: "org_golang_x_tools"},
35 {in: "golang.org/x/goimports", wantRoot: "golang.org/x/goimports", wantName: "org_golang_x_goimports"},
36 {in: "cloud.google.com/fashion/industry", wantRoot: "cloud.google.com/fashion", wantName: "com_google_cloud_fashion"},
37 {in: "github.com/foo", wantError: true},
38 {in: "github.com/foo/bar", wantRoot: "github.com/foo/bar", wantName: "com_github_foo_bar"},
39 {in: "github.com/foo/bar/baz", wantRoot: "github.com/foo/bar", wantName: "com_github_foo_bar"},
40 {in: "gopkg.in/yaml.v2", wantRoot: "gopkg.in/yaml.v2", wantName: "in_gopkg_yaml_v2"},
41 {in: "gopkg.in/src-d/go-git.v4", wantRoot: "gopkg.in/src-d/go-git.v4", wantName: "in_gopkg_src_d_go_git_v4"},
42 {in: "unsupported.org/x/net/context", wantError: true},
43 {
44 in: "private.com/my/repo/package/path",
45 repos: []Repo{
46 {
47 Name: "com_other_host_repo",
48 GoPrefix: "other-host.com/repo",
49 }, {
50 Name: "com_private_my_repo",
51 GoPrefix: "private.com/my/repo",
52 },
53 },
54 wantRoot: "private.com/my/repo",
55 wantName: "com_private_my_repo",
56 },
57 {
58 in: "unsupported.org/x/net/context",
59 repos: []Repo{
60 {
61 Name: "com_private_my_repo",
62 GoPrefix: "private.com/my/repo",
63 },
64 },
65 wantError: true,
66 },
67 {
68 in: "github.com/foo/bar",
69 repos: []Repo{{
70 Name: "custom_repo",
71 GoPrefix: "github.com/foo/bar",
72 }},
73 wantRoot: "github.com/foo/bar",
74 wantName: "custom_repo",
75 },
76 } {
77 t.Run(tc.in, func(t *testing.T) {
78 rc := NewStubRemoteCache(tc.repos)
79 if gotRoot, gotName, err := rc.Root(tc.in); err != nil {
80 if !tc.wantError {
81 t.Errorf("unexpected error: %v", err)
82 }
83 } else if tc.wantError {
84 t.Errorf("unexpected success: %v", tc.in)
85 } else if gotRoot != tc.wantRoot {
86 t.Errorf("root for %q: got %q; want %q", tc.in, gotRoot, tc.wantRoot)
87 } else if gotName != tc.wantName {
88 t.Errorf("name for %q: got %q; want %q", tc.in, gotName, tc.wantName)
89 }
90 })
91 }
92 }
93
94 func TestRootStatic(t *testing.T) {
95 for _, tc := range []struct {
96 in, wantRoot, wantName string
97 repos []Repo
98 }{
99 {
100 in: "private.com/my/repo/package/path",
101 repos: []Repo{
102 {
103 Name: "com_other_host_repo",
104 GoPrefix: "other-host.com/repo",
105 }, {
106 Name: "com_private_my_repo",
107 GoPrefix: "private.com/my/repo",
108 },
109 },
110 wantRoot: "private.com/my/repo",
111 wantName: "com_private_my_repo",
112 },
113 {
114 in: "unsupported.org/x/net/context",
115 repos: []Repo{
116 {
117 Name: "com_private_my_repo",
118 GoPrefix: "private.com/my/repo",
119 },
120 },
121 wantRoot: "",
122 wantName: "",
123 },
124 } {
125 t.Run(tc.in, func(t *testing.T) {
126 rc := NewStubRemoteCache(tc.repos)
127 if gotRoot, gotName, err := rc.RootStatic(tc.in); err != nil {
128 t.Errorf("unexpected error: %v", err)
129 } else if gotRoot != tc.wantRoot {
130 t.Errorf("root for %q: got %q; want %q", tc.in, gotRoot, tc.wantRoot)
131 } else if gotName != tc.wantName {
132 t.Errorf("name for %q: got %q; want %q", tc.in, gotName, tc.wantName)
133 }
134 })
135 }
136 }
137
138 func TestRootPopulatedFromGoMod(t *testing.T) {
139 tmpDir := t.TempDir()
140 goModPath := filepath.Join(tmpDir, "go.mod")
141 goModData := []byte(`
142 module example.com/use
143 go 1.19
144 require example.com/good v1.0.0
145 `)
146 if err := os.WriteFile(goModPath, goModData, 0666); err != nil {
147 t.Fatal(err)
148 }
149
150 rc := NewStubRemoteCache(nil)
151 if err := rc.PopulateFromGoMod(goModPath); err != nil {
152 t.Fatal(err)
153 }
154 errResolve := errors.New("test cannot lookup external package")
155 rc.RepoRootForImportPath = func(string, bool) (*vcs.RepoRoot, error) {
156 return nil, errResolve
157 }
158
159
160 goodPkgPath := "example.com/good/pkg"
161 wantRoot := "example.com/good"
162 wantName := "com_example_good"
163 root, name, err := rc.Root(goodPkgPath)
164 if err != nil {
165 t.Fatalf("could not resolve %q from go.mod: %v", goodPkgPath, err)
166 }
167 if root != wantRoot {
168 t.Errorf("got root %q; want %q", root, wantRoot)
169 }
170 if name != wantName {
171 t.Errorf("got name %q; want %q", root, wantName)
172 }
173
174
175
176 badPkgPath := "example.com/bad/pkg"
177 if _, _, err := rc.Root(badPkgPath); err == nil {
178 t.Errorf("resolving %q: unexpected success", badPkgPath)
179 } else if !errors.Is(err, errResolve) {
180 t.Errorf("resolving %q: got error %v, want %v", badPkgPath, err, errResolve)
181 }
182 }
183
184 func TestRemote(t *testing.T) {
185 for _, tc := range []struct {
186 desc, root string
187 repos []Repo
188 wantRemote, wantVCS string
189 wantError bool
190 }{
191 {
192 desc: "unstubbed_remote",
193 root: "github.com/bazelbuild/bazel-gazelle",
194 wantError: true,
195 }, {
196 desc: "known_repo",
197 root: "github.com/example/project",
198 repos: []Repo{{
199 Name: "com_github_example_project",
200 GoPrefix: "github.com/example/project",
201 Remote: "https://private.com/example/project",
202 VCS: "git",
203 }},
204 wantRemote: "https://private.com/example/project",
205 wantVCS: "git",
206 }, {
207 desc: "git_repo",
208 root: "example.com/repo",
209 wantRemote: "https://example.com/repo.git",
210 wantVCS: "git",
211 }, {
212 desc: "local_repo",
213 root: "github.com/example/project",
214 repos: []Repo{{
215 Name: "com_github_example_project",
216 GoPrefix: "github.com/example/project",
217 Remote: "/home/joebob/go/src/github.com/example/project",
218 VCS: "local",
219 }},
220 wantRemote: "/home/joebob/go/src/github.com/example/project",
221 wantVCS: "local",
222 },
223 } {
224 t.Run(tc.desc, func(t *testing.T) {
225 rc := NewStubRemoteCache(tc.repos)
226 if gotRemote, gotVCS, err := rc.Remote(tc.root); err != nil {
227 if !tc.wantError {
228 t.Errorf("unexpected error: %v", err)
229 }
230 } else if tc.wantError {
231 t.Errorf("unexpected success")
232 } else if gotRemote != tc.wantRemote {
233 t.Errorf("remote for %q: got %q ; want %q", tc.root, gotRemote, tc.wantRemote)
234 } else if gotVCS != tc.wantVCS {
235 t.Errorf("vcs for %q: got %q ; want %q", tc.root, gotVCS, tc.wantVCS)
236 }
237 })
238 }
239 }
240
241 func TestHead(t *testing.T) {
242 for _, tc := range []struct {
243 desc, remote, vcs string
244 wantCommit, wantTag string
245 wantError bool
246 }{
247 {
248 desc: "unstubbed_remote",
249 remote: "https://github.com/bazelbuild/bazel-gazelle",
250 vcs: "git",
251 wantError: true,
252 },
253 } {
254 t.Run(tc.desc, func(t *testing.T) {
255 rc := NewStubRemoteCache(nil)
256 if gotCommit, gotTag, err := rc.Head(tc.remote, tc.vcs); err != nil {
257 if !tc.wantError {
258 t.Errorf("unexpected error: %v", err)
259 }
260 } else if tc.wantError {
261 t.Errorf("unexpected success")
262 } else if gotCommit != tc.wantCommit {
263 t.Errorf("commit for %q: got %q ; want %q", tc.remote, gotCommit, tc.wantCommit)
264 } else if gotTag != tc.wantTag {
265 t.Errorf("tag for %q: got %q ; want %q", tc.remote, gotTag, tc.wantTag)
266 }
267 })
268 }
269 }
270
271 func TestMod(t *testing.T) {
272 for _, tc := range []struct {
273 desc, importPath string
274 repos []Repo
275 wantModPath, wantName string
276 wantErr bool
277 }{
278 {
279 desc: "no_special_cases",
280 importPath: "golang.org/x/exp",
281 wantErr: true,
282 }, {
283 desc: "known",
284 importPath: "example.com/known/v2/foo",
285 repos: []Repo{{
286 Name: "known",
287 GoPrefix: "example.com/known",
288 }},
289 wantModPath: "example.com/known",
290 wantName: "known",
291 }, {
292 desc: "semver_less_path_is_safe",
293 importPath: "example.com/known/internal/endpoints",
294 repos: []Repo{{
295 Name: "known",
296 GoPrefix: "example.com/known",
297 }, {
298 Name: "known_internal_endpoints_v2",
299 GoPrefix: "example.com/known/internal/endpoints/v2",
300 }},
301 wantModPath: "example.com/known",
302 wantName: "known",
303 }, {
304 desc: "lookup",
305 importPath: "example.com/stub/v2/foo",
306 wantModPath: "example.com/stub/v2",
307 wantName: "com_example_stub_v2",
308 },
309 } {
310 t.Run(tc.desc, func(t *testing.T) {
311 rc := NewStubRemoteCache(tc.repos)
312 modPath, name, err := rc.Mod(tc.importPath)
313 if err != nil && tc.wantErr {
314 return
315 } else if err == nil && tc.wantErr {
316 t.Error("want error; got success")
317 } else if err != nil {
318 t.Fatal(err)
319 }
320 if modPath != tc.wantModPath {
321 t.Errorf("modPath: got %s; want %s", modPath, tc.wantModPath)
322 }
323 if name != tc.wantName {
324 t.Errorf("name: got %s; want %s", name, tc.wantName)
325 }
326 })
327 }
328 }
329
330 func TestModVersion(t *testing.T) {
331 for _, tc := range []struct {
332 desc, modPath, query string
333 repos []Repo
334 wantName, wantVersion, wantSum string
335 }{
336 {
337 desc: "known",
338 modPath: "example.com/known",
339 query: "latest",
340 repos: []Repo{{
341 Name: "known",
342 GoPrefix: "example.com/known",
343 }},
344 wantName: "known",
345 wantVersion: "v1.2.3",
346 wantSum: "h1:abcdef",
347 }, {
348 desc: "unknown",
349 modPath: "example.com/unknown",
350 query: "latest",
351 wantName: "com_example_unknown",
352 wantVersion: "v1.2.3",
353 wantSum: "h1:abcdef",
354 },
355 } {
356 t.Run(tc.desc, func(t *testing.T) {
357 rc := NewStubRemoteCache(tc.repos)
358 name, version, sum, err := rc.ModVersion(tc.modPath, tc.query)
359 if err != nil {
360 t.Fatal(err)
361 }
362 if name != tc.wantName {
363 t.Errorf("name: got %q; want %q", name, tc.wantName)
364 }
365 if version != tc.wantVersion {
366 t.Errorf("version: got %q; want %q", version, tc.wantVersion)
367 }
368 if sum != tc.wantSum {
369 t.Errorf("sum: got %q; want %q", sum, tc.wantSum)
370 }
371 })
372 }
373 }
374
View as plain text