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  }