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