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  }