github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/cache/parse_test.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package cache
     6  
     7  import (
     8  	"bytes"
     9  	"go/ast"
    10  	"go/format"
    11  	"go/parser"
    12  	"go/token"
    13  	"go/types"
    14  	"reflect"
    15  	"sort"
    16  	"testing"
    17  
    18  	"github.com/powerman/golang-tools/go/packages"
    19  )
    20  
    21  func TestArrayLength(t *testing.T) {
    22  	tests := []struct {
    23  		expr   string
    24  		length int
    25  	}{
    26  		{`[...]int{0,1,2,3,4,5,6,7,8,9}`, 10},
    27  		{`[...]int{9:0}`, 10},
    28  		{`[...]int{19-10:0}`, 10},
    29  		{`[...]int{19-10:0, 17-10:0, 18-10:0}`, 10},
    30  	}
    31  
    32  	for _, tt := range tests {
    33  		expr, err := parser.ParseExpr(tt.expr)
    34  		if err != nil {
    35  			t.Fatal(err)
    36  		}
    37  		l, ok := arrayLength(expr.(*ast.CompositeLit))
    38  		if !ok {
    39  			t.Errorf("arrayLength did not recognize expression %#v", expr)
    40  		}
    41  		if l != tt.length {
    42  			t.Errorf("arrayLength(%#v) = %v, want %v", expr, l, tt.length)
    43  		}
    44  	}
    45  }
    46  
    47  func TestTrim(t *testing.T) {
    48  	tests := []struct {
    49  		name string
    50  		file string
    51  		kept []string
    52  	}{
    53  		{
    54  			name: "delete_unused",
    55  			file: `
    56  type x struct{}
    57  func y()
    58  var z int
    59  `,
    60  			kept: []string{},
    61  		},
    62  		{
    63  			// From the common type in testing.
    64  			name: "unexported_embedded",
    65  			file: `
    66  type x struct {}
    67  type Exported struct { x }
    68  `,
    69  			kept: []string{"Exported", "x"},
    70  		},
    71  		{
    72  			// From the d type in unicode.
    73  			name: "exported_field_unexported_type",
    74  			file: `
    75  type x struct {}
    76  type Exported struct {
    77  	X x
    78  }
    79  `,
    80  			kept: []string{"Exported", "x"},
    81  		},
    82  		{
    83  			// From errNotExist in io/fs.
    84  			name: "exported_var_function_call",
    85  			file: `
    86  func x() int { return 0 }
    87  var Exported = x()
    88  `,
    89  			kept: []string{"Exported", "x"},
    90  		},
    91  		{
    92  			// From DefaultServeMux in net/http.
    93  			name: "exported_pointer_to_unexported_var",
    94  			file: `
    95  var Exported = &x
    96  var x int
    97  `,
    98  			kept: []string{"Exported", "x"},
    99  		},
   100  		{
   101  			// From DefaultWriter in goldmark/renderer/html.
   102  			name: "exported_pointer_to_composite_lit",
   103  			file: `
   104  var Exported = &x{}
   105  type x struct{}
   106  `,
   107  			kept: []string{"Exported", "x"},
   108  		},
   109  		{
   110  			// From SelectDir in reflect.
   111  			name: "leave_constants",
   112  			file: `
   113  type Enum int
   114  const (
   115  	_             Enum = iota
   116  	EnumOne
   117  )
   118  `,
   119  			kept: []string{"Enum", "EnumOne"},
   120  		},
   121  		{
   122  			name: "constant_conversion",
   123  			file: `
   124  type x int
   125  const (
   126  	foo x = 0
   127  )
   128  `,
   129  			kept: []string{"x", "foo"},
   130  		},
   131  		{
   132  			name: "unexported_return",
   133  			file: `
   134  type x int
   135  func Exported() x {}
   136  type y int
   137  type Interface interface {
   138  	Exported() y
   139  }
   140  `,
   141  			kept: []string{"Exported", "Interface", "x", "y"},
   142  		},
   143  		{
   144  			name: "drop_composite_literals",
   145  			file: `
   146  type x int
   147  type Exported struct {
   148  	foo x
   149  }
   150  var Var = Exported{foo:1}
   151  `,
   152  			kept: []string{"Exported", "Var"},
   153  		},
   154  		{
   155  			name: "drop_function_literals",
   156  			file: `
   157  type x int
   158  var Exported = func() { return x(0) }
   159  `,
   160  			kept: []string{"Exported"},
   161  		},
   162  		{
   163  			name: "missing_receiver_panic",
   164  			file: `
   165  			func() foo() {}
   166  `,
   167  			kept: []string{},
   168  		},
   169  	}
   170  
   171  	for _, tt := range tests {
   172  		t.Run(tt.name, func(t *testing.T) {
   173  			fset := token.NewFileSet()
   174  			file, err := parser.ParseFile(fset, "main.go", "package main\n\n"+tt.file, parser.AllErrors)
   175  			if err != nil {
   176  				t.Fatal(err)
   177  			}
   178  			filter := &unexportedFilter{uses: map[string]bool{}}
   179  			filter.Filter([]*ast.File{file})
   180  			pkg := types.NewPackage("main", "main")
   181  			checker := types.NewChecker(&types.Config{
   182  				DisableUnusedImportCheck: true,
   183  			}, fset, pkg, nil)
   184  			if err := checker.Files([]*ast.File{file}); err != nil {
   185  				t.Error(err)
   186  			}
   187  			names := pkg.Scope().Names()
   188  			sort.Strings(names)
   189  			sort.Strings(tt.kept)
   190  			if !reflect.DeepEqual(names, tt.kept) {
   191  				t.Errorf("package contains names %v, wanted %v", names, tt.kept)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  func TestPkg(t *testing.T) {
   198  	t.Skip("for manual debugging")
   199  	fset := token.NewFileSet()
   200  	pkgs, err := packages.Load(&packages.Config{
   201  		Mode: packages.NeedSyntax | packages.NeedFiles,
   202  		Fset: fset,
   203  	}, "io")
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  	if len(pkgs[0].Errors) != 0 {
   208  		t.Fatal(pkgs[0].Errors)
   209  	}
   210  	filter := &unexportedFilter{uses: map[string]bool{}}
   211  	filter.Filter(pkgs[0].Syntax)
   212  	for _, file := range pkgs[0].Syntax {
   213  		buf := &bytes.Buffer{}
   214  		format.Node(buf, fset, file)
   215  		t.Log(buf.String())
   216  	}
   217  }