blob: 0b6a67523836079611d3ab0123f688c61680600a [file] [log] [blame]
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package test
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"internal/testenv"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
// runGenTest runs a test-generator, then runs the generated test.
// Generated test can either fail in compilation or execution.
// The environment variable parameter(s) is passed to the run
// of the generated test.
func runGenTest(t *testing.T, filename, tmpname string, ev ...string) {
testenv.MustHaveGoRun(t)
gotool := testenv.GoToolPath(t)
var stdout, stderr bytes.Buffer
cmd := testenv.Command(t, gotool, "run", filepath.Join("testdata", filename))
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
}
// Write stdout into a temporary file
tmpdir, ok := os.MkdirTemp("", tmpname)
if ok != nil {
t.Fatalf("Failed to create temporary directory")
}
defer os.RemoveAll(tmpdir)
rungo := filepath.Join(tmpdir, "run.go")
ok = os.WriteFile(rungo, stdout.Bytes(), 0600)
if ok != nil {
t.Fatalf("Failed to create temporary file " + rungo)
}
stdout.Reset()
stderr.Reset()
cmd = testenv.Command(t, gotool, "run", "-gcflags=-d=ssa/check/on", rungo)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = append(cmd.Env, ev...)
err := cmd.Run()
if err != nil {
t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
}
if s := stderr.String(); s != "" {
t.Errorf("Stderr = %s\nWant empty", s)
}
if s := stdout.String(); s != "" {
t.Errorf("Stdout = %s\nWant empty", s)
}
}
func TestGenFlowGraph(t *testing.T) {
if testing.Short() {
t.Skip("not run in short mode.")
}
runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1")
}
// TestCode runs all the tests in the testdata directory as subtests.
// These tests are special because we want to run them with different
// compiler flags set (and thus they can't just be _test.go files in
// this directory).
func TestCode(t *testing.T) {
testenv.MustHaveGoBuild(t)
gotool := testenv.GoToolPath(t)
// Make a temporary directory to work in.
tmpdir, err := os.MkdirTemp("", "TestCode")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
defer os.RemoveAll(tmpdir)
// Find all the test functions (and the files containing them).
var srcs []string // files containing Test functions
type test struct {
name string // TestFoo
usesFloat bool // might use float operations
}
var tests []test
files, err := os.ReadDir("testdata")
if err != nil {
t.Fatalf("can't read testdata directory: %v", err)
}
for _, f := range files {
if !strings.HasSuffix(f.Name(), "_test.go") {
continue
}
text, err := os.ReadFile(filepath.Join("testdata", f.Name()))
if err != nil {
t.Fatalf("can't read testdata/%s: %v", f.Name(), err)
}
fset := token.NewFileSet()
code, err := parser.ParseFile(fset, f.Name(), text, 0)
if err != nil {
t.Fatalf("can't parse testdata/%s: %v", f.Name(), err)
}
srcs = append(srcs, filepath.Join("testdata", f.Name()))
foundTest := false
for _, d := range code.Decls {
fd, ok := d.(*ast.FuncDecl)
if !ok {
continue
}
if !strings.HasPrefix(fd.Name.Name, "Test") {
continue
}
if fd.Recv != nil {
continue
}
if fd.Type.Results != nil {
continue
}
if len(fd.Type.Params.List) != 1 {
continue
}
p := fd.Type.Params.List[0]
if len(p.Names) != 1 {
continue
}
s, ok := p.Type.(*ast.StarExpr)
if !ok {
continue
}
sel, ok := s.X.(*ast.SelectorExpr)
if !ok {
continue
}
base, ok := sel.X.(*ast.Ident)
if !ok {
continue
}
if base.Name != "testing" {
continue
}
if sel.Sel.Name != "T" {
continue
}
// Found a testing function.
tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))})
foundTest = true
}
if !foundTest {
t.Fatalf("test file testdata/%s has no tests in it", f.Name())
}
}
flags := []string{""}
if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" || runtime.GOARCH == "386" {
flags = append(flags, ",softfloat")
}
for _, flag := range flags {
args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")}
args = append(args, srcs...)
out, err := testenv.Command(t, gotool, args...).CombinedOutput()
if err != nil || len(out) != 0 {
t.Fatalf("Build failed: %v\n%s\n", err, out)
}
// Now we have a test binary. Run it with all the tests as subtests of this one.
for _, test := range tests {
test := test
if flag == ",softfloat" && !test.usesFloat {
// No point in running the soft float version if the test doesn't use floats.
continue
}
t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) {
out, err := testenv.Command(t, filepath.Join(tmpdir, "code.test"), "-test.run="+test.name).CombinedOutput()
if err != nil || string(out) != "PASS\n" {
t.Errorf("Failed:\n%s\n", out)
}
})
}
}
}