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