github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 "io/ioutil" 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 // In nocgo builds (e.g. linux-amd64-nocgo), 134 // there is no "runtime/cgo" package, 135 // so cgo-generated Go files will have a failing import. 136 if !build.Default.CgoEnabled { 137 return 138 } 139 testenv.NeedsTool(t, "go") 140 141 // Test that we can load cgo-using packages with 142 // CGO_ENABLED=[01], which causes go/build to select pure 143 // Go/native implementations, respectively, based on build 144 // tags. 145 // 146 // Each entry specifies a package-level object and the generic 147 // file expected to define it when cgo is disabled. 148 // When cgo is enabled, the exact file is not specified (since 149 // it varies by platform), but must differ from the generic one. 150 // 151 // The test also loads the actual file to verify that the 152 // object is indeed defined at that location. 153 for _, test := range []struct { 154 pkg, name, genericFile string 155 }{ 156 {"net", "cgoLookupHost", "cgo_stub.go"}, 157 {"os/user", "current", "lookup_stubs.go"}, 158 } { 159 ctxt := build.Default 160 for _, ctxt.CgoEnabled = range []bool{false, true} { 161 conf := loader.Config{Build: &ctxt} 162 conf.Import(test.pkg) 163 prog, err := conf.Load() 164 if err != nil { 165 t.Errorf("Load failed: %v", err) 166 continue 167 } 168 info := prog.Imported[test.pkg] 169 if info == nil { 170 t.Errorf("package %s not found", test.pkg) 171 continue 172 } 173 obj := info.Pkg.Scope().Lookup(test.name) 174 if obj == nil { 175 t.Errorf("no object %s.%s", test.pkg, test.name) 176 continue 177 } 178 posn := prog.Fset.Position(obj.Pos()) 179 t.Logf("%s: %s (CgoEnabled=%t)", posn, obj, ctxt.CgoEnabled) 180 181 gotFile := filepath.Base(posn.Filename) 182 filesMatch := gotFile == test.genericFile 183 184 if ctxt.CgoEnabled && filesMatch { 185 t.Errorf("CGO_ENABLED=1: %s found in %s, want native file", 186 obj, gotFile) 187 } else if !ctxt.CgoEnabled && !filesMatch { 188 t.Errorf("CGO_ENABLED=0: %s found in %s, want %s", 189 obj, gotFile, test.genericFile) 190 } 191 192 // Load the file and check the object is declared at the right place. 193 b, err := ioutil.ReadFile(posn.Filename) 194 if err != nil { 195 t.Errorf("can't read %s: %s", posn.Filename, err) 196 continue 197 } 198 line := string(bytes.Split(b, []byte("\n"))[posn.Line-1]) 199 ident := line[posn.Column-1:] 200 if !strings.HasPrefix(ident, test.name) { 201 t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, ident) 202 } 203 } 204 } 205 }