libgo: update to go1.9
[official-gcc.git] / libgo / go / go / internal / gcimporter / gcimporter_test.go
blobc34f07c4c35bdf9782348acb8c8a8688f8de76d5
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.
5 package gcimporter
7 import (
8 "bytes"
9 "fmt"
10 "internal/testenv"
11 "io/ioutil"
12 "os"
13 "os/exec"
14 "path/filepath"
15 "runtime"
16 "strings"
17 "testing"
18 "time"
20 "go/types"
23 // skipSpecialPlatforms causes the test to be skipped for platforms where
24 // builders (build.golang.org) don't have access to compiled packages for
25 // import.
26 func skipSpecialPlatforms(t *testing.T) {
27 switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
28 case "nacl-amd64p32",
29 "nacl-386",
30 "nacl-arm",
31 "darwin-arm",
32 "darwin-arm64":
33 t.Skipf("no compiled packages available for import on %s", platform)
37 func compile(t *testing.T, dirname, filename string) string {
38 cmd := exec.Command(testenv.GoToolPath(t), "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)
45 // filename should end with ".go"
46 return filepath.Join(dirname, filename[:len(filename)-2]+"o")
49 func testPath(t *testing.T, path, srcDir string) *types.Package {
50 t0 := time.Now()
51 pkg, err := Import(make(map[string]*types.Package), path, srcDir)
52 if err != nil {
53 t.Errorf("testPath(%s): %s", path, err)
54 return nil
56 t.Logf("testPath(%s): %v", path, time.Since(t0))
57 return pkg
60 const maxTime = 30 * time.Second
62 func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
63 dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
64 list, err := ioutil.ReadDir(dirname)
65 if err != nil {
66 t.Fatalf("testDir(%s): %s", dirname, err)
68 for _, f := range list {
69 if time.Now().After(endTime) {
70 t.Log("testing time used up")
71 return
73 switch {
74 case !f.IsDir():
75 // try extensions
76 for _, ext := range pkgExts {
77 if strings.HasSuffix(f.Name(), ext) {
78 name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
79 if testPath(t, filepath.Join(dir, name), dir) != nil {
80 nimports++
84 case f.IsDir():
85 nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
88 return
91 func TestImportTestdata(t *testing.T) {
92 // This package only handles gc export data.
93 if runtime.Compiler != "gc" {
94 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
97 if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
98 defer os.Remove(outFn)
101 if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
102 // The package's Imports list must include all packages
103 // explicitly imported by exports.go, plus all packages
104 // referenced indirectly via exported objects in exports.go.
105 // With the textual export format, the list may also include
106 // additional packages that are not strictly required for
107 // import processing alone (they are exported to err "on
108 // the safe side").
109 // TODO(gri) update the want list to be precise, now that
110 // the textual export data is gone.
111 got := fmt.Sprint(pkg.Imports())
112 for _, want := range []string{"go/ast", "go/token"} {
113 if !strings.Contains(got, want) {
114 t.Errorf(`Package("exports").Imports() = %s, does not contain %s`, got, want)
120 func TestVersionHandling(t *testing.T) {
121 skipSpecialPlatforms(t) // we really only need to exclude nacl platforms, but this is fine
123 // This package only handles gc export data.
124 if runtime.Compiler != "gc" {
125 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
128 const dir = "./testdata/versions"
129 list, err := ioutil.ReadDir(dir)
130 if err != nil {
131 t.Fatal(err)
134 for _, f := range list {
135 name := f.Name()
136 if !strings.HasSuffix(name, ".a") {
137 continue // not a package file
139 if strings.Contains(name, "corrupted") {
140 continue // don't process a leftover corrupted file
142 pkgpath := "./" + name[:len(name)-2]
144 // test that export data can be imported
145 _, err := Import(make(map[string]*types.Package), pkgpath, dir)
146 if err != nil {
147 t.Errorf("import %q failed: %v", pkgpath, err)
148 continue
151 // create file with corrupted export data
152 // 1) read file
153 data, err := ioutil.ReadFile(filepath.Join(dir, name))
154 if err != nil {
155 t.Fatal(err)
157 // 2) find export data
158 i := bytes.Index(data, []byte("\n$$B\n")) + 5
159 j := bytes.Index(data[i:], []byte("\n$$\n")) + i
160 if i < 0 || j < 0 || i > j {
161 t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
163 // 3) corrupt the data (increment every 7th byte)
164 for k := j - 13; k >= i; k -= 7 {
165 data[k]++
167 // 4) write the file
168 pkgpath += "_corrupted"
169 filename := filepath.Join(dir, pkgpath) + ".a"
170 ioutil.WriteFile(filename, data, 0666)
171 defer os.Remove(filename)
173 // test that importing the corrupted file results in an error
174 _, err = Import(make(map[string]*types.Package), pkgpath, dir)
175 if err == nil {
176 t.Errorf("import corrupted %q succeeded", pkgpath)
177 } else if msg := err.Error(); !strings.Contains(msg, "version skew") {
178 t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
183 func TestImportStdLib(t *testing.T) {
184 skipSpecialPlatforms(t)
186 // This package only handles gc export data.
187 if runtime.Compiler != "gc" {
188 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
191 dt := maxTime
192 if testing.Short() && testenv.Builder() == "" {
193 dt = 10 * time.Millisecond
195 nimports := testDir(t, "", time.Now().Add(dt)) // installed packages
196 t.Logf("tested %d imports", nimports)
199 var importedObjectTests = []struct {
200 name string
201 want string
203 {"math.Pi", "const Pi untyped float"},
204 {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
205 {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
206 {"math.Sin", "func Sin(x float64) float64"},
207 // TODO(gri) add more tests
210 func TestImportedTypes(t *testing.T) {
211 skipSpecialPlatforms(t)
213 // This package only handles gc export data.
214 if runtime.Compiler != "gc" {
215 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
218 for _, test := range importedObjectTests {
219 s := strings.Split(test.name, ".")
220 if len(s) != 2 {
221 t.Fatal("inconsistent test data")
223 importPath := s[0]
224 objName := s[1]
226 pkg, err := Import(make(map[string]*types.Package), importPath, ".")
227 if err != nil {
228 t.Error(err)
229 continue
232 obj := pkg.Scope().Lookup(objName)
233 if obj == nil {
234 t.Errorf("%s: object not found", test.name)
235 continue
238 got := types.ObjectString(obj, types.RelativeTo(pkg))
239 if got != test.want {
240 t.Errorf("%s: got %q; want %q", test.name, got, test.want)
245 func TestIssue5815(t *testing.T) {
246 skipSpecialPlatforms(t)
248 // This package only handles gc export data.
249 if runtime.Compiler != "gc" {
250 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
253 pkg := importPkg(t, "strings")
255 scope := pkg.Scope()
256 for _, name := range scope.Names() {
257 obj := scope.Lookup(name)
258 if obj.Pkg() == nil {
259 t.Errorf("no pkg for %s", obj)
261 if tname, _ := obj.(*types.TypeName); tname != nil {
262 named := tname.Type().(*types.Named)
263 for i := 0; i < named.NumMethods(); i++ {
264 m := named.Method(i)
265 if m.Pkg() == nil {
266 t.Errorf("no pkg for %s", m)
273 // Smoke test to ensure that imported methods get the correct package.
274 func TestCorrectMethodPackage(t *testing.T) {
275 skipSpecialPlatforms(t)
277 // This package only handles gc export data.
278 if runtime.Compiler != "gc" {
279 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
282 imports := make(map[string]*types.Package)
283 _, err := Import(imports, "net/http", ".")
284 if err != nil {
285 t.Fatal(err)
288 mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
289 mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
290 sel := mset.Lookup(nil, "Lock")
291 lock := sel.Obj().(*types.Func)
292 if got, want := lock.Pkg().Path(), "sync"; got != want {
293 t.Errorf("got package path %q; want %q", got, want)
297 func TestIssue13566(t *testing.T) {
298 skipSpecialPlatforms(t)
300 // This package only handles gc export data.
301 if runtime.Compiler != "gc" {
302 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
305 // On windows, we have to set the -D option for the compiler to avoid having a drive
306 // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
307 if runtime.GOOS == "windows" {
308 t.Skip("avoid dealing with relative paths/drive letters on windows")
311 if f := compile(t, "testdata", "a.go"); f != "" {
312 defer os.Remove(f)
314 if f := compile(t, "testdata", "b.go"); f != "" {
315 defer os.Remove(f)
318 // import must succeed (test for issue at hand)
319 pkg := importPkg(t, "./testdata/b")
321 // make sure all indirectly imported packages have names
322 for _, imp := range pkg.Imports() {
323 if imp.Name() == "" {
324 t.Errorf("no name for %s package", imp.Path())
329 func TestIssue13898(t *testing.T) {
330 skipSpecialPlatforms(t)
332 // This package only handles gc export data.
333 if runtime.Compiler != "gc" {
334 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
337 // import go/internal/gcimporter which imports go/types partially
338 imports := make(map[string]*types.Package)
339 _, err := Import(imports, "go/internal/gcimporter", ".")
340 if err != nil {
341 t.Fatal(err)
344 // look for go/types package
345 var goTypesPkg *types.Package
346 for path, pkg := range imports {
347 if path == "go/types" {
348 goTypesPkg = pkg
349 break
352 if goTypesPkg == nil {
353 t.Fatal("go/types not found")
356 // look for go/types.Object type
357 obj := lookupObj(t, goTypesPkg.Scope(), "Object")
358 typ, ok := obj.Type().(*types.Named)
359 if !ok {
360 t.Fatalf("go/types.Object type is %v; wanted named type", typ)
363 // lookup go/types.Object.Pkg method
364 m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
365 if m == nil {
366 t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
369 // the method must belong to go/types
370 if m.Pkg().Path() != "go/types" {
371 t.Fatalf("found %v; want go/types", m.Pkg())
375 func TestIssue15517(t *testing.T) {
376 skipSpecialPlatforms(t)
378 // This package only handles gc export data.
379 if runtime.Compiler != "gc" {
380 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
383 // On windows, we have to set the -D option for the compiler to avoid having a drive
384 // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
385 if runtime.GOOS == "windows" {
386 t.Skip("avoid dealing with relative paths/drive letters on windows")
389 if f := compile(t, "testdata", "p.go"); f != "" {
390 defer os.Remove(f)
393 // Multiple imports of p must succeed without redeclaration errors.
394 // We use an import path that's not cleaned up so that the eventual
395 // file path for the package is different from the package path; this
396 // will expose the error if it is present.
398 // (Issue: Both the textual and the binary importer used the file path
399 // of the package to be imported as key into the shared packages map.
400 // However, the binary importer then used the package path to identify
401 // the imported package to mark it as complete; effectively marking the
402 // wrong package as complete. By using an "unclean" package path, the
403 // file and package path are different, exposing the problem if present.
404 // The same issue occurs with vendoring.)
405 imports := make(map[string]*types.Package)
406 for i := 0; i < 3; i++ {
407 if _, err := Import(imports, "./././testdata/p", "."); err != nil {
408 t.Fatal(err)
413 func TestIssue15920(t *testing.T) {
414 skipSpecialPlatforms(t)
416 // This package only handles gc export data.
417 if runtime.Compiler != "gc" {
418 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
421 // On windows, we have to set the -D option for the compiler to avoid having a drive
422 // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
423 if runtime.GOOS == "windows" {
424 t.Skip("avoid dealing with relative paths/drive letters on windows")
427 if f := compile(t, "testdata", "issue15920.go"); f != "" {
428 defer os.Remove(f)
431 importPkg(t, "./testdata/issue15920")
434 func TestIssue20046(t *testing.T) {
435 skipSpecialPlatforms(t)
437 // This package only handles gc export data.
438 if runtime.Compiler != "gc" {
439 t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
442 // On windows, we have to set the -D option for the compiler to avoid having a drive
443 // letter and an illegal ':' in the import path - just skip it (see also issue #3483).
444 if runtime.GOOS == "windows" {
445 t.Skip("avoid dealing with relative paths/drive letters on windows")
448 if f := compile(t, "testdata", "issue20046.go"); f != "" {
449 defer os.Remove(f)
452 // "./issue20046".V.M must exist
453 pkg := importPkg(t, "./testdata/issue20046")
454 obj := lookupObj(t, pkg.Scope(), "V")
455 if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
456 t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
460 func importPkg(t *testing.T, path string) *types.Package {
461 pkg, err := Import(make(map[string]*types.Package), path, ".")
462 if err != nil {
463 t.Fatal(err)
465 return pkg
468 func lookupObj(t *testing.T, scope *types.Scope, name string) types.Object {
469 if obj := scope.Lookup(name); obj != nil {
470 return obj
472 t.Fatalf("%s not found", name)
473 return nil