// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gcimporter
+package gcimporter_test
import (
"bytes"
"fmt"
+ "internal/goexperiment"
"internal/testenv"
"os"
"os/exec"
"testing"
"time"
+ "go/ast"
+ "go/importer"
+ "go/parser"
"go/token"
"go/types"
+
+ . "go/internal/gcimporter"
)
// skipSpecialPlatforms causes the test to be skipped for platforms where
const maxTime = 30 * time.Second
+var pkgExts = [...]string{".a", ".o"} // keep in sync with gcimporter.go
+
func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
list, err := os.ReadDir(dirname)
}
}
+func TestImportTypeparamTests(t *testing.T) {
+ // This test doesn't yet work with the unified export format.
+ if goexperiment.Unified {
+ t.Skip("unified export data format is currently unsupported")
+ }
+
+ // This package only handles gc export data.
+ if runtime.Compiler != "gc" {
+ t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+ }
+
+ tmpdir := mktmpdir(t)
+ defer os.RemoveAll(tmpdir)
+
+ // Check go files in test/typeparam, except those that fail for a known
+ // reason.
+ rootDir := filepath.Join(runtime.GOROOT(), "test", "typeparam")
+ list, err := os.ReadDir(rootDir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ skip := map[string]string{
+ "equal.go": "inconsistent embedded sorting", // TODO(rfindley): investigate this.
+ "nested.go": "fails to compile", // TODO(rfindley): investigate this.
+ }
+
+ for _, entry := range list {
+ if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
+ // For now, only consider standalone go files.
+ continue
+ }
+
+ t.Run(entry.Name(), func(t *testing.T) {
+ if reason, ok := skip[entry.Name()]; ok {
+ t.Skip(reason)
+ }
+
+ filename := filepath.Join(rootDir, entry.Name())
+ src, err := os.ReadFile(filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// compile")) {
+ // We're bypassing the logic of run.go here, so be conservative about
+ // the files we consider in an attempt to make this test more robust to
+ // changes in test/typeparams.
+ t.Skipf("not detected as a run test")
+ }
+
+ // Compile and import, and compare the resulting package with the package
+ // that was type-checked directly.
+ compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"))
+ pkgName := strings.TrimSuffix(entry.Name(), ".go")
+ imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
+ checked := checkFile(t, filename, src)
+
+ seen := make(map[string]bool)
+ for _, name := range imported.Scope().Names() {
+ if !token.IsExported(name) {
+ continue // ignore synthetic names like .inittask and .dict.*
+ }
+ seen[name] = true
+
+ importedObj := imported.Scope().Lookup(name)
+ got := types.ObjectString(importedObj, types.RelativeTo(imported))
+ got = sanitizeObjectString(got)
+
+ checkedObj := checked.Scope().Lookup(name)
+ if checkedObj == nil {
+ t.Fatalf("imported object %q was not type-checked", name)
+ }
+ want := types.ObjectString(checkedObj, types.RelativeTo(checked))
+ want = sanitizeObjectString(want)
+
+ if got != want {
+ t.Errorf("imported %q as %q, want %q", name, got, want)
+ }
+ }
+
+ for _, name := range checked.Scope().Names() {
+ if !token.IsExported(name) || seen[name] {
+ continue
+ }
+ t.Errorf("did not import object %q", name)
+ }
+ })
+ }
+}
+
+// sanitizeObjectString removes type parameter debugging markers from an object
+// string, to normalize it for comparison.
+// TODO(rfindley): this should not be necessary.
+func sanitizeObjectString(s string) string {
+ var runes []rune
+ for _, r := range s {
+ if r == '#' {
+ continue // trim instance markers
+ }
+ if '₀' <= r && r < '₀'+10 {
+ continue // trim type parameter subscripts
+ }
+ runes = append(runes, r)
+ }
+ return string(runes)
+}
+
+func checkFile(t *testing.T, filename string, src []byte) *types.Package {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, filename, src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ config := types.Config{
+ Importer: importer.Default(),
+ }
+ pkg, err := config.Check("", fset, []*ast.File{f}, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return pkg
+}
+
func TestVersionHandling(t *testing.T) {
skipSpecialPlatforms(t)