1
15
16 package main
17
18 import (
19 "flag"
20 "fmt"
21 "os"
22 "path/filepath"
23 "runtime"
24 "strings"
25 "testing"
26
27 "github.com/bazelbuild/bazel-gazelle/testtools"
28 "github.com/bazelbuild/rules_go/go/tools/bazel"
29 )
30
31 var goSdk = flag.String("go_sdk", "", "name of the go_sdk repository when invoked by Bazel")
32
33 func TestMain(m *testing.M) {
34 status := 1
35 defer func() {
36 os.Exit(status)
37 }()
38
39 flag.Parse()
40
41 var err error
42 tmpDir, err := os.MkdirTemp(os.Getenv("TEST_TMPDIR"), "gazelle_test")
43 if err != nil {
44 fmt.Fprintln(os.Stderr, err)
45 return
46 }
47 defer func() {
48
49
50
51
52 _ = filepath.Walk(tmpDir, func(path string, info os.FileInfo, err error) error {
53 if err != nil {
54 return err
55 }
56 if mode := info.Mode(); mode&0o200 == 0 {
57 err = os.Chmod(path, mode|0o200)
58 }
59 return err
60 })
61 os.RemoveAll(tmpDir)
62 }()
63
64 if *goSdk != "" {
65
66
67 entries, err := bazel.ListRunfiles()
68 if err != nil {
69 fmt.Fprintln(os.Stderr, err)
70 return
71 }
72
73 var goToolPath string
74 ext := ""
75 if runtime.GOOS == "windows" {
76 ext = ".exe"
77 }
78 for _, entry := range entries {
79 if entry.Workspace == *goSdk && entry.ShortPath == "bin/go"+ext {
80 goToolPath = entry.Path
81 break
82 }
83 }
84 if goToolPath == "" {
85 fmt.Fprintln(os.Stderr, "could not locate go tool")
86 return
87 }
88 os.Setenv("GOROOT", filepath.Dir(filepath.Dir(goToolPath)))
89 }
90 os.Setenv("GOCACHE", filepath.Join(tmpDir, "gocache"))
91 os.Setenv("GOPATH", filepath.Join(tmpDir, "gopath"))
92
93 status = m.Run()
94 }
95
96 func defaultArgs(dir string) []string {
97 return []string{
98 "-repo_root", dir,
99 "-go_prefix", "example.com/repo",
100 dir,
101 }
102 }
103
104 func TestCreateFile(t *testing.T) {
105
106 tmpdir := os.Getenv("TEST_TMPDIR")
107 dir, err := os.MkdirTemp(tmpdir, "")
108 if err != nil {
109 t.Fatalf("os.MkdirTemp(%q, %q) failed with %v; want success", tmpdir, "", err)
110 }
111 defer os.RemoveAll(dir)
112
113 goFile := filepath.Join(dir, "main.go")
114 if err = os.WriteFile(goFile, []byte("package main"), 0o600); err != nil {
115 t.Fatalf("error writing file %q: %v", goFile, err)
116 }
117
118
119 if err = run(dir, defaultArgs(dir)); err != nil {
120 t.Fatalf("run failed: %v", err)
121 }
122
123 buildFile := filepath.Join(dir, "BUILD.bazel")
124 if _, err = os.Stat(buildFile); err != nil {
125 t.Errorf("could not stat BUILD.bazel: %v", err)
126 }
127 }
128
129 func TestUpdateFile(t *testing.T) {
130
131 tmpdir := os.Getenv("TEST_TMPDIR")
132 dir, err := os.MkdirTemp(tmpdir, "")
133 if err != nil {
134 t.Fatalf("os.MkdirTemp(%q, %q) failed with %v; want success", tmpdir, "", err)
135 }
136 defer os.RemoveAll(dir)
137
138 goFile := filepath.Join(dir, "main.go")
139 if err = os.WriteFile(goFile, []byte("package main"), 0o600); err != nil {
140 t.Fatalf("error writing file %q: %v", goFile, err)
141 }
142
143 buildFile := filepath.Join(dir, "BUILD")
144 if err = os.WriteFile(buildFile, nil, 0o600); err != nil {
145 t.Fatalf("error writing file %q: %v", buildFile, err)
146 }
147
148
149 if err = run(dir, defaultArgs(dir)); err != nil {
150 t.Fatalf("run failed: %v", err)
151 }
152
153 if st, err := os.Stat(buildFile); err != nil {
154 t.Errorf("could not stat BUILD: %v", err)
155 } else if st.Size() == 0 {
156 t.Errorf("BUILD was not updated")
157 }
158
159 if _, err = os.Stat(filepath.Join(dir, "BUILD.bazel")); err == nil {
160 t.Errorf("BUILD.bazel should not exist")
161 }
162 }
163
164 func TestNoChanges(t *testing.T) {
165
166 tmpdir := os.Getenv("TEST_TMPDIR")
167 dir, err := os.MkdirTemp(tmpdir, "")
168 if err != nil {
169 t.Fatalf("os.MkdirTemp(%q, %q) failed with %v; want success", tmpdir, "", err)
170 }
171 defer os.RemoveAll(dir)
172
173 goFile := filepath.Join(dir, "main.go")
174 if err = os.WriteFile(goFile, []byte("package main\n\nfunc main() {}"), 0o600); err != nil {
175 t.Fatalf("error writing file %q: %v", goFile, err)
176 }
177
178 buildFile := filepath.Join(dir, "BUILD")
179 if err = os.WriteFile(buildFile, []byte(`load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
180
181 go_library(
182 name = "go_default_library",
183 srcs = ["main.go"],
184 importpath = "example.com/repo",
185 visibility = ["//visibility:private"],
186 )
187
188 go_binary(
189 name = "hello",
190 embed = [":go_default_library"],
191 visibility = ["//visibility:public"],
192 )
193 `), 0o600); err != nil {
194 t.Fatalf("error writing file %q: %v", buildFile, err)
195 }
196 st, err := os.Stat(buildFile)
197 if err != nil {
198 t.Errorf("could not stat BUILD: %v", err)
199 }
200 modTime := st.ModTime()
201
202
203 if err = run(dir, defaultArgs(dir)); err != nil {
204 t.Fatalf("run failed: %v", err)
205 }
206
207 if st, err := os.Stat(buildFile); err != nil {
208 t.Errorf("could not stat BUILD: %v", err)
209 } else if !modTime.Equal(st.ModTime()) {
210 t.Errorf("unexpected modificaiton to BUILD")
211 }
212 }
213
214 func TestFixReadWriteDir(t *testing.T) {
215 buildInFile := testtools.FileSpec{
216 Path: "in/BUILD.in",
217 Content: `
218 go_binary(
219 name = "hello",
220 pure = "on",
221 )
222 `,
223 }
224 buildSrcFile := testtools.FileSpec{
225 Path: "src/BUILD.bazel",
226 Content: `# src build file`,
227 }
228 oldFiles := []testtools.FileSpec{
229 buildInFile,
230 buildSrcFile,
231 {
232 Path: "src/hello.go",
233 Content: `
234 package main
235
236 func main() {}
237 `,
238 },
239 {
240 Path: "out/BUILD",
241 Content: `this should get replaced`,
242 },
243 }
244
245 for _, tc := range []struct {
246 desc string
247 args []string
248 want []testtools.FileSpec
249 }{
250 {
251 desc: "read",
252 args: []string{
253 "-repo_root={{dir}}/src",
254 "-experimental_read_build_files_dir={{dir}}/in",
255 "-build_file_name=BUILD.bazel,BUILD,BUILD.in",
256 "-go_prefix=example.com/repo",
257 "{{dir}}/src",
258 },
259 want: []testtools.FileSpec{
260 buildInFile,
261 {
262 Path: "src/BUILD.bazel",
263 Content: `
264 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
265
266 go_binary(
267 name = "hello",
268 embed = [":repo_lib"],
269 pure = "on",
270 visibility = ["//visibility:public"],
271 )
272
273 go_library(
274 name = "repo_lib",
275 srcs = ["hello.go"],
276 importpath = "example.com/repo",
277 visibility = ["//visibility:private"],
278 )
279 `,
280 },
281 },
282 }, {
283 desc: "write",
284 args: []string{
285 "-repo_root={{dir}}/src",
286 "-experimental_write_build_files_dir={{dir}}/out",
287 "-build_file_name=BUILD.bazel,BUILD,BUILD.in",
288 "-go_prefix=example.com/repo",
289 "{{dir}}/src",
290 },
291 want: []testtools.FileSpec{
292 buildInFile,
293 buildSrcFile,
294 {
295 Path: "out/BUILD",
296 Content: `
297 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
298
299 # src build file
300
301 go_library(
302 name = "repo_lib",
303 srcs = ["hello.go"],
304 importpath = "example.com/repo",
305 visibility = ["//visibility:private"],
306 )
307
308 go_binary(
309 name = "repo",
310 embed = [":repo_lib"],
311 visibility = ["//visibility:public"],
312 )
313 `,
314 },
315 },
316 }, {
317 desc: "read_and_write",
318 args: []string{
319 "-repo_root={{dir}}/src",
320 "-experimental_read_build_files_dir={{dir}}/in",
321 "-experimental_write_build_files_dir={{dir}}/out",
322 "-build_file_name=BUILD.bazel,BUILD,BUILD.in",
323 "-go_prefix=example.com/repo",
324 "{{dir}}/src",
325 },
326 want: []testtools.FileSpec{
327 buildInFile,
328 {
329 Path: "out/BUILD",
330 Content: `
331 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
332
333 go_binary(
334 name = "hello",
335 embed = [":repo_lib"],
336 pure = "on",
337 visibility = ["//visibility:public"],
338 )
339
340 go_library(
341 name = "repo_lib",
342 srcs = ["hello.go"],
343 importpath = "example.com/repo",
344 visibility = ["//visibility:private"],
345 )
346 `,
347 },
348 },
349 },
350 } {
351 t.Run(tc.desc, func(t *testing.T) {
352 dir, cleanup := testtools.CreateFiles(t, oldFiles)
353 defer cleanup()
354 replacer := strings.NewReplacer("{{dir}}", dir, "/", string(os.PathSeparator))
355 for i := range tc.args {
356 if strings.HasPrefix(tc.args[i], "-go_prefix=") {
357 continue
358 }
359 tc.args[i] = replacer.Replace(tc.args[i])
360 }
361 if err := run(dir, tc.args); err != nil {
362 t.Error(err)
363 }
364 testtools.CheckFiles(t, dir, tc.want)
365 })
366 }
367 }
368
369 func TestFix_LangFilter(t *testing.T) {
370 fixture := []testtools.FileSpec{
371 {
372 Path: "BUILD.bazel",
373 Content: `
374 load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
375
376 go_binary(
377 name = "nofix",
378 library = ":go_default_library",
379 visibility = ["//visibility:public"],
380 )
381
382 go_library(
383 name = "go_default_library",
384 srcs = ["main.go"],
385 importpath = "example.com/repo",
386 visibility = ["//visibility:public"],
387 )`,
388 },
389 {
390 Path: "main.go",
391 Content: `package main`,
392 },
393 }
394
395 dir, cleanup := testtools.CreateFiles(t, fixture)
396 defer cleanup()
397
398
399 if err := run(dir, []string{
400 "-repo_root", dir,
401 "-go_prefix", "example.com/repo",
402 "-lang=proto",
403 dir,
404 }); err != nil {
405 t.Fatalf("run failed: %v", err)
406 }
407
408 testtools.CheckFiles(t, dir, fixture)
409 }
410
View as plain text