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