1
16
17 package bzlmod
18
19 import (
20 "reflect"
21 "strconv"
22 "testing"
23
24 "github.com/bazelbuild/buildtools/build"
25 )
26
27 const proxiesNoModuleHeader = ``
28
29 const proxiesModuleNameHeader = `
30 module(name = "name")
31 `
32
33 const proxiesModuleRepoNameHeader = `
34 module(name = "name", repo_name = "repo_name")
35 `
36
37 const proxiesBody = `
38 prox1 = use_extension("@name//bzl:extensions.bzl", "ext")
39 prox1.use(name = "foo")
40 isolated_prox1 = use_extension("@name//bzl:extensions.bzl", "ext", dev_dependency = False, isolate = True)
41 isolated_prox1.use(name = "foo")
42 prox2 = use_extension("@name//bzl:extensions.bzl", "ext", dev_dependency = True)
43 prox2.use(list = ["foo", "bar"])
44 # some comment
45 prox3 = use_extension("@repo_name//bzl:extensions.bzl", "ext")
46 prox3.use(label = "@dep//:bar")
47 isolated_prox2 = use_extension("@name//bzl:extensions.bzl", "ext", dev_dependency = True, isolate = True)
48 isolated_prox2.use(name = "foo")
49 prox4 = use_extension("@repo_name//bzl:extensions.bzl", "ext", dev_dependency = True)
50 prox4.use(dict = {"foo": "bar"})
51 isolated_prox3 = use_extension("@name//bzl:extensions.bzl", "ext", dev_dependency = True, isolate = True)
52 isolated_prox3.use(name = "foo")
53 prox5 = use_extension("@//bzl:extensions.bzl", "ext")
54 prox5.use(name = "foo")
55 prox6 = use_extension("@//bzl:extensions.bzl", "ext", dev_dependency = True)
56 prox6.use(list = ["foo", "bar"])
57 prox7 = use_extension("//bzl:extensions.bzl", "ext", dev_dependency = False)
58 prox7.use(label = "@foo//:bar")
59 isolated_prox4 = use_extension("@name//bzl:extensions.bzl", "ext", isolate = True)
60 isolated_prox4.use(name = "foo")
61 prox8 = use_extension("//bzl:extensions.bzl", "ext", dev_dependency = True)
62 prox8.use(dict = {"foo": "bar"})
63 prox9 = use_extension(
64 # comment
65 "@dep//:extensions.bzl", "other_ext")
66 prox9.use(label = "@name//:bar")
67 prox10 = use_extension("@dep//:extensions.bzl", "other_ext", dev_dependency = bool(1))
68 prox10.use(dict = {"foo": "bar"})
69 `
70
71 func TestProxies(t *testing.T) {
72 for i, tc := range []struct {
73 content string
74 extBzlFiles []string
75 extName string
76 dev bool
77 expectedProxies []string
78 }{
79 {
80 proxiesNoModuleHeader + proxiesBody,
81 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl"},
82 "ext",
83 false,
84 []string{"prox5", "prox7"},
85 },
86 {
87 proxiesNoModuleHeader + proxiesBody,
88 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl"},
89 "ext",
90 true,
91 []string{"prox6", "prox8"},
92 },
93 {
94 proxiesModuleNameHeader + proxiesBody,
95 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl", "@name//bzl:extensions.bzl"},
96 "ext",
97 false,
98 []string{"prox1", "prox5", "prox7"},
99 },
100 {
101 proxiesModuleNameHeader + proxiesBody,
102 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl", "@name//bzl:extensions.bzl"},
103 "ext",
104 true,
105 []string{"prox2", "prox6", "prox8"},
106 },
107 {
108 proxiesModuleRepoNameHeader + proxiesBody,
109 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl", "@repo_name//bzl:extensions.bzl"},
110 "ext",
111 false,
112 []string{"prox3", "prox5", "prox7"},
113 },
114 {
115 proxiesModuleRepoNameHeader + proxiesBody,
116 []string{"//bzl:extensions.bzl", "@//bzl:extensions.bzl", "@repo_name//bzl:extensions.bzl"},
117 "ext",
118 true,
119 []string{"prox4", "prox6", "prox8"},
120 },
121 {
122 proxiesModuleRepoNameHeader + proxiesBody,
123 []string{"@name//bzl:extensions.bzl"},
124 "ext",
125 false,
126 []string{"prox1"},
127 },
128 {
129 proxiesModuleRepoNameHeader + proxiesBody,
130 []string{"@dep//:extensions.bzl"},
131 "other_ext",
132 false,
133 []string{"prox9"},
134 },
135 {
136 proxiesModuleRepoNameHeader + proxiesBody,
137 []string{"@dep//:extensions.bzl"},
138 "other_ext",
139 true,
140 []string{"prox10"},
141 },
142 } {
143 t.Run(strconv.Itoa(i), func(t *testing.T) {
144 for _, extBzlFile := range tc.extBzlFiles {
145 t.Run("label_"+extBzlFile, func(t *testing.T) {
146
147 f, err := build.ParseModule("MODULE.bazel", []byte(tc.content))
148 if err != nil {
149 t.Fatal(err)
150 }
151 actualProxies := Proxies(f, extBzlFile, tc.extName, tc.dev)
152 if !reflect.DeepEqual(actualProxies, tc.expectedProxies) {
153 t.Error("want: ", tc.expectedProxies, ", got: ", actualProxies)
154 }
155 })
156 }
157 })
158 }
159 }
160
161 func TestAllProxies(t *testing.T) {
162 for i, tc := range []struct {
163 proxy string
164 expectedProxies []string
165 }{
166 {
167 "invalid_proxy",
168 nil,
169 },
170 {
171 "isolated_prox1",
172 []string{"isolated_prox1"},
173 },
174 {
175 "isolated_prox2",
176 []string{"isolated_prox2"},
177 },
178 {
179 "isolated_prox3",
180 []string{"isolated_prox3"},
181 },
182 {
183 "isolated_prox4",
184 []string{"isolated_prox4"},
185 },
186 {
187 "prox1",
188 []string{"prox1", "prox5", "prox7"},
189 },
190 {
191 "prox2",
192 []string{"prox2", "prox6", "prox8"},
193 },
194 {
195 "prox9",
196 []string{"prox9"},
197 },
198 {
199 "prox10",
200 []string{"prox10"},
201 },
202 } {
203 t.Run(strconv.Itoa(i), func(t *testing.T) {
204 f, err := build.ParseModule("MODULE.bazel", []byte(proxiesModuleNameHeader+proxiesBody))
205 if err != nil {
206 t.Fatal(err)
207 }
208 proxies := AllProxies(f, tc.proxy)
209 if !reflect.DeepEqual(proxies, tc.expectedProxies) {
210 t.Error("want: ", tc.expectedProxies, ", got: ", proxies)
211 }
212 })
213 }
214 }
215
216 const useReposFile = `
217 prox1 = use_extension("@mod//bzl:extensions.bzl", "ext")
218 prox1.use()
219 prox1.config()
220 prox2 = use_extension("//bzl:extensions.bzl", "ext")
221 use_repo(prox2)
222 use_repo(prox1, "repo5")
223 prox3 = use_extension("@dep//bzl:extensions.bzl", "ext")
224 prox2_dev = use_extension("//bzl:extensions.bzl", "ext", dev_dependency = True)
225 use_repo(prox1, "repo1")
226 use_repo(prox3, "repo2")
227 use_repo(prox2, "repo3", "repo4")
228 `
229
230 func TestUseRepos(t *testing.T) {
231 for i, tc := range []struct {
232 content string
233 proxies []string
234 expectedStmts []int
235 }{
236 {
237 useReposFile,
238 []string{"prox2"},
239 []int{4, 10},
240 },
241 {
242 useReposFile,
243 []string{"prox1", "prox3"},
244 []int{5, 8, 9},
245 },
246 {
247 useReposFile,
248 []string{"prox2_dev"},
249 []int{},
250 },
251 } {
252 t.Run(strconv.Itoa(i), func(t *testing.T) {
253 f, err := build.ParseModule("MODULE.bazel", []byte(tc.content))
254 if err != nil {
255 t.Fatal(err)
256 }
257 var expectedUseRepos []*build.CallExpr
258 for _, stmt := range tc.expectedStmts {
259 expectedUseRepos = append(expectedUseRepos, f.Stmt[stmt].(*build.CallExpr))
260 }
261 actualUseRepos := UseRepos(f, tc.proxies)
262 if !reflect.DeepEqual(actualUseRepos, expectedUseRepos) {
263 t.Error("want: ", expectedUseRepos, ", got: ", actualUseRepos)
264 }
265 })
266 }
267 }
268
269 func TestNewUseRepos(t *testing.T) {
270 for i, tc := range []struct {
271 content string
272 proxies []string
273 expectedContent string
274 expectedUseRepo int
275 }{
276 {
277 ``,
278 []string{"prox1"},
279 ``,
280 -1,
281 },
282 {
283 `prox1 = use_extension("@module//:lib.bzl", "ext")`,
284 []string{"prox2"},
285 `prox1 = use_extension("@module//:lib.bzl", "ext")
286 `,
287 -1,
288 },
289 {
290 `prox1 = use_extension("@mod//bzl:extensions.bzl", "ext", dev_dependency = True)`,
291 []string{"prox1"},
292 `prox1 = use_extension("@mod//bzl:extensions.bzl", "ext", dev_dependency = True)
293 use_repo(prox1)
294 `,
295 1,
296 },
297 {
298 `prox1 = use_extension("@mod//bzl:extensions.bzl", "ext")
299 prox1.config()
300 prox1.download(name = "foo")`,
301 []string{"prox1"},
302 `prox1 = use_extension("@mod//bzl:extensions.bzl", "ext")
303 prox1.config()
304 prox1.download(name = "foo")
305 use_repo(prox1)
306 `,
307 3,
308 },
309 {
310 `go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
311 go_deps.from_file(go_mod = "//:go.mod")
312
313 pull = use_extension("@rules_oci//oci:pull.bzl", "go_deps")
314 pull.oci_pull(name = "distroless_base")
315 `,
316 []string{"go_deps"},
317 `go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
318 go_deps.from_file(go_mod = "//:go.mod")
319 use_repo(go_deps)
320
321 pull = use_extension("@rules_oci//oci:pull.bzl", "go_deps")
322 pull.oci_pull(name = "distroless_base")
323 `,
324 2,
325 },
326 {
327 `go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
328 go_deps.from_file(go_mod = "//:go.mod")
329
330 pull = use_extension("@rules_oci//oci:pull.bzl", "go_deps")
331 `,
332 []string{"go_deps"},
333 `go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
334 go_deps.from_file(go_mod = "//:go.mod")
335 use_repo(go_deps)
336
337 pull = use_extension("@rules_oci//oci:pull.bzl", "go_deps")
338 `,
339 2,
340 },
341 } {
342 t.Run(strconv.Itoa(i), func(t *testing.T) {
343 f, err := build.ParseModule("MODULE.bazel", []byte(tc.content))
344 if err != nil {
345 t.Fatal(err)
346 }
347 f, actualNewUseRepo := NewUseRepo(f, tc.proxies)
348 actualContent := string(build.Format(f))
349 if actualNewUseRepo != nil {
350 if !reflect.DeepEqual(actualNewUseRepo, f.Stmt[tc.expectedUseRepo]) {
351 t.Error("want: ", f.Stmt[tc.expectedUseRepo], ", got: ", actualNewUseRepo)
352 }
353 } else {
354 if tc.expectedUseRepo != -1 {
355 t.Error("wanted a nil new use_repo")
356 }
357 }
358 if !reflect.DeepEqual(actualContent, tc.expectedContent) {
359 t.Errorf("want:\n%q\ngot:\n%q\n", tc.expectedContent, actualContent)
360 }
361 })
362 }
363 }
364
365 func TestAddRepoUsages(t *testing.T) {
366 for i, tc := range []struct {
367 content string
368 repos []string
369 expectedContent string
370 }{
371 {
372 ``,
373 []string{},
374 ``,
375 },
376 {
377 `use_repo(prox)`,
378 []string{"repo2", "repo1"},
379 `use_repo(prox, "repo1", "repo2")
380 `,
381 },
382 {
383 `use_repo(
384 prox,
385 )`,
386 []string{"repo2", "repo1"},
387 `use_repo(
388 prox,
389 "repo1",
390 "repo2",
391 )
392 `,
393 },
394 {
395 `use_repo(prox, "repo2")`,
396 []string{"repo2", "repo1"},
397 `use_repo(prox, "repo1", "repo2")
398 `,
399 },
400 {
401 `use_repo(
402 prox,
403 "repo2",
404 )`,
405 []string{"repo2", "repo1"},
406 `use_repo(
407 prox,
408 "repo1",
409 "repo2",
410 )
411 `,
412 },
413 {
414 `use_repo(prox, "repo1")
415 use_repo(
416 prox2,
417 my_repo = "repo2",
418 "repo5",
419 )
420 use_repo(prox, "repo3")`,
421 []string{"repo3", "repo2", "repo4"},
422 `use_repo(prox, "repo1")
423
424 use_repo(
425 prox2,
426 "repo5",
427 my_repo = "repo2",
428 )
429
430 use_repo(prox, "repo3", "repo4")
431 `,
432 },
433 } {
434 t.Run(strconv.Itoa(i), func(t *testing.T) {
435 f, err := build.ParseModule("MODULE.bazel", []byte(tc.content))
436 if err != nil {
437 t.Fatal(err)
438 }
439 var useRepos []*build.CallExpr
440 for _, stmt := range f.Stmt {
441 useRepos = append(useRepos, stmt.(*build.CallExpr))
442 }
443 AddRepoUsages(useRepos, tc.repos...)
444 actualContent := string(build.Format(f))
445 if !reflect.DeepEqual(actualContent, tc.expectedContent) {
446 t.Errorf("want:\n%q\ngot:\n%q\n", tc.expectedContent, actualContent)
447 }
448 })
449 }
450 }
451
452 func TestRemoveRepoUsages(t *testing.T) {
453 for i, tc := range []struct {
454 content string
455 repos []string
456 expectedContent string
457 }{
458 {
459 ``,
460 []string{"repo1"},
461 ``,
462 },
463 {
464 `use_repo(prox)`,
465 []string{"repo2", "repo1"},
466 `use_repo(prox)
467 `,
468 },
469 {
470 `use_repo(
471 prox,
472 )`,
473 []string{"repo2", "repo1"},
474 `use_repo(
475 prox,
476 )
477 `,
478 },
479 {
480 `use_repo(prox, "repo2")`,
481 []string{"repo2", "repo1"},
482 `use_repo(prox)
483 `,
484 },
485 {
486 `use_repo(
487 prox,
488 "repo2",
489 )`,
490 []string{"repo2", "repo1"},
491 `use_repo(prox)
492 `,
493 },
494 {
495 `use_repo(prox, "repo1")
496 use_repo(
497 prox2,
498 my_repo = "repo2",
499 "repo5",
500 )
501 use_repo(prox, "repo3")`,
502 []string{"repo3", "repo2", "repo4"},
503 `use_repo(prox, "repo1")
504
505 use_repo(
506 prox2,
507 "repo5",
508 )
509
510 use_repo(prox)
511 `,
512 },
513 } {
514 t.Run(strconv.Itoa(i), func(t *testing.T) {
515 f, err := build.ParseModule("MODULE.bazel", []byte(tc.content))
516 if err != nil {
517 t.Fatal(err)
518 }
519 var useRepos []*build.CallExpr
520 for _, stmt := range f.Stmt {
521 useRepos = append(useRepos, stmt.(*build.CallExpr))
522 }
523 RemoveRepoUsages(useRepos, tc.repos...)
524 actualContent := string(build.Format(f))
525 if !reflect.DeepEqual(actualContent, tc.expectedContent) {
526 t.Errorf("want:\n%q\ngot:\n%q\n", tc.expectedContent, actualContent)
527 }
528 })
529 }
530 }
531
View as plain text