github.com/wedaly/gospelunk@v0.0.0-20240506220214-89e2d4a79789/pkg/list/list_test.go (about)

     1  package list
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/wedaly/gospelunk/pkg/file"
    12  )
    13  
    14  func TestList(t *testing.T) {
    15  	pkg := Package{
    16  		Name: "testmodule001",
    17  		ID:   "github.com/wedaly/gospelunk/pkg/list/testdata/testmodule001",
    18  	}
    19  
    20  	testPkg := Package{
    21  		Name: "testmodule001",
    22  		ID:   "github.com/wedaly/gospelunk/pkg/list/testdata/testmodule001 [github.com/wedaly/gospelunk/pkg/list/testdata/testmodule001.test]",
    23  	}
    24  
    25  	pkgPath := func(p string) string {
    26  		path := filepath.Join("testdata", "testmodule001", p)
    27  		absPath, err := filepath.Abs(path)
    28  		require.NoError(t, err)
    29  		return absPath
    30  	}
    31  
    32  	testCases := []struct {
    33  		name     string
    34  		dir      string
    35  		patterns []string
    36  		opts     Options
    37  		expected Result
    38  	}{
    39  		{
    40  			name:     "public only",
    41  			dir:      "testdata/testmodule001",
    42  			patterns: []string{"./..."},
    43  			opts:     Options{},
    44  			expected: Result{
    45  				Defs: []Definition{
    46  					{Name: "MyVar", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 3, Column: 5}},
    47  					{Name: "MyConst", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 5, Column: 7}},
    48  					{Name: "MyStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 7, Column: 6}},
    49  					{Name: "MyInterface", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 17, Column: 6}},
    50  					{Name: "MyFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 21, Column: 1}},
    51  				},
    52  			},
    53  		},
    54  		{
    55  			name:     "include struct fields",
    56  			dir:      "testdata/testmodule001",
    57  			patterns: []string{"./..."},
    58  			opts:     Options{IncludeStructFields: true},
    59  			expected: Result{
    60  				Defs: []Definition{
    61  					{Name: "MyVar", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 3, Column: 5}},
    62  					{Name: "MyConst", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 5, Column: 7}},
    63  					{Name: "MyStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 7, Column: 6}},
    64  					{Name: "MyStruct.MyField", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 8, Column: 2}},
    65  					{Name: "MyInterface", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 17, Column: 6}},
    66  					{Name: "MyFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 21, Column: 1}},
    67  				},
    68  			},
    69  		},
    70  		{
    71  			name:     "include interface methods",
    72  			dir:      "testdata/testmodule001",
    73  			patterns: []string{"./..."},
    74  			opts:     Options{IncludeInterfaceMethods: true},
    75  			expected: Result{
    76  				Defs: []Definition{
    77  					{Name: "MyVar", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 3, Column: 5}},
    78  					{Name: "MyConst", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 5, Column: 7}},
    79  					{Name: "MyStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 7, Column: 6}},
    80  					{Name: "MyInterface", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 17, Column: 6}},
    81  					{Name: "MyInterface.String", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 18, Column: 2}},
    82  					{Name: "MyFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 21, Column: 1}},
    83  				},
    84  			},
    85  		},
    86  		{
    87  			name:     "include private",
    88  			dir:      "testdata/testmodule001",
    89  			patterns: []string{"./..."},
    90  			opts:     Options{IncludePrivate: true, IncludeStructFields: true},
    91  			expected: Result{
    92  				Defs: []Definition{
    93  					{Name: "MyVar", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 3, Column: 5}},
    94  					{Name: "MyConst", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 5, Column: 7}},
    95  					{Name: "MyStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 7, Column: 6}},
    96  					{Name: "MyStruct.MyField", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 8, Column: 2}},
    97  					{Name: "MyStruct.privateField", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 9, Column: 2}},
    98  					{Name: "privateStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 12, Column: 6}},
    99  					{Name: "privateStruct.PublicField", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 13, Column: 2}},
   100  					{Name: "privateStruct.privateField", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 14, Column: 2}},
   101  					{Name: "MyInterface", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 17, Column: 6}},
   102  					{Name: "MyFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 21, Column: 1}},
   103  					{Name: "privateFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 25, Column: 1}},
   104  				},
   105  			},
   106  		},
   107  		{
   108  			name:     "include tests",
   109  			dir:      "testdata/testmodule001",
   110  			patterns: []string{"./..."},
   111  			opts:     Options{IncludeTests: true},
   112  			expected: Result{
   113  				Defs: []Definition{
   114  					{Name: "MyVar", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 3, Column: 5}},
   115  					{Name: "MyConst", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 5, Column: 7}},
   116  					{Name: "MyStruct", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 7, Column: 6}},
   117  					{Name: "MyInterface", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 17, Column: 6}},
   118  					{Name: "MyFunc", Pkg: pkg, Loc: file.Loc{Path: pkgPath("defs.go"), Line: 21, Column: 1}},
   119  					{Name: "TestStruct", Pkg: testPkg, Loc: file.Loc{Path: pkgPath("defs_test.go"), Line: 3, Column: 6}},
   120  				},
   121  			},
   122  		},
   123  	}
   124  
   125  	for _, tc := range testCases {
   126  		t.Run(tc.name, func(t *testing.T) {
   127  			withWorkingDir(t, tc.dir, func(t *testing.T) {
   128  				result, err := List(tc.patterns, tc.opts)
   129  				require.NoError(t, err)
   130  				assert.Equal(t, tc.expected, result)
   131  			})
   132  		})
   133  	}
   134  }
   135  
   136  func TestListWithCGo(t *testing.T) {
   137  	cgoRelPath := filepath.Join("testdata", "testmodule002", "cgo.go")
   138  	cgoPath, err := filepath.Abs(cgoRelPath)
   139  	require.NoError(t, err)
   140  
   141  	withWorkingDir(t, "testdata/testmodule002", func(t *testing.T) {
   142  		result, err := List([]string{"."}, Options{})
   143  		require.NoError(t, err)
   144  
   145  		expected := Result{
   146  			Defs: []Definition{
   147  				{
   148  					Loc:  file.Loc{Path: cgoPath, Line: 6, Column: 6},
   149  					Name: "MyStruct",
   150  					Pkg: Package{
   151  						Name: "testmodule002",
   152  						ID:   "github.com/wedaly/gospelunk/pkg/list/testdata/testmodule002",
   153  					},
   154  				},
   155  				{
   156  					Loc:  file.Loc{Path: cgoPath, Line: 8, Column: 1},
   157  					Name: "Random",
   158  					Pkg: Package{
   159  						Name: "testmodule002",
   160  						ID:   "github.com/wedaly/gospelunk/pkg/list/testdata/testmodule002",
   161  					},
   162  				},
   163  			},
   164  		}
   165  		assert.Equal(t, expected, result)
   166  	})
   167  }
   168  
   169  func TestListWithImports(t *testing.T) {
   170  	withWorkingDir(t, "testdata/testmodule003", func(t *testing.T) {
   171  		result, err := List([]string{"."}, Options{OnlyImports: true})
   172  		require.NoError(t, err)
   173  
   174  		// Exact definitions may vary based on Go stdlib, so check that imported packages are included.
   175  		defPkgs := make(map[string][]string)
   176  		for _, def := range result.Defs {
   177  			defPkgs[def.Pkg.ID] = append(defPkgs[def.Pkg.ID], def.Name)
   178  		}
   179  		assert.Equal(t, 2, len(defPkgs))
   180  		assert.Equal(t, []string{"SubFunc"}, defPkgs["github.com/wedaly/gospelunk/pkg/list/testdata/testmodule003/subpkg"])
   181  		assert.Greater(t, len(defPkgs["fmt"]), 1)
   182  	})
   183  }
   184  
   185  func TestListFileOutsideGoModule(t *testing.T) {
   186  	withWorkingDir(t, "testdata", func(t *testing.T) {
   187  		result, err := List([]string{"file=testmodule004/first.go"}, Options{})
   188  		require.NoError(t, err)
   189  
   190  		// Expect definitions from both files in the package.
   191  		var defNames []string
   192  		for _, def := range result.Defs {
   193  			defNames = append(defNames, def.Name)
   194  		}
   195  		expected := []string{"FirstFunc", "SecondFunc"}
   196  		assert.Equal(t, expected, defNames)
   197  	})
   198  }
   199  
   200  func withWorkingDir(t *testing.T, dir string, f func(t *testing.T)) {
   201  	oldWd, err := os.Getwd()
   202  	require.NoError(t, err)
   203  	defer os.Chdir(oldWd)
   204  	err = os.Chdir(dir)
   205  	require.NoError(t, err)
   206  	f(t)
   207  }