1// Copyright 2018 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 5package packages_test 6 7import ( 8 "bytes" 9 "io/ioutil" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "testing" 14 "time" 15 16 "golang.org/x/tools/go/packages" 17) 18 19// This test loads the metadata for the standard library, 20func TestStdlibMetadata(t *testing.T) { 21 // TODO(adonovan): see if we can get away without this hack. 22 // if runtime.GOOS == "android" { 23 // t.Skipf("incomplete std lib on %s", runtime.GOOS) 24 // } 25 26 runtime.GC() 27 t0 := time.Now() 28 var memstats runtime.MemStats 29 runtime.ReadMemStats(&memstats) 30 alloc := memstats.Alloc 31 32 // Load, parse and type-check the program. 33 cfg := &packages.Config{Mode: packages.LoadAllSyntax} 34 pkgs, err := packages.Load(cfg, "std") 35 if err != nil { 36 t.Fatalf("failed to load metadata: %v", err) 37 } 38 39 t1 := time.Now() 40 runtime.GC() 41 runtime.ReadMemStats(&memstats) 42 runtime.KeepAlive(pkgs) 43 44 t.Logf("Loaded %d packages", len(pkgs)) 45 numPkgs := len(pkgs) 46 47 want := 150 // 186 on linux, 185 on windows. 48 if numPkgs < want { 49 t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) 50 } 51 52 t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) 53 t.Log("Metadata: ", t1.Sub(t0)) // ~800ms on 12 threads 54 t.Log("#MB: ", int64(memstats.Alloc-alloc)/1000000) // ~1MB 55} 56 57func TestCgoOption(t *testing.T) { 58 if testing.Short() { 59 t.Skip("skipping in short mode; uses tons of memory (golang.org/issue/14113)") 60 } 61 62 // TODO(adonovan): see if we can get away without these old 63 // go/loader hacks now that we use the go list command. 64 // 65 // switch runtime.GOOS { 66 // // On these systems, the net and os/user packages don't use cgo 67 // // or the std library is incomplete (Android). 68 // case "android", "plan9", "solaris", "windows": 69 // t.Skipf("no cgo or incomplete std lib on %s", runtime.GOOS) 70 // } 71 // // In nocgo builds (e.g. linux-amd64-nocgo), 72 // // there is no "runtime/cgo" package, 73 // // so cgo-generated Go files will have a failing import. 74 // if !build.Default.CgoEnabled { 75 // return 76 // } 77 78 // Test that we can load cgo-using packages with 79 // DisableCgo=true/false, which, among other things, causes go 80 // list to select pure Go/native implementations, respectively, 81 // based on build tags. 82 // 83 // Each entry specifies a package-level object and the generic 84 // file expected to define it when cgo is disabled. 85 // When cgo is enabled, the exact file is not specified (since 86 // it varies by platform), but must differ from the generic one. 87 // 88 // The test also loads the actual file to verify that the 89 // object is indeed defined at that location. 90 for _, test := range []struct { 91 pkg, name, genericFile string 92 }{ 93 {"net", "cgoLookupHost", "cgo_stub.go"}, 94 {"os/user", "current", "lookup_stubs.go"}, 95 } { 96 cfg := &packages.Config{Mode: packages.LoadSyntax} 97 pkgs, err := packages.Load(cfg, test.pkg) 98 if err != nil { 99 t.Errorf("Load failed: %v", err) 100 continue 101 } 102 pkg := pkgs[0] 103 obj := pkg.Types.Scope().Lookup(test.name) 104 if obj == nil { 105 t.Errorf("no object %s.%s", test.pkg, test.name) 106 continue 107 } 108 posn := pkg.Fset.Position(obj.Pos()) 109 gotFile := filepath.Base(posn.Filename) 110 filesMatch := gotFile == test.genericFile 111 112 if filesMatch { 113 t.Errorf("!DisableCgo: %s found in %s, want native file", 114 obj, gotFile) 115 } 116 117 // Load the file and check the object is declared at the right place. 118 b, err := ioutil.ReadFile(posn.Filename) 119 if err != nil { 120 t.Errorf("can't read %s: %s", posn.Filename, err) 121 continue 122 } 123 line := string(bytes.Split(b, []byte("\n"))[posn.Line-1]) 124 // Don't assume posn.Column is accurate. 125 if !strings.Contains(line, "func "+test.name) { 126 t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, line) 127 } 128 } 129} 130