github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/go/internal/gcimporter/gcimporter_test.go (about)

     1  // Copyright 2011 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 gcimporter
     6  
     7  import (
     8  	"fmt"
     9  	"internal/testenv"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"runtime"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"go/types"
    20  )
    21  
    22  // skipSpecialPlatforms causes the test to be skipped for platforms where
    23  // builders (build.golang.org) don't have access to compiled packages for
    24  // import.
    25  func skipSpecialPlatforms(t *testing.T) {
    26  	switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
    27  	case "nacl-amd64p32",
    28  		"nacl-386",
    29  		"nacl-arm",
    30  		"darwin-arm",
    31  		"darwin-arm64":
    32  		t.Skipf("no compiled packages available for import on %s", platform)
    33  	}
    34  }
    35  
    36  func compile(t *testing.T, dirname, filename string) string {
    37  	testenv.MustHaveGoBuild(t)
    38  	cmd := exec.Command("go", "tool", "compile", filename)
    39  	cmd.Dir = dirname
    40  	out, err := cmd.CombinedOutput()
    41  	if err != nil {
    42  		t.Logf("%s", out)
    43  		t.Fatalf("go tool compile %s failed: %s", filename, err)
    44  	}
    45  	// filename should end with ".go"
    46  	return filepath.Join(dirname, filename[:len(filename)-2]+"o")
    47  }
    48  
    49  // Use the same global imports map for all tests. The effect is
    50  // as if all tested packages were imported into a single package.
    51  var imports = make(map[string]*types.Package)
    52  
    53  func testPath(t *testing.T, path string) *types.Package {
    54  	t0 := time.Now()
    55  	pkg, err := Import(imports, path)
    56  	if err != nil {
    57  		t.Errorf("testPath(%s): %s", path, err)
    58  		return nil
    59  	}
    60  	t.Logf("testPath(%s): %v", path, time.Since(t0))
    61  	return pkg
    62  }
    63  
    64  const maxTime = 30 * time.Second
    65  
    66  func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
    67  	dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
    68  	list, err := ioutil.ReadDir(dirname)
    69  	if err != nil {
    70  		t.Fatalf("testDir(%s): %s", dirname, err)
    71  	}
    72  	for _, f := range list {
    73  		if time.Now().After(endTime) {
    74  			t.Log("testing time used up")
    75  			return
    76  		}
    77  		switch {
    78  		case !f.IsDir():
    79  			// try extensions
    80  			for _, ext := range pkgExts {
    81  				if strings.HasSuffix(f.Name(), ext) {
    82  					name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
    83  					if testPath(t, filepath.Join(dir, name)) != nil {
    84  						nimports++
    85  					}
    86  				}
    87  			}
    88  		case f.IsDir():
    89  			nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
    90  		}
    91  	}
    92  	return
    93  }
    94  
    95  func TestImport(t *testing.T) {
    96  	// This package only handles gc export data.
    97  	if runtime.Compiler != "gc" {
    98  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
    99  		return
   100  	}
   101  
   102  	if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
   103  		defer os.Remove(outFn)
   104  	}
   105  
   106  	nimports := 0
   107  	if pkg := testPath(t, "./testdata/exports"); pkg != nil {
   108  		nimports++
   109  		// The package's Imports should include all the types
   110  		// referenced by the exportdata, which may be more than
   111  		// the import statements in the package's source, but
   112  		// fewer than the transitive closure of dependencies.
   113  		want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]`
   114  		got := fmt.Sprint(pkg.Imports())
   115  		if got != want {
   116  			t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
   117  		}
   118  	}
   119  	nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
   120  	t.Logf("tested %d imports", nimports)
   121  }
   122  
   123  var importedObjectTests = []struct {
   124  	name string
   125  	want string
   126  }{
   127  	{"math.Pi", "const Pi untyped float"},
   128  	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
   129  	{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
   130  	{"math.Sin", "func Sin(x float64) float64"},
   131  	// TODO(gri) add more tests
   132  }
   133  
   134  func TestImportedTypes(t *testing.T) {
   135  	skipSpecialPlatforms(t)
   136  
   137  	// This package only handles gc export data.
   138  	if runtime.Compiler != "gc" {
   139  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   140  		return
   141  	}
   142  
   143  	for _, test := range importedObjectTests {
   144  		s := strings.Split(test.name, ".")
   145  		if len(s) != 2 {
   146  			t.Fatal("inconsistent test data")
   147  		}
   148  		importPath := s[0]
   149  		objName := s[1]
   150  
   151  		pkg, err := Import(imports, importPath)
   152  		if err != nil {
   153  			t.Error(err)
   154  			continue
   155  		}
   156  
   157  		obj := pkg.Scope().Lookup(objName)
   158  		if obj == nil {
   159  			t.Errorf("%s: object not found", test.name)
   160  			continue
   161  		}
   162  
   163  		got := types.ObjectString(obj, types.RelativeTo(pkg))
   164  		if got != test.want {
   165  			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
   166  		}
   167  	}
   168  }
   169  
   170  func TestIssue5815(t *testing.T) {
   171  	skipSpecialPlatforms(t)
   172  
   173  	// This package only handles gc export data.
   174  	if runtime.Compiler != "gc" {
   175  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   176  		return
   177  	}
   178  
   179  	pkg, err := Import(make(map[string]*types.Package), "strings")
   180  	if err != nil {
   181  		t.Fatal(err)
   182  	}
   183  
   184  	scope := pkg.Scope()
   185  	for _, name := range scope.Names() {
   186  		obj := scope.Lookup(name)
   187  		if obj.Pkg() == nil {
   188  			t.Errorf("no pkg for %s", obj)
   189  		}
   190  		if tname, _ := obj.(*types.TypeName); tname != nil {
   191  			named := tname.Type().(*types.Named)
   192  			for i := 0; i < named.NumMethods(); i++ {
   193  				m := named.Method(i)
   194  				if m.Pkg() == nil {
   195  					t.Errorf("no pkg for %s", m)
   196  				}
   197  			}
   198  		}
   199  	}
   200  }
   201  
   202  // Smoke test to ensure that imported methods get the correct package.
   203  func TestCorrectMethodPackage(t *testing.T) {
   204  	skipSpecialPlatforms(t)
   205  
   206  	// This package only handles gc export data.
   207  	if runtime.Compiler != "gc" {
   208  		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
   209  		return
   210  	}
   211  
   212  	imports := make(map[string]*types.Package)
   213  	_, err := Import(imports, "net/http")
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
   219  	mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
   220  	sel := mset.Lookup(nil, "Lock")
   221  	lock := sel.Obj().(*types.Func)
   222  	if got, want := lock.Pkg().Path(), "sync"; got != want {
   223  		t.Errorf("got package path %q; want %q", got, want)
   224  	}
   225  }