1
2
3
4
5 package interp_test
6
7
8
9
10
11
12
13
14
15
16
17
18 import (
19 "bytes"
20 "fmt"
21 "go/build"
22 "go/types"
23 "log"
24 "os"
25 "path/filepath"
26 "runtime"
27 "strings"
28 "testing"
29 "time"
30 "unsafe"
31
32 "golang.org/x/tools/go/loader"
33 "golang.org/x/tools/go/ssa"
34 "golang.org/x/tools/go/ssa/interp"
35 "golang.org/x/tools/go/ssa/ssautil"
36 "golang.org/x/tools/internal/testenv"
37 )
38
39
40
41
42
43
44 var gorootTestTests = []string{
45 "235.go",
46 "alias1.go",
47 "func5.go",
48 "func6.go",
49 "func7.go",
50 "func8.go",
51 "helloworld.go",
52 "varinit.go",
53 "escape3.go",
54 "initcomma.go",
55 "cmp.go",
56 "compos.go",
57 "turing.go",
58 "indirect.go",
59 "complit.go",
60 "for.go",
61 "struct0.go",
62 "intcvt.go",
63 "printbig.go",
64 "deferprint.go",
65 "escape.go",
66 "range.go",
67 "const4.go",
68 "float_lit.go",
69 "bigalg.go",
70 "decl.go",
71 "if.go",
72 "named.go",
73 "bigmap.go",
74 "func.go",
75 "reorder2.go",
76 "gc.go",
77 "simassign.go",
78 "iota.go",
79 "nilptr2.go",
80 "utf.go",
81 "method.go",
82 "char_lit.go",
83 "env.go",
84 "int_lit.go",
85 "string_lit.go",
86 "defer.go",
87 "typeswitch.go",
88 "stringrange.go",
89 "reorder.go",
90 "method3.go",
91 "literal.go",
92 "nul1.go",
93 "zerodivide.go",
94 "convert.go",
95 "convT2X.go",
96 "switch.go",
97 "ddd.go",
98 "blank.go",
99 "closedchan.go",
100 "divide.go",
101 "rename.go",
102 "nil.go",
103 "recover1.go",
104 "recover2.go",
105 "recover3.go",
106 "typeswitch1.go",
107 "floatcmp.go",
108 "crlf.go",
109 }
110
111
112 var testdataTests = []string{
113 "boundmeth.go",
114 "complit.go",
115 "convert.go",
116 "coverage.go",
117 "deepequal.go",
118 "defer.go",
119 "fieldprom.go",
120 "forvarlifetime_old.go",
121 "ifaceconv.go",
122 "ifaceprom.go",
123 "initorder.go",
124 "methprom.go",
125 "mrvchain.go",
126 "range.go",
127 "recover.go",
128 "reflect.go",
129 "slice2arrayptr.go",
130 "static.go",
131 "width32.go",
132 "rangevarlifetime_old.go",
133 "fixedbugs/issue52342.go",
134 "fixedbugs/issue55115.go",
135 "fixedbugs/issue52835.go",
136 "fixedbugs/issue55086.go",
137 "typeassert.go",
138 "zeros.go",
139 }
140
141 func init() {
142
143
144 os.Setenv("GOOS", runtime.GOOS)
145 os.Setenv("GOARCH", runtime.GOARCH)
146 }
147
148 func run(t *testing.T, input string, goroot string) {
149
150
151 if filepath.Base(input) == "recover2.go" {
152 t.Skip("The recover2.go test is broken in go1.14+. See golang.org/issue/34089.")
153 }
154
155 t.Logf("Input: %s\n", input)
156
157 start := time.Now()
158
159 ctx := build.Default
160 ctx.GOROOT = goroot
161 ctx.GOOS = runtime.GOOS
162 ctx.GOARCH = runtime.GOARCH
163 if filepath.Base(input) == "width32.go" && unsafe.Sizeof(int(0)) > 4 {
164 t.Skipf("skipping: width32.go checks behavior for a 32-bit int")
165 }
166
167 gover := ""
168 if p := testenv.Go1Point(); p > 0 {
169 gover = fmt.Sprintf("go1.%d", p)
170 }
171
172 conf := loader.Config{Build: &ctx, TypeChecker: types.Config{GoVersion: gover}}
173 if _, err := conf.FromArgs([]string{input}, true); err != nil {
174 t.Fatalf("FromArgs(%s) failed: %s", input, err)
175 }
176
177 conf.Import("runtime")
178
179
180 var hint string
181 defer func() {
182 if hint != "" {
183 fmt.Println("FAIL")
184 fmt.Println(hint)
185 } else {
186 fmt.Println("PASS")
187 }
188
189 interp.CapturedOutput = nil
190 }()
191
192 hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n", input)
193
194 iprog, err := conf.Load()
195 if err != nil {
196 t.Fatalf("conf.Load(%s) failed: %s", input, err)
197 }
198
199 bmode := ssa.InstantiateGenerics | ssa.SanityCheckFunctions
200
201 prog := ssautil.CreateProgram(iprog, bmode)
202 prog.Build()
203
204 mainPkg := prog.Package(iprog.Created[0].Pkg)
205 if mainPkg == nil {
206 t.Fatalf("not a main package: %s", input)
207 }
208
209 interp.CapturedOutput = new(bytes.Buffer)
210
211 sizes := types.SizesFor("gc", ctx.GOARCH)
212 if sizes.Sizeof(types.Typ[types.Int]) < 4 {
213 panic("bogus SizesFor")
214 }
215 hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -test -run --interp=T %s\n", input)
216 var imode interp.Mode
217
218
219 exitCode := interp.Interpret(mainPkg, imode, sizes, input, []string{})
220 if exitCode != 0 {
221 t.Fatalf("interpreting %s: exit code was %d", input, exitCode)
222 }
223
224 if strings.Contains(interp.CapturedOutput.String(), "BUG") {
225 t.Fatalf("interpreting %s: exited zero but output contained 'BUG'", input)
226 }
227
228 hint = ""
229
230 if false {
231 t.Log(input, time.Since(start))
232 }
233 }
234
235
236
237
238
239
240 func makeGoroot(t *testing.T) string {
241 goroot := t.TempDir()
242 src := filepath.Join(goroot, "src")
243
244 err := filepath.Walk("testdata/src", func(path string, info os.FileInfo, err error) error {
245 if err != nil {
246 return err
247 }
248
249 rel, err := filepath.Rel("testdata/src", path)
250 if err != nil {
251 return err
252 }
253 targ := filepath.Join(src, rel)
254
255 if info.IsDir() {
256 return os.Mkdir(targ, info.Mode().Perm()|0700)
257 }
258
259 b, err := os.ReadFile(path)
260 if err != nil {
261 return err
262 }
263 return os.WriteFile(targ, b, info.Mode().Perm())
264 })
265 if err != nil {
266 t.Fatal(err)
267 }
268
269 constsGo := fmt.Sprintf(`package runtime
270 const GOOS = %q
271 const GOARCH = %q
272 `, runtime.GOOS, runtime.GOARCH)
273 err = os.WriteFile(filepath.Join(src, "runtime/consts.go"), []byte(constsGo), 0644)
274 if err != nil {
275 t.Fatal(err)
276 }
277
278 return goroot
279 }
280
281
282 func TestTestdataFiles(t *testing.T) {
283 goroot := makeGoroot(t)
284 cwd, err := os.Getwd()
285 if err != nil {
286 log.Fatal(err)
287 }
288 for _, input := range testdataTests {
289 t.Run(input, func(t *testing.T) {
290 run(t, filepath.Join(cwd, "testdata", input), goroot)
291 })
292 }
293 }
294
295
296 func TestGorootTest(t *testing.T) {
297 goroot := makeGoroot(t)
298 for _, input := range gorootTestTests {
299 t.Run(input, func(t *testing.T) {
300 run(t, filepath.Join(build.Default.GOROOT, "test", input), goroot)
301 })
302 }
303 }
304
305
306
307
308 func TestTypeparamTest(t *testing.T) {
309 goroot := makeGoroot(t)
310
311
312
313 skip := map[string]string{
314 "chans.go": "interp tests do not support runtime.SetFinalizer",
315 "issue23536.go": "unknown reason",
316 "issue48042.go": "interp tests do not handle reflect.Value.SetInt",
317 "issue47716.go": "interp tests do not handle unsafe.Sizeof",
318 "issue50419.go": "interp tests do not handle dispatch to String() correctly",
319 "issue51733.go": "interp does not handle unsafe casts",
320 "ordered.go": "math.NaN() comparisons not being handled correctly",
321 "orderedmap.go": "interp tests do not support runtime.SetFinalizer",
322 "stringer.go": "unknown reason",
323 "issue48317.go": "interp tests do not support encoding/json",
324 "issue48318.go": "interp tests do not support encoding/json",
325 "issue58513.go": "interp tests do not support runtime.Caller",
326 }
327
328 dir := filepath.Join(build.Default.GOROOT, "test", "typeparam")
329 list, err := os.ReadDir(dir)
330 if err != nil {
331 t.Fatal(err)
332 }
333 for _, entry := range list {
334 if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
335 continue
336 }
337 t.Run(entry.Name(), func(t *testing.T) {
338 input := filepath.Join(dir, entry.Name())
339 src, err := os.ReadFile(input)
340 if err != nil {
341 t.Fatal(err)
342 }
343
344
345 if !bytes.HasPrefix(src, []byte("// run")) || bytes.HasPrefix(src, []byte("// rundir")) {
346 t.Logf("Not a `// run` file: %s", entry.Name())
347 return
348 }
349
350 if reason := skip[entry.Name()]; reason != "" {
351 t.Skipf("skipping: %s", reason)
352 }
353
354 run(t, input, goroot)
355 })
356 }
357 }
358
View as plain text