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