GoPLS Viewer

Home|gopls/go/ssa/interp/interp_test.go
1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package interp_test
6
7// This test runs the SSA interpreter over sample Go programs.
8// Because the interpreter requires intrinsics for assembly
9// functions and many low-level runtime routines, it is inherently
10// not robust to evolutionary change in the standard library.
11// Therefore the test cases are restricted to programs that
12// use a fake standard library in testdata/src containing a tiny
13// subset of simple functions useful for writing assertions.
14//
15// We no longer attempt to interpret any real standard packages such as
16// fmt or testing, as it proved too fragile.
17
18import (
19    "bytes"
20    "fmt"
21    "go/build"
22    "go/types"
23    "log"
24    "os"
25    "path/filepath"
26    "strings"
27    "testing"
28    "time"
29
30    "golang.org/x/tools/go/loader"
31    "golang.org/x/tools/go/ssa"
32    "golang.org/x/tools/go/ssa/interp"
33    "golang.org/x/tools/go/ssa/ssautil"
34    "golang.org/x/tools/internal/typeparams"
35)
36
37// Each line contains a space-separated list of $GOROOT/test/
38// filenames comprising the main package of a program.
39// They are ordered quickest-first, roughly.
40//
41// If a test in this list fails spuriously, remove it.
42var gorootTestTests = []string{
43    "235.go",
44    "alias1.go",
45    "func5.go",
46    "func6.go",
47    "func7.go",
48    "func8.go",
49    "helloworld.go",
50    "varinit.go",
51    "escape3.go",
52    "initcomma.go",
53    "cmp.go",
54    "compos.go",
55    "turing.go",
56    "indirect.go",
57    "complit.go",
58    "for.go",
59    "struct0.go",
60    "intcvt.go",
61    "printbig.go",
62    "deferprint.go",
63    "escape.go",
64    "range.go",
65    "const4.go",
66    "float_lit.go",
67    "bigalg.go",
68    "decl.go",
69    "if.go",
70    "named.go",
71    "bigmap.go",
72    "func.go",
73    "reorder2.go",
74    "gc.go",
75    "simassign.go",
76    "iota.go",
77    "nilptr2.go",
78    "utf.go",
79    "method.go",
80    "char_lit.go",
81    "env.go",
82    "int_lit.go",
83    "string_lit.go",
84    "defer.go",
85    "typeswitch.go",
86    "stringrange.go",
87    "reorder.go",
88    "method3.go",
89    "literal.go",
90    "nul1.go"// doesn't actually assert anything (errorcheckoutput)
91    "zerodivide.go",
92    "convert.go",
93    "convT2X.go",
94    "switch.go",
95    "ddd.go",
96    "blank.go"// partly disabled
97    "closedchan.go",
98    "divide.go",
99    "rename.go",
100    "nil.go",
101    "recover1.go",
102    "recover2.go",
103    "recover3.go",
104    "typeswitch1.go",
105    "floatcmp.go",
106    "crlf.go"// doesn't actually assert anything (runoutput)
107}
108
109// These are files in go.tools/go/ssa/interp/testdata/.
110var testdataTests = []string{
111    "boundmeth.go",
112    "complit.go",
113    "convert.go",
114    "coverage.go",
115    "deepequal.go",
116    "defer.go",
117    "fieldprom.go",
118    "ifaceconv.go",
119    "ifaceprom.go",
120    "initorder.go",
121    "methprom.go",
122    "mrvchain.go",
123    "range.go",
124    "recover.go",
125    "reflect.go",
126    "static.go",
127    "width32.go",
128
129    "fixedbugs/issue52342.go",
130}
131
132func init() {
133    if typeparams.Enabled {
134        testdataTests = append(testdataTests"fixedbugs/issue52835.go")
135        testdataTests = append(testdataTests"fixedbugs/issue55086.go")
136        testdataTests = append(testdataTests"typeassert.go")
137        testdataTests = append(testdataTests"zeros.go")
138    }
139}
140
141// Specific GOARCH to use for a test case in go.tools/go/ssa/interp/testdata/.
142// Defaults to amd64 otherwise.
143var testdataArchs = map[string]string{
144    "width32.go""386",
145}
146
147func run(t *testing.Tinput stringbool {
148    // The recover2 test case is broken on Go 1.14+. See golang/go#34089.
149    // TODO(matloob): Fix this.
150    if filepath.Base(input) == "recover2.go" {
151        t.Skip("The recover2.go test is broken in go1.14+. See golang.org/issue/34089.")
152    }
153
154    t.Logf("Input: %s\n"input)
155
156    start := time.Now()
157
158    ctx := build.Default    // copy
159    ctx.GOROOT = "testdata" // fake goroot
160    ctx.GOOS = "linux"
161    ctx.GOARCH = "amd64"
162    if archok := testdataArchs[filepath.Base(input)]; ok {
163        ctx.GOARCH = arch
164    }
165
166    conf := loader.Config{Build: &ctx}
167    if _err := conf.FromArgs([]string{input}, true); err != nil {
168        t.Errorf("FromArgs(%s) failed: %s"inputerr)
169        return false
170    }
171
172    conf.Import("runtime")
173
174    // Print a helpful hint if we don't make it to the end.
175    var hint string
176    defer func() {
177        if hint != "" {
178            fmt.Println("FAIL")
179            fmt.Println(hint)
180        } else {
181            fmt.Println("PASS")
182        }
183
184        interp.CapturedOutput = nil
185    }()
186
187    hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n"input)
188
189    iprogerr := conf.Load()
190    if err != nil {
191        t.Errorf("conf.Load(%s) failed: %s"inputerr)
192        return false
193    }
194
195    bmode := ssa.InstantiateGenerics | ssa.SanityCheckFunctions
196    // bmode |= ssa.PrintFunctions // enable for debugging
197    prog := ssautil.CreateProgram(iprogbmode)
198    prog.Build()
199
200    mainPkg := prog.Package(iprog.Created[0].Pkg)
201    if mainPkg == nil {
202        t.Fatalf("not a main package: %s"input)
203    }
204
205    interp.CapturedOutput = new(bytes.Buffer)
206
207    sizes := types.SizesFor("gc"ctx.GOARCH)
208    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)
209    var imode interp.Mode // default mode
210    // imode |= interp.DisableRecover // enable for debugging
211    // imode |= interp.EnableTracing // enable for debugging
212    exitCode := interp.Interpret(mainPkgimodesizesinput, []string{})
213    if exitCode != 0 {
214        t.Fatalf("interpreting %s: exit code was %d"inputexitCode)
215    }
216    // $GOROOT/test tests use this convention:
217    if strings.Contains(interp.CapturedOutput.String(), "BUG") {
218        t.Fatalf("interpreting %s: exited zero but output contained 'BUG'"input)
219    }
220
221    hint = "" // call off the hounds
222
223    if false {
224        t.Log(inputtime.Since(start)) // test profiling
225    }
226
227    return true
228}
229
230func printFailures(failures []string) {
231    if failures != nil {
232        fmt.Println("The following tests failed:")
233        for _f := range failures {
234            fmt.Printf("\t%s\n"f)
235        }
236    }
237}
238
239// TestTestdataFiles runs the interpreter on testdata/*.go.
240func TestTestdataFiles(t *testing.T) {
241    cwderr := os.Getwd()
242    if err != nil {
243        log.Fatal(err)
244    }
245    var failures []string
246    for _input := range testdataTests {
247        if !run(tfilepath.Join(cwd"testdata"input)) {
248            failures = append(failuresinput)
249        }
250    }
251    printFailures(failures)
252}
253
254// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
255func TestGorootTest(t *testing.T) {
256    var failures []string
257
258    for _input := range gorootTestTests {
259        if !run(tfilepath.Join(build.Default.GOROOT"test"input)) {
260            failures = append(failuresinput)
261        }
262    }
263    printFailures(failures)
264}
265
266// TestTypeparamTest runs the interpreter on runnable examples
267// in $GOROOT/test/typeparam/*.go.
268
269func TestTypeparamTest(t *testing.T) {
270    if !typeparams.Enabled {
271        return
272    }
273
274    // Skip known failures for the given reason.
275    // TODO(taking): Address these.
276    skip := map[string]string{
277        "chans.go":       "interp tests do not support runtime.SetFinalizer",
278        "issue23536.go":  "unknown reason",
279        "issue376214.go""unknown issue with variadic cast on bytes",
280        "issue48042.go":  "interp tests do not handle reflect.Value.SetInt",
281        "issue47716.go":  "interp tests do not handle unsafe.Sizeof",
282        "issue50419.go":  "interp tests do not handle dispatch to String() correctly",
283        "issue51733.go":  "interp does not handle unsafe casts",
284        "ordered.go":     "math.NaN() comparisons not being handled correctly",
285        "orderedmap.go":  "interp tests do not support runtime.SetFinalizer",
286        "stringer.go":    "unknown reason",
287        "issue48317.go":  "interp tests do not support encoding/json",
288        "issue48318.go":  "interp tests do not support encoding/json",
289    }
290    // Collect all of the .go files in dir that are runnable.
291    dir := filepath.Join(build.Default.GOROOT"test""typeparam")
292    listerr := os.ReadDir(dir)
293    if err != nil {
294        t.Fatal(err)
295    }
296    var inputs []string
297    for _entry := range list {
298        if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
299            continue // Consider standalone go files.
300        }
301        if reason := skip[entry.Name()]; reason != "" {
302            t.Logf("skipping %q due to %s."entry.Name(), reason)
303            continue
304        }
305        input := filepath.Join(direntry.Name())
306        srcerr := os.ReadFile(input)
307        if err != nil {
308            t.Fatal(err)
309        }
310        // Only build test files that can be compiled, or compiled and run.
311        if bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// rundir")) {
312            inputs = append(inputsinput)
313        } else {
314            t.Logf("Not a `// run` file: %s"entry.Name())
315        }
316    }
317
318    var failures []string
319    for _input := range inputs {
320        t.Log("running"input)
321        if !run(tinput) {
322            failures = append(failuresinput)
323        }
324    }
325    printFailures(failures)
326}
327
MembersX
loader
TestGorootTest
TestGorootTest.failures
TestTypeparamTest.RangeStmt_7614.BlockStmt.err
TestTypeparamTest.inputs
run.ctx
run.hint
run.exitCode
printFailures
printFailures.BlockStmt.RangeStmt_5635.f
TestTypeparamTest.skip
TestTypeparamTest.list
TestTypeparamTest.RangeStmt_7614.BlockStmt.src
filepath
run.input
run.conf
run._
printFailures.failures
build
interp
run
run.start
run.err
TestTestdataFiles
TestTypeparamTest.t
testing
run.imode
TestTestdataFiles.cwd
TestTypeparamTest.RangeStmt_8285.input
typeparams
run.t
run.prog
run.sizes
TestTestdataFiles.t
TestTestdataFiles.RangeStmt_5885.input
TestTypeparamTest.dir
TestTypeparamTest.failures
log
run.iprog
run.mainPkg
TestTestdataFiles.err
TestTypeparamTest.err
TestTypeparamTest.RangeStmt_7614.entry
TestTypeparamTest.RangeStmt_7614.BlockStmt.input
ssautil
TestTestdataFiles.failures
TestGorootTest.t
TestGorootTest.RangeStmt_6172.input
TestTypeparamTest
Members
X