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