Skip to content

Commit d2c1642

Browse files
adonovangopherbot
authored andcommitted
internal/gcimporter: rewrite TestIExportData_stdlib using go/packages
This breaks a dependency on the deprecated go/loader, and removes a bunch of legacy cruft. Updates golang/go#69556 Change-Id: I13e1b249db761bd0604881233116ca2a6c9c9904 Reviewed-on: https://go-review.googlesource.com/c/tools/+/614676 Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent af67b9d commit d2c1642

File tree

2 files changed

+67
-109
lines changed

2 files changed

+67
-109
lines changed

internal/gcimporter/iexport_go118_test.go

-4
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,6 @@ func TestImportTypeparamTests(t *testing.T) {
106106
t.Fatal(err)
107107
}
108108

109-
if isUnifiedBuilder() {
110-
t.Skip("unified export data format is currently unsupported")
111-
}
112-
113109
for _, entry := range list {
114110
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
115111
// For now, only consider standalone go files.

internal/gcimporter/iexport_test.go

+67-105
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,28 @@
77
package gcimporter_test
88

99
import (
10-
"bufio"
1110
"bytes"
1211
"fmt"
1312
"go/ast"
14-
"go/build"
1513
"go/constant"
1614
"go/importer"
1715
"go/parser"
1816
"go/token"
1917
"go/types"
20-
"io"
2118
"math/big"
2219
"os"
2320
"path/filepath"
2421
"reflect"
25-
"runtime"
26-
"sort"
2722
"strings"
2823
"testing"
2924

30-
"golang.org/x/tools/go/ast/inspector"
31-
"golang.org/x/tools/go/buildutil"
3225
"golang.org/x/tools/go/gcexportdata"
33-
"golang.org/x/tools/go/loader"
26+
"golang.org/x/tools/go/packages"
3427
"golang.org/x/tools/internal/aliases"
3528
"golang.org/x/tools/internal/gcimporter"
3629
"golang.org/x/tools/internal/testenv"
37-
"golang.org/x/tools/internal/typeparams/genericfeatures"
3830
)
3931

40-
func readExportFile(filename string) ([]byte, error) {
41-
f, err := os.Open(filename)
42-
if err != nil {
43-
return nil, err
44-
}
45-
defer f.Close()
46-
47-
buf := bufio.NewReader(f)
48-
if _, _, err := gcimporter.FindExportData(buf); err != nil {
49-
return nil, err
50-
}
51-
52-
if ch, err := buf.ReadByte(); err != nil {
53-
return nil, err
54-
} else if ch != 'i' {
55-
return nil, fmt.Errorf("unexpected byte: %v", ch)
56-
}
57-
58-
return io.ReadAll(buf)
59-
}
60-
6132
func iexport(fset *token.FileSet, version int, pkg *types.Package) ([]byte, error) {
6233
var buf bytes.Buffer
6334
const bundle, shallow = false, false
@@ -67,105 +38,95 @@ func iexport(fset *token.FileSet, version int, pkg *types.Package) ([]byte, erro
6738
return buf.Bytes(), nil
6839
}
6940

70-
// isUnifiedBuilder reports whether we are executing on a go builder that uses
71-
// unified export data.
72-
func isUnifiedBuilder() bool {
73-
return os.Getenv("GO_BUILDER_NAME") == "linux-amd64-unified"
74-
}
75-
76-
const minStdlibPackages = 248
77-
7841
func TestIExportData_stdlib(t *testing.T) {
79-
if runtime.Compiler == "gccgo" {
80-
t.Skip("gccgo standard library is inaccessible")
81-
}
82-
testenv.NeedsGoBuild(t)
42+
testenv.NeedsGoPackages(t)
8343
if isRace {
8444
t.Skipf("stdlib tests take too long in race mode and flake on builders")
8545
}
8646
if testing.Short() {
8747
t.Skip("skipping RAM hungry test in -short mode")
8848
}
8949

90-
// Load, parse and type-check the program.
91-
ctxt := build.Default // copy
92-
ctxt.GOPATH = "" // disable GOPATH
93-
conf := loader.Config{
94-
Build: &ctxt,
95-
AllowErrors: true,
96-
TypeChecker: types.Config{
97-
Sizes: types.SizesFor(ctxt.Compiler, ctxt.GOARCH),
98-
Error: func(err error) { t.Log(err) },
99-
},
100-
}
101-
for _, path := range buildutil.AllPackages(conf.Build) {
102-
conf.Import(path)
50+
var errorsDir string // GOROOT/src/errors directory
51+
{
52+
cfg := packages.Config{
53+
Mode: packages.NeedName | packages.NeedFiles,
54+
}
55+
pkgs, err := packages.Load(&cfg, "errors")
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
errorsDir = filepath.Dir(pkgs[0].GoFiles[0])
10360
}
10461

105-
// Create a package containing type and value errors to ensure
106-
// they are properly encoded/decoded.
107-
f, err := conf.ParseFile("haserrors/haserrors.go", `package haserrors
62+
// Load types from syntax for all std packages.
63+
//
64+
// Append a file to package errors containing type and
65+
// value errors to ensure they are properly encoded/decoded.
66+
const bad = `package errors
10867
const UnknownValue = "" + 0
10968
type UnknownType undefined
110-
`)
69+
`
70+
cfg := packages.Config{
71+
Mode: packages.LoadAllSyntax | packages.NeedDeps,
72+
Overlay: map[string][]byte{filepath.Join(errorsDir, "bad.go"): []byte(bad)},
73+
}
74+
pkgs, err := packages.Load(&cfg, "std") // ~800ms
11175
if err != nil {
11276
t.Fatal(err)
11377
}
114-
conf.CreateFromFiles("haserrors", f)
78+
fset := pkgs[0].Fset
11579

116-
prog, err := conf.Load()
117-
if err != nil {
118-
t.Fatalf("Load failed: %v", err)
119-
}
80+
version := gcimporter.IExportVersion
12081

121-
var sorted []*types.Package
122-
isUnified := isUnifiedBuilder()
123-
for pkg, info := range prog.AllPackages {
124-
// Temporarily skip packages that use generics on the unified builder, to
125-
// fix TryBots.
126-
//
127-
// TODO(#48595): fix this test with GOEXPERIMENT=unified.
128-
inspect := inspector.New(info.Files)
129-
features := genericfeatures.ForPackage(inspect, &info.Info)
130-
if isUnified && features != 0 {
131-
t.Logf("skipping package %q which uses generics", pkg.Path())
132-
continue
82+
// Export and reimport each package, and check that they match.
83+
var allPkgs []*types.Package
84+
var errorsPkg *types.Package // reimported errors package
85+
packages.Visit(pkgs, nil, func(ppkg *packages.Package) { // ~300ms
86+
pkg := ppkg.Types
87+
path := pkg.Path()
88+
if path == "unsafe" ||
89+
strings.HasPrefix(path, "cmd/") ||
90+
strings.HasPrefix(path, "vendor/") {
91+
return
13392
}
134-
if info.Files != nil { // non-empty directory
135-
sorted = append(sorted, pkg)
93+
allPkgs = append(allPkgs, pkg)
94+
95+
// Export and reimport the package, and compare.
96+
exportdata, err := iexport(fset, version, pkg)
97+
if err != nil {
98+
t.Error(err)
99+
return
100+
}
101+
pkg2 := testPkgData(t, fset, version, pkg, exportdata)
102+
if path == "errors" {
103+
errorsPkg = pkg2
136104
}
137-
}
138-
sort.Slice(sorted, func(i, j int) bool {
139-
return sorted[i].Path() < sorted[j].Path()
140105
})
141106

142-
version := gcimporter.IExportVersion
143-
numPkgs := len(sorted)
144-
if want := minStdlibPackages; numPkgs < want {
145-
t.Errorf("Loaded only %d packages, want at least %d", numPkgs, want)
107+
// Assert that we saw a plausible sized library.
108+
const minStdlibPackages = 284
109+
if n := len(allPkgs); n < minStdlibPackages {
110+
t.Errorf("Loaded only %d packages, want at least %d", n, minStdlibPackages)
146111
}
147112

148-
// TODO(adonovan): opt: parallelize this slow loop.
149-
for _, pkg := range sorted {
150-
if exportdata, err := iexport(conf.Fset, version, pkg); err != nil {
151-
t.Error(err)
152-
} else {
153-
testPkgData(t, conf.Fset, version, pkg, exportdata)
113+
// Check that reimported errors package has bad decls.
114+
if errorsPkg == nil {
115+
t.Fatalf("'errors' package not found")
116+
}
117+
for _, name := range []string{"UnknownType", "UnknownValue"} {
118+
obj := errorsPkg.Scope().Lookup(name)
119+
if obj == nil {
120+
t.Errorf("errors.%s not found", name)
154121
}
155-
156-
if pkg.Name() == "main" || pkg.Name() == "haserrors" {
157-
// skip; no export data
158-
} else if bp, err := ctxt.Import(pkg.Path(), "", build.FindOnly); err != nil {
159-
t.Log("warning:", err)
160-
} else if exportdata, err := readExportFile(bp.PkgObj); err != nil {
161-
t.Log("warning:", err)
162-
} else {
163-
testPkgData(t, conf.Fset, version, pkg, exportdata)
122+
if typ := obj.Type().Underlying(); typ.String() != "invalid type" {
123+
t.Errorf("errors.%s has underlying type %s, want invalid type", name, typ)
164124
}
165125
}
166126

127+
// (Sole) test of bundle functionality (250ms).
167128
var bundle bytes.Buffer
168-
if err := gcimporter.IExportBundle(&bundle, conf.Fset, sorted); err != nil {
129+
if err := gcimporter.IExportBundle(&bundle, fset, allPkgs); err != nil {
169130
t.Fatal(err)
170131
}
171132
fset2 := token.NewFileSet()
@@ -174,13 +135,13 @@ type UnknownType undefined
174135
if err != nil {
175136
t.Fatal(err)
176137
}
177-
178-
for i, pkg := range sorted {
179-
testPkg(t, conf.Fset, version, pkg, fset2, pkgs2[i])
138+
for i, pkg := range allPkgs {
139+
testPkg(t, fset, version, pkg, fset2, pkgs2[i])
180140
}
181141
}
182142

183-
func testPkgData(t *testing.T, fset *token.FileSet, version int, pkg *types.Package, exportdata []byte) {
143+
// testPkgData imports a package from export data and compares it with pkg.
144+
func testPkgData(t *testing.T, fset *token.FileSet, version int, pkg *types.Package, exportdata []byte) *types.Package {
184145
imports := make(map[string]*types.Package)
185146
fset2 := token.NewFileSet()
186147
_, pkg2, err := gcimporter.IImportData(fset2, imports, exportdata, pkg.Path())
@@ -189,6 +150,7 @@ func testPkgData(t *testing.T, fset *token.FileSet, version int, pkg *types.Pack
189150
}
190151

191152
testPkg(t, fset, version, pkg, fset2, pkg2)
153+
return pkg2
192154
}
193155

194156
func testPkg(t *testing.T, fset *token.FileSet, version int, pkg *types.Package, fset2 *token.FileSet, pkg2 *types.Package) {

0 commit comments

Comments
 (0)