1
2
3
4
5 package srcimporter
6
7 import (
8 "flag"
9 "go/build"
10 "go/token"
11 "go/types"
12 "internal/testenv"
13 "os"
14 "path"
15 "path/filepath"
16 "strings"
17 "testing"
18 "time"
19 )
20
21 func TestMain(m *testing.M) {
22 flag.Parse()
23 build.Default.GOROOT = testenv.GOROOT(nil)
24 os.Exit(m.Run())
25 }
26
27 const maxTime = 2 * time.Second
28
29 var importer = New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
30
31 func doImport(t *testing.T, path, srcDir string) {
32 t0 := time.Now()
33 if _, err := importer.ImportFrom(path, srcDir, 0); err != nil {
34
35 if _, nogo := err.(*build.NoGoError); !nogo {
36 t.Errorf("import %q failed (%v)", path, err)
37 }
38 return
39 }
40 t.Logf("import %q: %v", path, time.Since(t0))
41 }
42
43
44
45
46
47 func walkDir(t *testing.T, path string, endTime time.Time) (int, bool) {
48 if time.Now().After(endTime) {
49 t.Log("testing time used up")
50 return 0, true
51 }
52
53
54 if path == "builtin" || path == "unsafe" || strings.HasSuffix(path, "testdata") {
55 return 0, false
56 }
57
58 list, err := os.ReadDir(filepath.Join(testenv.GOROOT(t), "src", path))
59 if err != nil {
60 t.Fatalf("walkDir %s failed (%v)", path, err)
61 }
62
63 nimports := 0
64 hasGoFiles := false
65 for _, f := range list {
66 if f.IsDir() {
67 n, abort := walkDir(t, filepath.Join(path, f.Name()), endTime)
68 nimports += n
69 if abort {
70 return nimports, true
71 }
72 } else if strings.HasSuffix(f.Name(), ".go") {
73 hasGoFiles = true
74 }
75 }
76
77 if hasGoFiles {
78 doImport(t, path, "")
79 nimports++
80 }
81
82 return nimports, false
83 }
84
85 func TestImportStdLib(t *testing.T) {
86 testenv.MustHaveSource(t)
87
88 if testing.Short() && testenv.Builder() == "" {
89 t.Skip("skipping in -short mode")
90 }
91 dt := maxTime
92 nimports, _ := walkDir(t, "", time.Now().Add(dt))
93 t.Logf("tested %d imports", nimports)
94 }
95
96 var importedObjectTests = []struct {
97 name string
98 want string
99 }{
100 {"flag.Bool", "func Bool(name string, value bool, usage string) *bool"},
101 {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
102 {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
103 {"math.Pi", "const Pi untyped float"},
104 {"math.Sin", "func Sin(x float64) float64"},
105 {"math/big.Int", "type Int struct{neg bool; abs nat}"},
106 {"golang.org/x/text/unicode/norm.MaxSegmentSize", "const MaxSegmentSize untyped int"},
107 }
108
109 func TestImportedTypes(t *testing.T) {
110 testenv.MustHaveSource(t)
111
112 for _, test := range importedObjectTests {
113 i := strings.LastIndex(test.name, ".")
114 if i < 0 {
115 t.Fatal("invalid test data format")
116 }
117 importPath := test.name[:i]
118 objName := test.name[i+1:]
119
120 pkg, err := importer.ImportFrom(importPath, ".", 0)
121 if err != nil {
122 t.Error(err)
123 continue
124 }
125
126 obj := pkg.Scope().Lookup(objName)
127 if obj == nil {
128 t.Errorf("%s: object not found", test.name)
129 continue
130 }
131
132 got := types.ObjectString(obj, types.RelativeTo(pkg))
133 if got != test.want {
134 t.Errorf("%s: got %q; want %q", test.name, got, test.want)
135 }
136
137 if named, _ := obj.Type().(*types.Named); named != nil {
138 verifyInterfaceMethodRecvs(t, named, 0)
139 }
140 }
141 }
142
143
144
145 func verifyInterfaceMethodRecvs(t *testing.T, named *types.Named, level int) {
146
147 if level > 10 {
148 t.Errorf("%s: embeds itself", named)
149 return
150 }
151
152 iface, _ := named.Underlying().(*types.Interface)
153 if iface == nil {
154 return
155 }
156
157
158 for i := 0; i < iface.NumExplicitMethods(); i++ {
159 m := iface.ExplicitMethod(i)
160 recv := m.Type().(*types.Signature).Recv()
161 if recv == nil {
162 t.Errorf("%s: missing receiver type", m)
163 continue
164 }
165 if recv.Type() != named {
166 t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
167 }
168 }
169
170
171 for i := 0; i < iface.NumEmbeddeds(); i++ {
172
173 verifyInterfaceMethodRecvs(t, iface.Embedded(i), level+1)
174 }
175 }
176
177 func TestReimport(t *testing.T) {
178 testenv.MustHaveSource(t)
179
180
181
182
183 mathPkg := types.NewPackage("math", "math")
184 importer := New(&build.Default, token.NewFileSet(), map[string]*types.Package{mathPkg.Path(): mathPkg})
185 _, err := importer.ImportFrom("math", ".", 0)
186 if err == nil || !strings.HasPrefix(err.Error(), "reimport") {
187 t.Errorf("got %v; want reimport error", err)
188 }
189 }
190
191 func TestIssue20855(t *testing.T) {
192 testenv.MustHaveSource(t)
193
194 pkg, err := importer.ImportFrom("go/internal/srcimporter/testdata/issue20855", ".", 0)
195 if err == nil || !strings.Contains(err.Error(), "missing function body") {
196 t.Fatalf("got unexpected or no error: %v", err)
197 }
198 if pkg == nil {
199 t.Error("got no package despite no hard errors")
200 }
201 }
202
203 func testImportPath(t *testing.T, pkgPath string) {
204 testenv.MustHaveSource(t)
205
206 pkgName := path.Base(pkgPath)
207
208 pkg, err := importer.Import(pkgPath)
209 if err != nil {
210 t.Fatal(err)
211 }
212
213 if pkg.Name() != pkgName {
214 t.Errorf("got %q; want %q", pkg.Name(), pkgName)
215 }
216
217 if pkg.Path() != pkgPath {
218 t.Errorf("got %q; want %q", pkg.Path(), pkgPath)
219 }
220 }
221
222
223 func TestIssue23092(t *testing.T) {
224 testImportPath(t, "./testdata/issue23092")
225 }
226
227
228 func TestIssue24392(t *testing.T) {
229 testImportPath(t, "go/internal/srcimporter/testdata/issue24392")
230 }
231
232 func TestCgo(t *testing.T) {
233 testenv.MustHaveGoBuild(t)
234 testenv.MustHaveCGO(t)
235
236 buildCtx := build.Default
237 importer := New(&buildCtx, token.NewFileSet(), make(map[string]*types.Package))
238 _, err := importer.ImportFrom("cmd/cgo/internal/test", buildCtx.Dir, 0)
239 if err != nil {
240 t.Fatalf("Import failed: %v", err)
241 }
242 }
243
View as plain text