github.com/shulhan/golangci-lint@v1.10.1/pkg/packages/resolver_test.go (about)

     1  package packages_test
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/golangci/golangci-lint/pkg/fsutils"
    12  	"github.com/golangci/golangci-lint/pkg/logutils"
    13  	"github.com/golangci/golangci-lint/pkg/packages"
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  type fsPreparer struct {
    18  	t      *testing.T
    19  	root   string
    20  	prevWD string
    21  }
    22  
    23  func (fp fsPreparer) clean() {
    24  	err := os.Chdir(fp.prevWD)
    25  	assert.NoError(fp.t, err)
    26  
    27  	err = os.RemoveAll(fp.root)
    28  	assert.NoError(fp.t, err)
    29  }
    30  
    31  func prepareFS(t *testing.T, paths ...string) *fsPreparer {
    32  	root, err := ioutil.TempDir("/tmp", "golangci.test.path_resolver")
    33  	assert.NoError(t, err)
    34  
    35  	prevWD, err := fsutils.Getwd()
    36  	assert.NoError(t, err)
    37  
    38  	err = os.Chdir(root)
    39  	assert.NoError(t, err)
    40  
    41  	for _, p := range paths {
    42  		err = os.MkdirAll(filepath.Dir(p), os.ModePerm)
    43  		assert.NoError(t, err)
    44  
    45  		if strings.HasSuffix(p, "/") {
    46  			continue
    47  		}
    48  
    49  		goFile := "package p\n"
    50  		err = ioutil.WriteFile(p, []byte(goFile), os.ModePerm)
    51  		assert.NoError(t, err)
    52  	}
    53  
    54  	return &fsPreparer{
    55  		root:   root,
    56  		t:      t,
    57  		prevWD: prevWD,
    58  	}
    59  }
    60  
    61  func newTestResolver(t *testing.T, excludeDirs []string) *packages.Resolver {
    62  	r, err := packages.NewResolver(nil, excludeDirs, logutils.NewStderrLog(""))
    63  	assert.NoError(t, err)
    64  
    65  	return r
    66  }
    67  
    68  func TestPathResolverNotExistingPath(t *testing.T) {
    69  	fp := prepareFS(t)
    70  	defer fp.clean()
    71  
    72  	_, err := newTestResolver(t, nil).Resolve("a")
    73  	assert.EqualError(t, err, "can't eval symlinks for path a: lstat a: no such file or directory")
    74  }
    75  
    76  func TestPathResolverCommonCases(t *testing.T) {
    77  	type testCase struct {
    78  		name         string
    79  		prepare      []string
    80  		resolve      []string
    81  		expFiles     []string
    82  		expDirs      []string
    83  		includeTests bool
    84  	}
    85  
    86  	testCases := []testCase{
    87  		{
    88  			name:    "empty root recursively",
    89  			resolve: []string{"./..."},
    90  		},
    91  		{
    92  			name:    "empty root",
    93  			resolve: []string{"./"},
    94  		},
    95  		{
    96  			name:    "vendor is excluded recursively",
    97  			prepare: []string{"vendor/a/b.go"},
    98  			resolve: []string{"./..."},
    99  		},
   100  		{
   101  			name:    "vendor is excluded",
   102  			prepare: []string{"vendor/a.go"},
   103  			resolve: []string{"./..."},
   104  		},
   105  		{
   106  			name:    "nested vendor is excluded",
   107  			prepare: []string{"d/vendor/a.go"},
   108  			resolve: []string{"./..."},
   109  		},
   110  		{
   111  			name:     "vendor dir is excluded by regexp, not the exact match",
   112  			prepare:  []string{"vendors/a.go", "novendor/b.go"},
   113  			resolve:  []string{"./..."},
   114  			expDirs:  []string{"vendors"},
   115  			expFiles: []string{"vendors/a.go"},
   116  		},
   117  		{
   118  			name:     "vendor explicitly resolved",
   119  			prepare:  []string{"vendor/a.go"},
   120  			resolve:  []string{"./vendor"},
   121  			expDirs:  []string{"vendor"},
   122  			expFiles: []string{"vendor/a.go"},
   123  		},
   124  		{
   125  			name:     "nested vendor explicitly resolved",
   126  			prepare:  []string{"d/vendor/a.go"},
   127  			resolve:  []string{"d/vendor"},
   128  			expDirs:  []string{"d/vendor"},
   129  			expFiles: []string{"d/vendor/a.go"},
   130  		},
   131  		{
   132  			name:     "extensions filter recursively",
   133  			prepare:  []string{"a/b.go", "a/c.txt", "d.go", "e.csv"},
   134  			resolve:  []string{"./..."},
   135  			expDirs:  []string{".", "a"},
   136  			expFiles: []string{"a/b.go", "d.go"},
   137  		},
   138  		{
   139  			name:     "extensions filter",
   140  			prepare:  []string{"a/b.go", "a/c.txt", "d.go"},
   141  			resolve:  []string{"a"},
   142  			expDirs:  []string{"a"},
   143  			expFiles: []string{"a/b.go"},
   144  		},
   145  		{
   146  			name:     "one level dirs exclusion",
   147  			prepare:  []string{"a/b/d.go", "a/c.go"},
   148  			resolve:  []string{"./a"},
   149  			expDirs:  []string{"a"},
   150  			expFiles: []string{"a/c.go"},
   151  		},
   152  		{
   153  			name:     "explicitly resolved files",
   154  			prepare:  []string{"a/b/c.go", "a/d.txt"},
   155  			resolve:  []string{"./a/...", "a/d.txt"},
   156  			expDirs:  []string{"a/b"},
   157  			expFiles: []string{"a/b/c.go", "a/d.txt"},
   158  		},
   159  		{
   160  			name:    ".* dotfiles are always ignored",
   161  			prepare: []string{".git/a.go", ".circleci/b.go"},
   162  			resolve: []string{"./..."},
   163  		},
   164  		{
   165  			name:     "exclude dirs on any depth level",
   166  			prepare:  []string{"ok/.git/a.go", "ok/b.go"},
   167  			resolve:  []string{"./..."},
   168  			expDirs:  []string{"ok"},
   169  			expFiles: []string{"ok/b.go"},
   170  		},
   171  		{
   172  			name:     "exclude path, not name",
   173  			prepare:  []string{"ex/clude/me/a.go", "c/d.go"},
   174  			resolve:  []string{"./..."},
   175  			expDirs:  []string{"c"},
   176  			expFiles: []string{"c/d.go"},
   177  		},
   178  		{
   179  			name:     "exclude partial path",
   180  			prepare:  []string{"prefix/ex/clude/me/a.go", "prefix/ex/clude/me/subdir/c.go", "prefix/b.go"},
   181  			resolve:  []string{"./..."},
   182  			expDirs:  []string{"prefix"},
   183  			expFiles: []string{"prefix/b.go"},
   184  		},
   185  		{
   186  			name:     "don't exclude file instead of dir",
   187  			prepare:  []string{"a/exclude.go"},
   188  			resolve:  []string{"a"},
   189  			expDirs:  []string{"a"},
   190  			expFiles: []string{"a/exclude.go"},
   191  		},
   192  		{
   193  			name:    "don't exclude file instead of dir: check dir is excluded",
   194  			prepare: []string{"a/exclude.go/b.go"},
   195  			resolve: []string{"a/..."},
   196  		},
   197  		{
   198  			name:    "ignore _*",
   199  			prepare: []string{"_any/a.go"},
   200  			resolve: []string{"./..."},
   201  		},
   202  		{
   203  			name:         "include tests",
   204  			prepare:      []string{"a/b.go", "a/b_test.go"},
   205  			resolve:      []string{"./..."},
   206  			expDirs:      []string{"a"},
   207  			expFiles:     []string{"a/b.go", "a/b_test.go"},
   208  			includeTests: true,
   209  		},
   210  		{
   211  			name:     "exclude tests",
   212  			prepare:  []string{"a/b.go", "a/b_test.go"},
   213  			resolve:  []string{"./..."},
   214  			expDirs:  []string{"a"},
   215  			expFiles: []string{"a/b.go"},
   216  		},
   217  		{
   218  			name:     "exclude tests except explicitly set",
   219  			prepare:  []string{"a/b.go", "a/b_test.go", "a/c_test.go"},
   220  			resolve:  []string{"./...", "a/c_test.go"},
   221  			expDirs:  []string{"a"},
   222  			expFiles: []string{"a/b.go", "a/c_test.go"},
   223  		},
   224  		{
   225  			name:     "exclude dirs with no go files",
   226  			prepare:  []string{"a/b.txt", "a/c/d.go"},
   227  			resolve:  []string{"./..."},
   228  			expDirs:  []string{"a/c"},
   229  			expFiles: []string{"a/c/d.go"},
   230  		},
   231  		{
   232  			name:     "exclude dirs with no go files with root dir",
   233  			prepare:  []string{"a/b.txt", "a/c/d.go", "e.go"},
   234  			resolve:  []string{"./..."},
   235  			expDirs:  []string{".", "a/c"},
   236  			expFiles: []string{"a/c/d.go", "e.go"},
   237  		},
   238  		{
   239  			name:     "resolve absolute paths",
   240  			prepare:  []string{"a/b.go", "a/c.txt", "d.go", "e.csv"},
   241  			resolve:  []string{"${CWD}/..."},
   242  			expDirs:  []string{".", "a"},
   243  			expFiles: []string{"a/b.go", "d.go"},
   244  		},
   245  	}
   246  
   247  	fsutils.UseWdCache(false)
   248  	for _, tc := range testCases {
   249  		t.Run(tc.name, func(t *testing.T) {
   250  			fp := prepareFS(t, tc.prepare...)
   251  			defer fp.clean()
   252  
   253  			for i, rp := range tc.resolve {
   254  				tc.resolve[i] = strings.Replace(rp, "${CWD}", fp.root, -1)
   255  			}
   256  
   257  			r := newTestResolver(t, []string{"vendor$", "ex/clude/me", "exclude"})
   258  
   259  			prog, err := r.Resolve(tc.resolve...)
   260  			assert.NoError(t, err)
   261  			assert.NotNil(t, prog)
   262  
   263  			progFiles := prog.Files(tc.includeTests)
   264  			sort.StringSlice(progFiles).Sort()
   265  			sort.StringSlice(tc.expFiles).Sort()
   266  
   267  			progDirs := prog.Dirs()
   268  			sort.StringSlice(progDirs).Sort()
   269  			sort.StringSlice(tc.expDirs).Sort()
   270  
   271  			if tc.expFiles == nil {
   272  				assert.Empty(t, progFiles)
   273  			} else {
   274  				assert.Equal(t, tc.expFiles, progFiles, "files")
   275  			}
   276  
   277  			if tc.expDirs == nil {
   278  				assert.Empty(t, progDirs)
   279  			} else {
   280  				assert.Equal(t, tc.expDirs, progDirs, "dirs")
   281  			}
   282  		})
   283  	}
   284  }