golang.org/x/tools@v0.21.0/go/loader/stdlib_test.go (about) 1 // Copyright 2013 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 loader_test 6 7 // This file enumerates all packages beneath $GOROOT, loads them, plus 8 // their external tests if any, runs the type checker on them, and 9 // prints some summary information. 10 11 import ( 12 "bytes" 13 "fmt" 14 "go/ast" 15 "go/build" 16 "go/token" 17 "go/types" 18 "os" 19 "path/filepath" 20 "runtime" 21 "strings" 22 "testing" 23 "time" 24 25 "golang.org/x/tools/go/buildutil" 26 "golang.org/x/tools/go/loader" 27 "golang.org/x/tools/internal/testenv" 28 ) 29 30 func TestStdlib(t *testing.T) { 31 if runtime.GOOS == "android" { 32 t.Skipf("incomplete std lib on %s", runtime.GOOS) 33 } 34 if testing.Short() { 35 t.Skip("skipping in short mode; uses tons of memory (https://golang.org/issue/14113)") 36 } 37 testenv.NeedsTool(t, "go") 38 39 runtime.GC() 40 t0 := time.Now() 41 var memstats runtime.MemStats 42 runtime.ReadMemStats(&memstats) 43 alloc := memstats.Alloc 44 45 // Load, parse and type-check the program. 46 ctxt := build.Default // copy 47 ctxt.GOPATH = "" // disable GOPATH 48 conf := loader.Config{Build: &ctxt} 49 for _, path := range buildutil.AllPackages(conf.Build) { 50 conf.ImportWithTests(path) 51 } 52 53 prog, err := conf.Load() 54 if err != nil { 55 t.Fatalf("Load failed: %v", err) 56 } 57 58 t1 := time.Now() 59 runtime.GC() 60 runtime.ReadMemStats(&memstats) 61 62 numPkgs := len(prog.AllPackages) 63 if want := 205; numPkgs < want { 64 t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want) 65 } 66 67 // Dump package members. 68 if false { 69 for pkg := range prog.AllPackages { 70 fmt.Printf("Package %s:\n", pkg.Path()) 71 scope := pkg.Scope() 72 qualifier := types.RelativeTo(pkg) 73 for _, name := range scope.Names() { 74 if ast.IsExported(name) { 75 fmt.Printf("\t%s\n", types.ObjectString(scope.Lookup(name), qualifier)) 76 } 77 } 78 fmt.Println() 79 } 80 } 81 82 // Check that Test functions for regexp and compress/bzip2 are 83 // simultaneously present. The apparent cycle formed when augmenting 84 // these packages by their tests (together with io/ioutil's test, which is now 85 // an xtest) was the original motivation or reporting golang.org/issue/7114. 86 // 87 // compress/bzip2.TestBitReader in bzip2_test.go imports io/ioutil 88 // io/ioutil.TestTempFile in tempfile_test.go imports regexp (no longer exists) 89 // regexp.TestRE2Search in exec_test.go imports compress/bzip2 90 for _, test := range []struct{ pkg, fn string }{ 91 {"regexp", "TestRE2Search"}, 92 {"compress/bzip2", "TestBitReader"}, 93 } { 94 info := prog.Imported[test.pkg] 95 if info == nil { 96 t.Errorf("failed to load package %q", test.pkg) 97 continue 98 } 99 obj, _ := info.Pkg.Scope().Lookup(test.fn).(*types.Func) 100 if obj == nil { 101 t.Errorf("package %q has no func %q", test.pkg, test.fn) 102 continue 103 } 104 } 105 106 // Dump some statistics. 107 108 // determine line count 109 var lineCount int 110 prog.Fset.Iterate(func(f *token.File) bool { 111 lineCount += f.LineCount() 112 return true 113 }) 114 115 t.Log("GOMAXPROCS: ", runtime.GOMAXPROCS(0)) 116 t.Log("#Source lines: ", lineCount) 117 t.Log("Load/parse/typecheck: ", t1.Sub(t0)) 118 t.Log("#MB: ", int64(memstats.Alloc-alloc)/1000000) 119 } 120 121 func TestCgoOption(t *testing.T) { 122 if testing.Short() { 123 t.Skip("skipping in short mode; uses tons of memory (https://golang.org/issue/14113)") 124 } 125 switch runtime.GOOS { 126 // On these systems, the net and os/user packages don't use cgo 127 // or the std library is incomplete (Android). 128 case "android", "plan9", "solaris", "windows": 129 t.Skipf("no cgo or incomplete std lib on %s", runtime.GOOS) 130 case "darwin": 131 t.Skipf("golang/go#58493: file locations in this test are stale on darwin") 132 } 133 testenv.NeedsTool(t, "go") 134 // In nocgo builds (e.g. linux-amd64-nocgo), 135 // there is no "runtime/cgo" package, 136 // so cgo-generated Go files will have a failing import. 137 testenv.NeedsTool(t, "cgo") 138 139 // Test that we can load cgo-using packages with 140 // CGO_ENABLED=[01], which causes go/build to select pure 141 // Go/native implementations, respectively, based on build 142 // tags. 143 // 144 // Each entry specifies a package-level object and the generic 145 // file expected to define it when cgo is disabled. 146 // When cgo is enabled, the exact file is not specified (since 147 // it varies by platform), but must differ from the generic one. 148 // 149 // The test also loads the actual file to verify that the 150 // object is indeed defined at that location. 151 for _, test := range []struct { 152 pkg, name, genericFile string 153 }{ 154 {"net", "cgoLookupHost", "cgo_stub.go"}, 155 {"os/user", "current", "lookup_stubs.go"}, 156 } { 157 ctxt := build.Default 158 for _, ctxt.CgoEnabled = range []bool{false, true} { 159 conf := loader.Config{Build: &ctxt} 160 conf.Import(test.pkg) 161 prog, err := conf.Load() 162 if err != nil { 163 t.Errorf("Load failed: %v", err) 164 continue 165 } 166 info := prog.Imported[test.pkg] 167 if info == nil { 168 t.Errorf("package %s not found", test.pkg) 169 continue 170 } 171 obj := info.Pkg.Scope().Lookup(test.name) 172 if obj == nil { 173 t.Errorf("no object %s.%s", test.pkg, test.name) 174 continue 175 } 176 posn := prog.Fset.Position(obj.Pos()) 177 t.Logf("%s: %s (CgoEnabled=%t)", posn, obj, ctxt.CgoEnabled) 178 179 gotFile := filepath.Base(posn.Filename) 180 filesMatch := gotFile == test.genericFile 181 182 if ctxt.CgoEnabled && filesMatch { 183 t.Errorf("CGO_ENABLED=1: %s found in %s, want native file", 184 obj, gotFile) 185 } else if !ctxt.CgoEnabled && !filesMatch { 186 t.Errorf("CGO_ENABLED=0: %s found in %s, want %s", 187 obj, gotFile, test.genericFile) 188 } 189 190 // Load the file and check the object is declared at the right place. 191 b, err := os.ReadFile(posn.Filename) 192 if err != nil { 193 t.Errorf("can't read %s: %s", posn.Filename, err) 194 continue 195 } 196 line := string(bytes.Split(b, []byte("\n"))[posn.Line-1]) 197 ident := line[posn.Column-1:] 198 if !strings.HasPrefix(ident, test.name) { 199 t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, ident) 200 } 201 } 202 } 203 }