github.com/wolfd/bazel-gazelle@v0.14.0/internal/walk/walk_test.go (about) 1 /* Copyright 2018 The Bazel Authors. All rights reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package walk 17 18 import ( 19 "flag" 20 "io/ioutil" 21 "os" 22 "path" 23 "path/filepath" 24 "reflect" 25 "strings" 26 "testing" 27 28 "github.com/bazelbuild/bazel-gazelle/internal/config" 29 "github.com/bazelbuild/bazel-gazelle/internal/rule" 30 ) 31 32 func TestConfigureCallbackOrder(t *testing.T) { 33 dir, err := createFiles([]fileSpec{{path: "a/b/"}}) 34 if err != nil { 35 t.Fatal(err) 36 } 37 defer os.RemoveAll(dir) 38 var configureRels, callbackRels []string 39 c, cexts := testConfig(dir) 40 cexts = append(cexts, &testConfigurer{func(_ *config.Config, rel string, _ *rule.File) { 41 configureRels = append(configureRels, rel) 42 }}) 43 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 44 callbackRels = append(callbackRels, rel) 45 }) 46 if want := []string{"", "a", "a/b"}; !reflect.DeepEqual(configureRels, want) { 47 t.Errorf("configure order: got %#v; want %#v", configureRels, want) 48 } 49 if want := []string{"a/b", "a", ""}; !reflect.DeepEqual(callbackRels, want) { 50 t.Errorf("callback order: got %#v; want %#v", callbackRels, want) 51 } 52 } 53 54 func TestUpdateDirs(t *testing.T) { 55 dir, err := createFiles([]fileSpec{ 56 {path: "update/sub/"}, 57 { 58 path: "update/ignore/BUILD.bazel", 59 content: "# gazelle:ignore", 60 }, 61 {path: "update/ignore/sub/"}, 62 { 63 path: "update/error/BUILD.bazel", 64 content: "(", 65 }, 66 {path: "update/error/sub/"}, 67 }) 68 if err != nil { 69 t.Fatal(err) 70 } 71 defer os.RemoveAll(dir) 72 c, cexts := testConfig(dir) 73 c.Dirs = []string{filepath.Join(dir, "update")} 74 type updateSpec struct { 75 rel string 76 update bool 77 } 78 var updates []updateSpec 79 Walk(c, cexts, func(_ string, rel string, _ *config.Config, update bool, _ *rule.File, _, _, _ []string) { 80 updates = append(updates, updateSpec{rel, update}) 81 }) 82 want := []updateSpec{ 83 {"update/error/sub", true}, 84 {"update/error", false}, 85 {"update/ignore/sub", true}, 86 {"update/ignore", false}, 87 {"update/sub", true}, 88 {"update", true}, 89 {"", false}, 90 } 91 if !reflect.DeepEqual(updates, want) { 92 t.Errorf("got %#v; want %#v", updates, want) 93 } 94 } 95 96 func TestCustomBuildName(t *testing.T) { 97 dir, err := createFiles([]fileSpec{ 98 { 99 path: "BUILD.bazel", 100 content: "# gazelle:build_file_name BUILD.test", 101 }, { 102 path: "BUILD", 103 }, { 104 path: "sub/BUILD.test", 105 }, { 106 path: "sub/BUILD.bazel", 107 }, 108 }) 109 if err != nil { 110 t.Fatal(err) 111 } 112 defer os.RemoveAll(dir) 113 c, cexts := testConfig(dir) 114 var buildRels []string 115 Walk(c, cexts, func(_ string, _ string, _ *config.Config, _ bool, f *rule.File, _, _, _ []string) { 116 rel, err := filepath.Rel(c.RepoRoot, f.Path) 117 if err != nil { 118 t.Error(err) 119 } else { 120 buildRels = append(buildRels, filepath.ToSlash(rel)) 121 } 122 }) 123 want := []string{ 124 "sub/BUILD.test", 125 "BUILD.bazel", 126 } 127 if !reflect.DeepEqual(buildRels, want) { 128 t.Errorf("got %#v; want %#v", buildRels, want) 129 } 130 } 131 132 func TestExcludeFiles(t *testing.T) { 133 dir, err := createFiles([]fileSpec{ 134 { 135 path: "BUILD.bazel", 136 content: ` 137 # gazelle:exclude a.go 138 # gazelle:exclude sub/b.go 139 # gazelle:exclude ign 140 # gazelle:exclude gen 141 142 gen( 143 name = "x", 144 out = "gen", 145 ) 146 `, 147 }, 148 {path: "a.go"}, 149 {path: ".dot"}, 150 {path: "_blank"}, 151 {path: "sub/b.go"}, 152 {path: "ign/bad"}, 153 }) 154 if err != nil { 155 t.Fatal(err) 156 } 157 defer os.RemoveAll(dir) 158 c, cexts := testConfig(dir) 159 var files []string 160 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, regularFiles, genFiles []string) { 161 for _, f := range regularFiles { 162 files = append(files, path.Join(rel, f)) 163 } 164 for _, f := range genFiles { 165 files = append(files, path.Join(rel, f)) 166 } 167 }) 168 want := []string{"BUILD.bazel"} 169 if !reflect.DeepEqual(files, want) { 170 t.Errorf("got %#v; want %#v", files, want) 171 } 172 } 173 174 func TestGeneratedFiles(t *testing.T) { 175 dir, err := createFiles([]fileSpec{ 176 { 177 path: "BUILD.bazel", 178 content: ` 179 unknown_rule( 180 name = "blah1", 181 out = "gen1", 182 ) 183 184 unknown_rule( 185 name = "blah2", 186 outs = [ 187 "gen2", 188 "gen-and-static", 189 ], 190 ) 191 `, 192 }, 193 {path: "gen-and-static"}, 194 {path: "static"}, 195 }) 196 if err != nil { 197 t.Fatal(err) 198 } 199 defer os.RemoveAll(dir) 200 c, cexts := testConfig(dir) 201 var regularFiles, genFiles []string 202 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, reg, gen []string) { 203 for _, f := range reg { 204 regularFiles = append(regularFiles, path.Join(rel, f)) 205 } 206 for _, f := range gen { 207 genFiles = append(genFiles, path.Join(rel, f)) 208 } 209 }) 210 if want := []string{"BUILD.bazel", "gen-and-static", "static"}; !reflect.DeepEqual(regularFiles, want) { 211 t.Errorf("regularFiles: got %#v; want %#v", regularFiles, want) 212 } 213 if want := []string{"gen1", "gen2", "gen-and-static"}; !reflect.DeepEqual(genFiles, want) { 214 t.Errorf("genFiles: got %#v; want %#v", genFiles, want) 215 } 216 } 217 218 func TestSymlinksBasic(t *testing.T) { 219 files := []fileSpec{ 220 {path: "root/a.go", content: "package a"}, 221 {path: "root/b", symlink: "../b"}, // symlink outside repo is followed 222 {path: "root/c", symlink: "c"}, // symlink inside repo is not followed. 223 {path: "root/d", symlink: "../b/d"}, // symlink under root/b not followed 224 {path: "root/e", symlink: "../e"}, 225 {path: "c/c.go", symlink: "package c"}, 226 {path: "b/b.go", content: "package b"}, 227 {path: "b/d/d.go", content: "package d"}, 228 {path: "e/loop", symlink: "loop2"}, // symlink loop 229 {path: "e/loop2", symlink: "loop"}, 230 } 231 dir, err := createFiles(files) 232 if err != nil { 233 t.Fatalf("createFiles() failed with %v; want success", err) 234 } 235 c, cexts := testConfig(filepath.Join(dir, "root")) 236 var rels []string 237 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 238 rels = append(rels, rel) 239 }) 240 want := []string{"b/d", "b", "e", ""} 241 if !reflect.DeepEqual(rels, want) { 242 t.Errorf("got %#v; want %#v", rels, want) 243 } 244 } 245 246 func TestSymlinksIgnore(t *testing.T) { 247 files := []fileSpec{ 248 { 249 path: "root/BUILD", 250 content: "# gazelle:exclude b", 251 }, 252 {path: "root/b", symlink: "../b"}, 253 {path: "b/b.go", content: "package b"}, 254 } 255 dir, err := createFiles(files) 256 if err != nil { 257 t.Fatalf("createFiles() failed with %v; want success", err) 258 } 259 c, cexts := testConfig(filepath.Join(dir, "root")) 260 var rels []string 261 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 262 rels = append(rels, rel) 263 }) 264 want := []string{""} 265 if !reflect.DeepEqual(rels, want) { 266 t.Errorf("got %#v; want %#v", rels, want) 267 } 268 } 269 270 func TestSymlinksMixIgnoredAndNonIgnored(t *testing.T) { 271 files := []fileSpec{ 272 { 273 path: "root/BUILD", 274 content: "# gazelle:exclude b", 275 }, 276 {path: "root/b", symlink: "../b"}, // ignored 277 {path: "root/b2", symlink: "../b"}, // not ignored 278 {path: "b/b.go", content: "package b"}, 279 } 280 dir, err := createFiles(files) 281 if err != nil { 282 t.Fatalf("createFiles() failed with %v; want success", err) 283 } 284 c, cexts := testConfig(filepath.Join(dir, "root")) 285 var rels []string 286 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 287 rels = append(rels, rel) 288 }) 289 want := []string{"b2", ""} 290 if !reflect.DeepEqual(rels, want) { 291 t.Errorf("got %#v; want %#v", rels, want) 292 } 293 } 294 295 func TestSymlinksChained(t *testing.T) { 296 files := []fileSpec{ 297 {path: "root/b", symlink: "../link0"}, 298 {path: "link0", symlink: "b"}, 299 {path: "root/b2", symlink: "../b"}, 300 {path: "b/b.go", content: "package b"}, 301 } 302 dir, err := createFiles(files) 303 if err != nil { 304 t.Fatalf("createFiles() failed with %v; want success", err) 305 } 306 c, cexts := testConfig(filepath.Join(dir, "root")) 307 var rels []string 308 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 309 rels = append(rels, rel) 310 }) 311 want := []string{"b", ""} 312 if !reflect.DeepEqual(rels, want) { 313 t.Errorf("got %#v; want %#v", rels, want) 314 } 315 } 316 317 func TestSymlinksDangling(t *testing.T) { 318 files := []fileSpec{ 319 {path: "root/b", symlink: "../b"}, 320 } 321 dir, err := createFiles(files) 322 if err != nil { 323 t.Fatalf("createFiles() failed with %v; want success", err) 324 } 325 c, cexts := testConfig(filepath.Join(dir, "root")) 326 var rels []string 327 Walk(c, cexts, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 328 rels = append(rels, rel) 329 }) 330 want := []string{""} 331 if !reflect.DeepEqual(rels, want) { 332 t.Errorf("got %#v; want %#v", rels, want) 333 } 334 } 335 336 type fileSpec struct { 337 path, content, symlink string 338 } 339 340 func createFiles(files []fileSpec) (string, error) { 341 dir, err := ioutil.TempDir(os.Getenv("TEST_TMPDIR"), "walk_test") 342 if err != nil { 343 return "", err 344 } 345 for _, f := range files { 346 path := filepath.Join(dir, f.path) 347 if strings.HasSuffix(f.path, "/") { 348 if err := os.MkdirAll(path, 0700); err != nil { 349 return dir, err 350 } 351 continue 352 } 353 if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { 354 return "", err 355 } 356 if f.symlink != "" { 357 if err := os.Symlink(f.symlink, path); err != nil { 358 return "", err 359 } 360 continue 361 } 362 if err := ioutil.WriteFile(path, []byte(f.content), 0600); err != nil { 363 return "", err 364 } 365 } 366 return dir, nil 367 } 368 369 func testConfig(repoRoot string) (*config.Config, []config.Configurer) { 370 c := config.New() 371 c.RepoRoot = repoRoot 372 cexts := []config.Configurer{&config.CommonConfigurer{}} 373 return c, cexts 374 } 375 376 type testConfigurer struct { 377 configure func(c *config.Config, rel string, f *rule.File) 378 } 379 380 func (_ *testConfigurer) RegisterFlags(_ *flag.FlagSet, _ string, _ *config.Config) {} 381 382 func (_ *testConfigurer) CheckFlags(_ *flag.FlagSet, _ *config.Config) error { return nil } 383 384 func (_ *testConfigurer) KnownDirectives() []string { return nil } 385 386 func (tc *testConfigurer) Configure(c *config.Config, rel string, f *rule.File) { 387 tc.configure(c, rel, f) 388 }