github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/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 "path" 21 "path/filepath" 22 "testing" 23 24 "github.com/bazelbuild/bazel-gazelle/config" 25 "github.com/bazelbuild/bazel-gazelle/rule" 26 "github.com/bazelbuild/bazel-gazelle/testtools" 27 "github.com/google/go-cmp/cmp" 28 ) 29 30 func TestConfigureCallbackOrder(t *testing.T) { 31 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{{Path: "a/b/"}}) 32 defer cleanup() 33 34 var configureRels, callbackRels []string 35 c, cexts := testConfig(t, dir) 36 cexts = append(cexts, &testConfigurer{func(_ *config.Config, rel string, _ *rule.File) { 37 configureRels = append(configureRels, rel) 38 }}) 39 Walk(c, cexts, []string{dir}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, _, _ []string) { 40 callbackRels = append(callbackRels, rel) 41 }) 42 configureWant := []string{"", "a", "a/b"} 43 if diff := cmp.Diff(configureWant, configureRels); diff != "" { 44 t.Errorf("configure order (-want +got):\n%s", diff) 45 } 46 callbackWant := []string{"a/b", "a", ""} 47 if diff := cmp.Diff(callbackWant, callbackRels); diff != "" { 48 t.Errorf("callback order (-want +got):\n%s", diff) 49 } 50 } 51 52 func TestUpdateDirs(t *testing.T) { 53 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ 54 {Path: "update/sub/"}, 55 {Path: "update/sub/sub/"}, 56 { 57 Path: "update/ignore/BUILD.bazel", 58 Content: "# gazelle:ignore", 59 }, 60 {Path: "update/ignore/sub/"}, 61 { 62 Path: "update/error/BUILD.bazel", 63 Content: "(", 64 }, 65 {Path: "update/error/sub/"}, 66 }) 67 defer cleanup() 68 69 type visitSpec struct { 70 Rel string 71 Update bool 72 } 73 for _, tc := range []struct { 74 desc string 75 rels []string 76 mode Mode 77 want []visitSpec 78 }{ 79 { 80 desc: "visit_all_update_subdirs", 81 rels: []string{"update"}, 82 mode: VisitAllUpdateSubdirsMode, 83 want: []visitSpec{ 84 {"update/error/sub", true}, 85 {"update/error", false}, 86 {"update/ignore/sub", true}, 87 {"update/ignore", false}, 88 {"update/sub/sub", true}, 89 {"update/sub", true}, 90 {"update", true}, 91 {"", false}, 92 }, 93 }, { 94 desc: "visit_all_update_dirs", 95 rels: []string{"update", "update/ignore/sub"}, 96 mode: VisitAllUpdateDirsMode, 97 want: []visitSpec{ 98 {"update/error/sub", false}, 99 {"update/error", false}, 100 {"update/ignore/sub", true}, 101 {"update/ignore", false}, 102 {"update/sub/sub", false}, 103 {"update/sub", false}, 104 {"update", true}, 105 {"", false}, 106 }, 107 }, { 108 desc: "update_dirs", 109 rels: []string{"update", "update/ignore/sub"}, 110 mode: UpdateDirsMode, 111 want: []visitSpec{ 112 {"update/ignore/sub", true}, 113 {"update", true}, 114 }, 115 }, { 116 desc: "update_subdirs", 117 rels: []string{"update/ignore", "update/sub"}, 118 mode: UpdateSubdirsMode, 119 want: []visitSpec{ 120 {"update/ignore/sub", true}, 121 {"update/ignore", false}, 122 {"update/sub/sub", true}, 123 {"update/sub", true}, 124 }, 125 }, 126 } { 127 t.Run(tc.desc, func(t *testing.T) { 128 c, cexts := testConfig(t, dir) 129 dirs := make([]string, len(tc.rels)) 130 for i, rel := range tc.rels { 131 dirs[i] = filepath.Join(dir, filepath.FromSlash(rel)) 132 } 133 var visits []visitSpec 134 Walk(c, cexts, dirs, tc.mode, func(_ string, rel string, _ *config.Config, update bool, _ *rule.File, _, _, _ []string) { 135 visits = append(visits, visitSpec{rel, update}) 136 }) 137 if diff := cmp.Diff(tc.want, visits); diff != "" { 138 t.Errorf("Walk visits (-want +got):\n%s", diff) 139 } 140 }) 141 } 142 } 143 144 func TestCustomBuildName(t *testing.T) { 145 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ 146 { 147 Path: "BUILD.bazel", 148 Content: "# gazelle:build_file_name BUILD.test", 149 }, { 150 Path: "BUILD", 151 }, { 152 Path: "sub/BUILD.test", 153 }, { 154 Path: "sub/BUILD.bazel", 155 }, 156 }) 157 defer cleanup() 158 159 c, cexts := testConfig(t, dir) 160 var rels []string 161 Walk(c, cexts, []string{dir}, VisitAllUpdateSubdirsMode, func(_ string, _ string, _ *config.Config, _ bool, f *rule.File, _, _, _ []string) { 162 rel, err := filepath.Rel(c.RepoRoot, f.Path) 163 if err != nil { 164 t.Error(err) 165 } else { 166 rels = append(rels, filepath.ToSlash(rel)) 167 } 168 }) 169 want := []string{ 170 "sub/BUILD.test", 171 "BUILD.bazel", 172 } 173 if diff := cmp.Diff(want, rels); diff != "" { 174 t.Errorf("Walk relative paths (-want +got):\n%s", diff) 175 } 176 } 177 178 func TestExcludeFiles(t *testing.T) { 179 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ 180 { 181 Path: "BUILD.bazel", 182 Content: ` 183 # gazelle:exclude **/*.pb.go 184 # gazelle:exclude *.gen.go 185 # gazelle:exclude a.go 186 # gazelle:exclude c/**/b 187 # gazelle:exclude gen 188 # gazelle:exclude ign 189 # gazelle:exclude sub/b.go 190 191 gen( 192 name = "x", 193 out = "gen", 194 )`, 195 }, 196 { 197 Path: ".bazelignore", 198 Content: ` 199 dir 200 dir2/a/b 201 dir3/ 202 203 # Globs are not allowed in .bazelignore so this will not be ignored 204 foo/* 205 206 # Random comment followed by a line 207 a.file 208 `, 209 }, 210 {Path: ".dot"}, // not ignored 211 {Path: "_blank"}, // not ignored 212 {Path: "a/a.proto"}, // not ignored 213 {Path: "a/b.gen.go"}, // not ignored 214 {Path: "dir2/a/c"}, // not ignored 215 {Path: "foo/a/c"}, // not ignored 216 217 {Path: "a.gen.go"}, // ignored by '*.gen.go' 218 {Path: "a.go"}, // ignored by 'a.go' 219 {Path: "a.pb.go"}, // ignored by '**/*.pb.go' 220 {Path: "a/a.pb.go"}, // ignored by '**/*.pb.go' 221 {Path: "a/b/a.pb.go"}, // ignored by '**/*.pb.go' 222 {Path: "c/x/b/foo"}, // ignored by 'c/**/b' 223 {Path: "c/x/y/b/bar"}, // ignored by 'c/**/b' 224 {Path: "c/x/y/b/foo/bar"}, // ignored by 'c/**/b' 225 {Path: "ign/bad"}, // ignored by 'ign' 226 {Path: "sub/b.go"}, // ignored by 'sub/b.go' 227 {Path: "dir/contents"}, // ignored by .bazelignore 'dir' 228 {Path: "dir2/a/b"}, // ignored by .bazelignore 'dir2/a/b' 229 {Path: "dir3/g/h"}, // ignored by .bazelignore 'dir3/' 230 {Path: "a.file"}, // ignored by .bazelignore 'a.file' 231 }) 232 defer cleanup() 233 234 c, cexts := testConfig(t, dir) 235 var files []string 236 Walk(c, cexts, []string{dir}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, regularFiles, genFiles []string) { 237 for _, f := range regularFiles { 238 files = append(files, path.Join(rel, f)) 239 } 240 for _, f := range genFiles { 241 files = append(files, path.Join(rel, f)) 242 } 243 }) 244 want := []string{"a/a.proto", "a/b.gen.go", "dir2/a/c", "foo/a/c", ".bazelignore", ".dot", "BUILD.bazel", "_blank"} 245 if diff := cmp.Diff(want, files); diff != "" { 246 t.Errorf("Walk files (-want +got):\n%s", diff) 247 } 248 } 249 250 func TestExcludeSelf(t *testing.T) { 251 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ 252 { 253 Path: "BUILD.bazel", 254 }, { 255 Path: "sub/BUILD.bazel", 256 Content: "# gazelle:exclude .", 257 }, { 258 Path: "sub/below/BUILD.bazel", 259 }, 260 }) 261 defer cleanup() 262 263 c, cexts := testConfig(t, dir) 264 var rels []string 265 Walk(c, cexts, []string{dir}, VisitAllUpdateDirsMode, func(_ string, rel string, _ *config.Config, _ bool, f *rule.File, _, _, _ []string) { 266 rels = append(rels, rel) 267 }) 268 269 want := []string{""} 270 if diff := cmp.Diff(want, rels); diff != "" { 271 t.Errorf("Walk relative paths (-want +got):\n%s", diff) 272 } 273 } 274 275 func TestGeneratedFiles(t *testing.T) { 276 dir, cleanup := testtools.CreateFiles(t, []testtools.FileSpec{ 277 { 278 Path: "BUILD.bazel", 279 Content: ` 280 unknown_rule( 281 name = "blah1", 282 out = "gen1", 283 ) 284 285 unknown_rule( 286 name = "blah2", 287 outs = [ 288 "gen2", 289 "gen-and-static", 290 ], 291 ) 292 `, 293 }, 294 {Path: "gen-and-static"}, 295 {Path: "static"}, 296 }) 297 defer cleanup() 298 299 c, cexts := testConfig(t, dir) 300 var regularFiles, genFiles []string 301 Walk(c, cexts, []string{dir}, VisitAllUpdateSubdirsMode, func(_ string, rel string, _ *config.Config, _ bool, _ *rule.File, _, reg, gen []string) { 302 for _, f := range reg { 303 regularFiles = append(regularFiles, path.Join(rel, f)) 304 } 305 for _, f := range gen { 306 genFiles = append(genFiles, path.Join(rel, f)) 307 } 308 }) 309 regWant := []string{"BUILD.bazel", "gen-and-static", "static"} 310 if diff := cmp.Diff(regWant, regularFiles); diff != "" { 311 t.Errorf("Walk regularFiles (-want +got):\n%s", diff) 312 } 313 genWant := []string{"gen1", "gen2", "gen-and-static"} 314 if diff := cmp.Diff(genWant, genFiles); diff != "" { 315 t.Errorf("Walk genFiles (-want +got):\n%s", diff) 316 } 317 } 318 319 func testConfig(t *testing.T, dir string) (*config.Config, []config.Configurer) { 320 args := []string{"-repo_root", dir} 321 cexts := []config.Configurer{&config.CommonConfigurer{}, &Configurer{}} 322 c := testtools.NewTestConfig(t, cexts, nil, args) 323 return c, cexts 324 } 325 326 type testConfigurer struct { 327 configure func(c *config.Config, rel string, f *rule.File) 328 } 329 330 func (*testConfigurer) RegisterFlags(_ *flag.FlagSet, _ string, _ *config.Config) {} 331 332 func (*testConfigurer) CheckFlags(_ *flag.FlagSet, _ *config.Config) error { return nil } 333 334 func (*testConfigurer) KnownDirectives() []string { return nil } 335 336 func (tc *testConfigurer) Configure(c *config.Config, rel string, f *rule.File) { 337 tc.configure(c, rel, f) 338 }