github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/interp/interp_test.go (about)

     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  
     5  // +build !windows,!plan9
     6  
     7  package interp_test
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"go/build"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  
    19  	"llvm.org/llgo/third_party/gotools/go/loader"
    20  	"llvm.org/llgo/third_party/gotools/go/ssa"
    21  	"llvm.org/llgo/third_party/gotools/go/ssa/interp"
    22  	"llvm.org/llgo/third_party/gotools/go/types"
    23  )
    24  
    25  // Each line contains a space-separated list of $GOROOT/test/
    26  // filenames comprising the main package of a program.
    27  // They are ordered quickest-first, roughly.
    28  //
    29  // TODO(adonovan): integrate into the $GOROOT/test driver scripts,
    30  // golden file checking, etc.
    31  var gorootTestTests = []string{
    32  	"235.go",
    33  	"alias1.go",
    34  	"chancap.go",
    35  	"func5.go",
    36  	"func6.go",
    37  	"func7.go",
    38  	"func8.go",
    39  	"helloworld.go",
    40  	"varinit.go",
    41  	"escape3.go",
    42  	"initcomma.go",
    43  	"cmp.go",
    44  	"compos.go",
    45  	"turing.go",
    46  	"indirect.go",
    47  	"complit.go",
    48  	"for.go",
    49  	"struct0.go",
    50  	"intcvt.go",
    51  	"printbig.go",
    52  	"deferprint.go",
    53  	"escape.go",
    54  	"range.go",
    55  	"const4.go",
    56  	"float_lit.go",
    57  	"bigalg.go",
    58  	"decl.go",
    59  	"if.go",
    60  	"named.go",
    61  	"bigmap.go",
    62  	"func.go",
    63  	"reorder2.go",
    64  	"closure.go",
    65  	"gc.go",
    66  	"simassign.go",
    67  	"iota.go",
    68  	"nilptr2.go",
    69  	"goprint.go", // doesn't actually assert anything (cmpout)
    70  	"utf.go",
    71  	"method.go",
    72  	"char_lit.go",
    73  	"env.go",
    74  	"int_lit.go",
    75  	"string_lit.go",
    76  	"defer.go",
    77  	"typeswitch.go",
    78  	"stringrange.go",
    79  	"reorder.go",
    80  	"method3.go",
    81  	"literal.go",
    82  	"nul1.go", // doesn't actually assert anything (errorcheckoutput)
    83  	"zerodivide.go",
    84  	"convert.go",
    85  	"convT2X.go",
    86  	"switch.go",
    87  	"initialize.go",
    88  	"ddd.go",
    89  	"blank.go", // partly disabled
    90  	"map.go",
    91  	"closedchan.go",
    92  	"divide.go",
    93  	"rename.go",
    94  	"const3.go",
    95  	"nil.go",
    96  	"recover.go", // reflection parts disabled
    97  	"recover1.go",
    98  	"recover2.go",
    99  	"recover3.go",
   100  	"typeswitch1.go",
   101  	"floatcmp.go",
   102  	"crlf.go", // doesn't actually assert anything (runoutput)
   103  	// Slow tests follow.
   104  	"bom.go", // ~1.7s
   105  	"gc1.go", // ~1.7s
   106  	"cmplxdivide.go cmplxdivide1.go", // ~2.4s
   107  
   108  	// Working, but not worth enabling:
   109  	// "append.go",    // works, but slow (15s).
   110  	// "gc2.go",       // works, but slow, and cheats on the memory check.
   111  	// "sigchld.go",   // works, but only on POSIX.
   112  	// "peano.go",     // works only up to n=9, and slow even then.
   113  	// "stack.go",     // works, but too slow (~30s) by default.
   114  	// "solitaire.go", // works, but too slow (~30s).
   115  	// "const.go",     // works but for but one bug: constant folder doesn't consider representations.
   116  	// "init1.go",     // too slow (80s) and not that interesting. Cheats on ReadMemStats check too.
   117  	// "rotate.go rotate0.go", // emits source for a test
   118  	// "rotate.go rotate1.go", // emits source for a test
   119  	// "rotate.go rotate2.go", // emits source for a test
   120  	// "rotate.go rotate3.go", // emits source for a test
   121  	// "64bit.go",             // emits source for a test
   122  	// "run.go",               // test driver, not a test.
   123  
   124  	// Broken.  TODO(adonovan): fix.
   125  	// copy.go         // very slow; but with N=4 quickly crashes, slice index out of range.
   126  	// nilptr.go       // interp: V > uintptr not implemented. Slow test, lots of mem
   127  	// args.go         // works, but requires specific os.Args from the driver.
   128  	// index.go        // a template, not a real test.
   129  	// mallocfin.go    // SetFinalizer not implemented.
   130  
   131  	// TODO(adonovan): add tests from $GOROOT/test/* subtrees:
   132  	// bench chan bugs fixedbugs interface ken.
   133  }
   134  
   135  // These are files in go.tools/go/ssa/interp/testdata/.
   136  var testdataTests = []string{
   137  	"boundmeth.go",
   138  	"complit.go",
   139  	"coverage.go",
   140  	"defer.go",
   141  	"fieldprom.go",
   142  	"ifaceconv.go",
   143  	"ifaceprom.go",
   144  	"initorder.go",
   145  	"methprom.go",
   146  	"mrvchain.go",
   147  	"range.go",
   148  	"recover.go",
   149  	"reflect.go",
   150  	"static.go",
   151  	"callstack.go",
   152  }
   153  
   154  // These are files and packages in $GOROOT/src/.
   155  var gorootSrcTests = []string{
   156  	"encoding/ascii85",
   157  	"encoding/csv",
   158  	"encoding/hex",
   159  	"encoding/pem",
   160  	"hash/crc32",
   161  	// "testing", // TODO(adonovan): implement runtime.Goexit correctly
   162  	"text/scanner",
   163  	"unicode",
   164  
   165  	// Too slow:
   166  	// "container/ring",
   167  	// "hash/adler32",
   168  
   169  	// TODO(adonovan): packages with Examples require os.Pipe (unimplemented):
   170  	// "unicode/utf8",
   171  	// "log",
   172  	// "path",
   173  	// "flag",
   174  }
   175  
   176  type successPredicate func(exitcode int, output string) error
   177  
   178  func run(t *testing.T, dir, input string, success successPredicate) bool {
   179  	fmt.Printf("Input: %s\n", input)
   180  
   181  	start := time.Now()
   182  
   183  	var inputs []string
   184  	for _, i := range strings.Split(input, " ") {
   185  		if strings.HasSuffix(i, ".go") {
   186  			i = dir + i
   187  		}
   188  		inputs = append(inputs, i)
   189  	}
   190  
   191  	var conf loader.Config
   192  	if _, err := conf.FromArgs(inputs, true); err != nil {
   193  		t.Errorf("FromArgs(%s) failed: %s", inputs, err)
   194  		return false
   195  	}
   196  
   197  	conf.Import("runtime")
   198  
   199  	// Print a helpful hint if we don't make it to the end.
   200  	var hint string
   201  	defer func() {
   202  		if hint != "" {
   203  			fmt.Println("FAIL")
   204  			fmt.Println(hint)
   205  		} else {
   206  			fmt.Println("PASS")
   207  		}
   208  
   209  		interp.CapturedOutput = nil
   210  	}()
   211  
   212  	hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
   213  
   214  	iprog, err := conf.Load()
   215  	if err != nil {
   216  		t.Errorf("conf.Load(%s) failed: %s", inputs, err)
   217  		return false
   218  	}
   219  
   220  	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
   221  	prog.BuildAll()
   222  
   223  	var mainPkg *ssa.Package
   224  	var initialPkgs []*ssa.Package
   225  	for _, info := range iprog.InitialPackages() {
   226  		if info.Pkg.Path() == "runtime" {
   227  			continue // not an initial package
   228  		}
   229  		p := prog.Package(info.Pkg)
   230  		initialPkgs = append(initialPkgs, p)
   231  		if mainPkg == nil && p.Func("main") != nil {
   232  			mainPkg = p
   233  		}
   234  	}
   235  	if mainPkg == nil {
   236  		testmainPkg := prog.CreateTestMainPackage(initialPkgs...)
   237  		if testmainPkg == nil {
   238  			t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg)
   239  			return false
   240  		}
   241  		if testmainPkg.Func("main") == nil {
   242  			t.Errorf("synthetic testmain package has no main")
   243  			return false
   244  		}
   245  		mainPkg = testmainPkg
   246  	}
   247  
   248  	var out bytes.Buffer
   249  	interp.CapturedOutput = &out
   250  
   251  	hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input)
   252  	exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{8, 8}, inputs[0], []string{})
   253  
   254  	// The definition of success varies with each file.
   255  	if err := success(exitCode, out.String()); err != nil {
   256  		t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
   257  		return false
   258  	}
   259  
   260  	hint = "" // call off the hounds
   261  
   262  	if false {
   263  		fmt.Println(input, time.Since(start)) // test profiling
   264  	}
   265  
   266  	return true
   267  }
   268  
   269  const slash = string(os.PathSeparator)
   270  
   271  func printFailures(failures []string) {
   272  	if failures != nil {
   273  		fmt.Println("The following tests failed:")
   274  		for _, f := range failures {
   275  			fmt.Printf("\t%s\n", f)
   276  		}
   277  	}
   278  }
   279  
   280  func success(exitcode int, output string) error {
   281  	if exitcode != 0 {
   282  		return fmt.Errorf("exit code was %d", exitcode)
   283  	}
   284  	if strings.Contains(output, "BUG") {
   285  		return fmt.Errorf("exited zero but output contained 'BUG'")
   286  	}
   287  	return nil
   288  }
   289  
   290  // TestTestdataFiles runs the interpreter on testdata/*.go.
   291  func TestTestdataFiles(t *testing.T) {
   292  	var failures []string
   293  	for _, input := range testdataTests {
   294  		if !run(t, "testdata"+slash, input, success) {
   295  			failures = append(failures, input)
   296  		}
   297  	}
   298  	printFailures(failures)
   299  }
   300  
   301  // TestGorootTest runs the interpreter on $GOROOT/test/*.go.
   302  func TestGorootTest(t *testing.T) {
   303  	if testing.Short() {
   304  		return // too slow (~30s)
   305  	}
   306  
   307  	var failures []string
   308  
   309  	for _, input := range gorootTestTests {
   310  		if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
   311  			failures = append(failures, input)
   312  		}
   313  	}
   314  	for _, input := range gorootSrcTests {
   315  		if !run(t, filepath.Join(build.Default.GOROOT, "src")+slash, input, success) {
   316  			failures = append(failures, input)
   317  		}
   318  	}
   319  	printFailures(failures)
   320  }
   321  
   322  // TestTestmainPackage runs the interpreter on a synthetic "testmain" package.
   323  func TestTestmainPackage(t *testing.T) {
   324  	success := func(exitcode int, output string) error {
   325  		if exitcode == 0 {
   326  			return fmt.Errorf("unexpected success")
   327  		}
   328  		if !strings.Contains(output, "FAIL: TestFoo") {
   329  			return fmt.Errorf("missing failure log for TestFoo")
   330  		}
   331  		if !strings.Contains(output, "FAIL: TestBar") {
   332  			return fmt.Errorf("missing failure log for TestBar")
   333  		}
   334  		// TODO(adonovan): test benchmarks too
   335  		return nil
   336  	}
   337  	run(t, "testdata"+slash, "a_test.go", success)
   338  }
   339  
   340  // CreateTestMainPackage should return nil if there were no tests.
   341  func TestNullTestmainPackage(t *testing.T) {
   342  	var conf loader.Config
   343  	conf.CreateFromFilenames("", "testdata/b_test.go")
   344  	iprog, err := conf.Load()
   345  	if err != nil {
   346  		t.Fatalf("CreatePackages failed: %s", err)
   347  	}
   348  	prog := ssa.Create(iprog, ssa.SanityCheckFunctions)
   349  	mainPkg := prog.Package(iprog.Created[0].Pkg)
   350  	if mainPkg.Func("main") != nil {
   351  		t.Fatalf("unexpected main function")
   352  	}
   353  	if prog.CreateTestMainPackage(mainPkg) != nil {
   354  		t.Fatalf("CreateTestMainPackage returned non-nil")
   355  	}
   356  }