golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/go/ssa/interp/interp_go122_test.go (about)

     1  // Copyright 2023 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  //go:build go1.22
     6  // +build go1.22
     7  
     8  package interp_test
     9  
    10  import (
    11  	"bytes"
    12  	"log"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"reflect"
    17  	"testing"
    18  
    19  	"golang.org/x/tools/internal/testenv"
    20  )
    21  
    22  func init() {
    23  	testdataTests = append(testdataTests,
    24  		"rangevarlifetime_go122.go",
    25  		"forvarlifetime_go122.go",
    26  	)
    27  }
    28  
    29  // TestExperimentRange tests files in testdata with GOEXPERIMENT=range set.
    30  func TestExperimentRange(t *testing.T) {
    31  	testenv.NeedsGoExperiment(t, "range")
    32  
    33  	// TODO: Is cwd actually needed here?
    34  	goroot := makeGoroot(t)
    35  	cwd, err := os.Getwd()
    36  	if err != nil {
    37  		log.Fatal(err)
    38  	}
    39  	run(t, filepath.Join(cwd, "testdata", "rangeoverint.go"), goroot)
    40  }
    41  
    42  // TestRangeFunc tests range-over-func in a subprocess.
    43  func TestRangeFunc(t *testing.T) {
    44  	testenv.NeedsGo1Point(t, 23)
    45  
    46  	// TODO(taking): Remove subprocess from the test and capture output another way.
    47  	if os.Getenv("INTERPTEST_CHILD") == "1" {
    48  		testRangeFunc(t)
    49  		return
    50  	}
    51  
    52  	testenv.NeedsExec(t)
    53  	testenv.NeedsTool(t, "go")
    54  
    55  	cmd := exec.Command(os.Args[0], "-test.run=TestRangeFunc")
    56  	cmd.Env = append(os.Environ(), "INTERPTEST_CHILD=1")
    57  	out, err := cmd.CombinedOutput()
    58  	if len(out) > 0 {
    59  		t.Logf("out=<<%s>>", out)
    60  	}
    61  
    62  	// Check the output of the tests.
    63  	const (
    64  		RERR_DONE      = "Saw expected panic: yield function called after range loop exit"
    65  		RERR_MISSING   = "Saw expected panic: iterator call did not preserve panic"
    66  		RERR_EXHAUSTED = RERR_DONE // ssa does not distinguish. Same message as RERR_DONE.
    67  
    68  		CERR_DONE      = "Saw expected panic: checked rangefunc error: loop iteration after body done"
    69  		CERR_EXHAUSTED = "Saw expected panic: checked rangefunc error: loop iteration after iterator exit"
    70  		CERR_MISSING   = "Saw expected panic: checked rangefunc error: loop iterator swallowed panic"
    71  
    72  		panickyIterMsg = "Saw expected panic: Panicky iterator panicking"
    73  	)
    74  	expected := map[string][]string{
    75  		// rangefunc.go
    76  		"TestCheck":                           []string{"i = 45", CERR_DONE},
    77  		"TestCooperativeBadOfSliceIndex":      []string{RERR_EXHAUSTED, "i = 36"},
    78  		"TestCooperativeBadOfSliceIndexCheck": []string{CERR_EXHAUSTED, "i = 36"},
    79  		"TestTrickyIterAll":                   []string{"i = 36", RERR_EXHAUSTED},
    80  		"TestTrickyIterOne":                   []string{"i = 1", RERR_EXHAUSTED},
    81  		"TestTrickyIterZero":                  []string{"i = 0", RERR_EXHAUSTED},
    82  		"TestTrickyIterZeroCheck":             []string{"i = 0", CERR_EXHAUSTED},
    83  		"TestTrickyIterEcho": []string{
    84  			"first loop i=0",
    85  			"first loop i=1",
    86  			"first loop i=3",
    87  			"first loop i=6",
    88  			"i = 10",
    89  			"second loop i=0",
    90  			RERR_EXHAUSTED,
    91  			"end i=0",
    92  		},
    93  		"TestTrickyIterEcho2": []string{
    94  			"k=0,x=1,i=0",
    95  			"k=0,x=2,i=1",
    96  			"k=0,x=3,i=3",
    97  			"k=0,x=4,i=6",
    98  			"i = 10",
    99  			"k=1,x=1,i=0",
   100  			RERR_EXHAUSTED,
   101  			"end i=1",
   102  		},
   103  		"TestBreak1":                []string{"[1 2 -1 1 2 -2 1 2 -3]"},
   104  		"TestBreak2":                []string{"[1 2 -1 1 2 -2 1 2 -3]"},
   105  		"TestContinue":              []string{"[-1 1 2 -2 1 2 -3 1 2 -4]"},
   106  		"TestBreak3":                []string{"[100 10 2 4 200 10 2 4 20 2 4 300 10 2 4 20 2 4 30]"},
   107  		"TestBreak1BadA":            []string{"[1 2 -1 1 2 -2 1 2 -3]", RERR_DONE},
   108  		"TestBreak1BadB":            []string{"[1 2]", RERR_DONE},
   109  		"TestMultiCont0":            []string{"[1000 10 2 4 2000]"},
   110  		"TestMultiCont1":            []string{"[1000 10 2 4]", RERR_DONE},
   111  		"TestMultiCont2":            []string{"[1000 10 2 4]", RERR_DONE},
   112  		"TestMultiCont3":            []string{"[1000 10 2 4]", RERR_DONE},
   113  		"TestMultiBreak0":           []string{"[1000 10 2 4]", RERR_DONE},
   114  		"TestMultiBreak1":           []string{"[1000 10 2 4]", RERR_DONE},
   115  		"TestMultiBreak2":           []string{"[1000 10 2 4]", RERR_DONE},
   116  		"TestMultiBreak3":           []string{"[1000 10 2 4]", RERR_DONE},
   117  		"TestPanickyIterator1":      []string{panickyIterMsg},
   118  		"TestPanickyIterator1Check": []string{panickyIterMsg},
   119  		"TestPanickyIterator2":      []string{RERR_MISSING},
   120  		"TestPanickyIterator2Check": []string{CERR_MISSING},
   121  		"TestPanickyIterator3":      []string{"[100 10 1 2 200 10 1 2]"},
   122  		"TestPanickyIterator3Check": []string{"[100 10 1 2 200 10 1 2]"},
   123  		"TestPanickyIterator4":      []string{RERR_MISSING},
   124  		"TestPanickyIterator4Check": []string{CERR_MISSING},
   125  		"TestVeryBad1":              []string{"[1 10]"},
   126  		"TestVeryBad2":              []string{"[1 10]"},
   127  		"TestVeryBadCheck":          []string{"[1 10]"},
   128  		"TestOk":                    []string{"[1 10]"},
   129  		"TestBreak1BadDefer":        []string{RERR_DONE, "[1 2 -1 1 2 -2 1 2 -3 -30 -20 -10]"},
   130  		"TestReturns":               []string{"[-1 1 2 -10]", "[-1 1 2 -10]", RERR_DONE, "[-1 1 2 -10]", RERR_DONE},
   131  		"TestGotoA":                 []string{"testGotoA1[-1 1 2 -2 1 2 -3 1 2 -4 -30 -20 -10]", "testGotoA2[-1 1 2 -2 1 2 -3 1 2 -4 -30 -20 -10]", RERR_DONE, "testGotoA3[-1 1 2 -10]", RERR_DONE},
   132  		"TestGotoB":                 []string{"testGotoB1[-1 1 2 999 -10]", "testGotoB2[-1 1 2 -10]", RERR_DONE, "testGotoB3[-1 1 2 -10]", RERR_DONE},
   133  		"TestPanicReturns": []string{
   134  			"Got expected 'f return'",
   135  			"Got expected 'g return'",
   136  			"Got expected 'h return'",
   137  			"Got expected 'k return'",
   138  			"Got expected 'j return'",
   139  			"Got expected 'm return'",
   140  			"Got expected 'n return and n closure return'",
   141  		},
   142  	}
   143  	got := make(map[string][]string)
   144  	for _, ln := range bytes.Split(out, []byte("\n")) {
   145  		if ind := bytes.Index(ln, []byte(" \t ")); ind >= 0 {
   146  			n, m := string(ln[:ind]), string(ln[ind+3:])
   147  			got[n] = append(got[n], m)
   148  		}
   149  	}
   150  	for n, es := range expected {
   151  		if gs := got[n]; !reflect.DeepEqual(es, gs) {
   152  			t.Errorf("Output of test %s did not match expected output %v. got %v", n, es, gs)
   153  		}
   154  	}
   155  	for n, gs := range got {
   156  		if expected[n] == nil {
   157  			t.Errorf("No expected output for test %s. got %v", n, gs)
   158  		}
   159  	}
   160  
   161  	var exitcode int
   162  	if err, ok := err.(*exec.ExitError); ok {
   163  		exitcode = err.ExitCode()
   164  	}
   165  	const want = 0
   166  	if exitcode != want {
   167  		t.Errorf("exited %d, want %d", exitcode, want)
   168  	}
   169  }
   170  
   171  func testRangeFunc(t *testing.T) {
   172  	goroot := makeGoroot(t)
   173  	cwd, err := os.Getwd()
   174  	if err != nil {
   175  		log.Fatal(err)
   176  	}
   177  
   178  	input := "rangefunc.go"
   179  	run(t, filepath.Join(cwd, "testdata", input), goroot)
   180  }