...
Run Format

Source file src/go/internal/srcimporter/srcimporter_test.go

Documentation: go/internal/srcimporter

     1  // Copyright 2017 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 srcimporter
     6  
     7  import (
     8  	"go/build"
     9  	"go/token"
    10  	"go/types"
    11  	"internal/testenv"
    12  	"io/ioutil"
    13  	"path/filepath"
    14  	"runtime"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  const maxTime = 2 * time.Second
    21  
    22  var importer = New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
    23  
    24  func doImport(t *testing.T, path, srcDir string) {
    25  	t0 := time.Now()
    26  	if _, err := importer.ImportFrom(path, srcDir, 0); err != nil {
    27  		// don't report an error if there's no buildable Go files
    28  		if _, nogo := err.(*build.NoGoError); !nogo {
    29  			t.Errorf("import %q failed (%v)", path, err)
    30  		}
    31  		return
    32  	}
    33  	t.Logf("import %q: %v", path, time.Since(t0))
    34  }
    35  
    36  // walkDir imports the all the packages with the given path
    37  // prefix recursively. It returns the number of packages
    38  // imported and whether importing was aborted because time
    39  // has passed endTime.
    40  func walkDir(t *testing.T, path string, endTime time.Time) (int, bool) {
    41  	if time.Now().After(endTime) {
    42  		t.Log("testing time used up")
    43  		return 0, true
    44  	}
    45  
    46  	// ignore fake packages and testdata directories
    47  	if path == "builtin" || path == "unsafe" || strings.HasSuffix(path, "testdata") {
    48  		return 0, false
    49  	}
    50  
    51  	list, err := ioutil.ReadDir(filepath.Join(runtime.GOROOT(), "src", path))
    52  	if err != nil {
    53  		t.Fatalf("walkDir %s failed (%v)", path, err)
    54  	}
    55  
    56  	nimports := 0
    57  	hasGoFiles := false
    58  	for _, f := range list {
    59  		if f.IsDir() {
    60  			n, abort := walkDir(t, filepath.Join(path, f.Name()), endTime)
    61  			nimports += n
    62  			if abort {
    63  				return nimports, true
    64  			}
    65  		} else if strings.HasSuffix(f.Name(), ".go") {
    66  			hasGoFiles = true
    67  		}
    68  	}
    69  
    70  	if hasGoFiles {
    71  		doImport(t, path, "")
    72  		nimports++
    73  	}
    74  
    75  	return nimports, false
    76  }
    77  
    78  func TestImportStdLib(t *testing.T) {
    79  	if !testenv.HasSrc() {
    80  		t.Skip("no source code available")
    81  	}
    82  
    83  	dt := maxTime
    84  	if testing.Short() && testenv.Builder() == "" {
    85  		dt = 500 * time.Millisecond
    86  	}
    87  	nimports, _ := walkDir(t, "", time.Now().Add(dt)) // installed packages
    88  	t.Logf("tested %d imports", nimports)
    89  }
    90  
    91  var importedObjectTests = []struct {
    92  	name string
    93  	want string
    94  }{
    95  	{"flag.Bool", "func Bool(name string, value bool, usage string) *bool"},
    96  	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
    97  	{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"}, // go/types.gcCompatibilityMode is off => interface not flattened
    98  	{"math.Pi", "const Pi untyped float"},
    99  	{"math.Sin", "func Sin(x float64) float64"},
   100  	{"math/big.Int", "type Int struct{neg bool; abs nat}"},
   101  	{"golang_org/x/text/unicode/norm.MaxSegmentSize", "const MaxSegmentSize untyped int"},
   102  }
   103  
   104  func TestImportedTypes(t *testing.T) {
   105  	if !testenv.HasSrc() {
   106  		t.Skip("no source code available")
   107  	}
   108  
   109  	for _, test := range importedObjectTests {
   110  		s := strings.Split(test.name, ".")
   111  		if len(s) != 2 {
   112  			t.Fatal("invalid test data format")
   113  		}
   114  		importPath := s[0]
   115  		objName := s[1]
   116  
   117  		pkg, err := importer.ImportFrom(importPath, ".", 0)
   118  		if err != nil {
   119  			t.Error(err)
   120  			continue
   121  		}
   122  
   123  		obj := pkg.Scope().Lookup(objName)
   124  		if obj == nil {
   125  			t.Errorf("%s: object not found", test.name)
   126  			continue
   127  		}
   128  
   129  		got := types.ObjectString(obj, types.RelativeTo(pkg))
   130  		if got != test.want {
   131  			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
   132  		}
   133  	}
   134  }
   135  
   136  func TestReimport(t *testing.T) {
   137  	if !testenv.HasSrc() {
   138  		t.Skip("no source code available")
   139  	}
   140  
   141  	// Reimporting a partially imported (incomplete) package is not supported (see issue #19337).
   142  	// Make sure we recognize the situation and report an error.
   143  
   144  	mathPkg := types.NewPackage("math", "math") // incomplete package
   145  	importer := New(&build.Default, token.NewFileSet(), map[string]*types.Package{mathPkg.Path(): mathPkg})
   146  	_, err := importer.ImportFrom("math", ".", 0)
   147  	if err == nil || !strings.HasPrefix(err.Error(), "reimport") {
   148  		t.Errorf("got %v; want reimport error", err)
   149  	}
   150  }
   151  
   152  func TestIssue20855(t *testing.T) {
   153  	if !testenv.HasSrc() {
   154  		t.Skip("no source code available")
   155  	}
   156  
   157  	pkg, err := importer.ImportFrom("go/internal/srcimporter/testdata/issue20855", ".", 0)
   158  	if err == nil || !strings.Contains(err.Error(), "missing function body") {
   159  		t.Fatalf("got unexpected or no error: %v", err)
   160  	}
   161  	if pkg == nil {
   162  		t.Error("got no package despite no hard errors")
   163  	}
   164  }
   165  

View as plain text