github.com/switchupcb/yaegi@v0.10.2/interp/interp_eval_test.go (about)

     1  package interp_test
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"log"
    11  	"net/http"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"runtime"
    16  	"strconv"
    17  	"strings"
    18  	"sync"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/switchupcb/yaegi/interp"
    23  	"github.com/switchupcb/yaegi/stdlib"
    24  )
    25  
    26  func init() { log.SetFlags(log.Lshortfile) }
    27  
    28  // testCase represents an interpreter test case.
    29  // Care must be taken when defining multiple test cases within the same interpreter
    30  // context, as all declarations occur in the global scope and are therefore
    31  // shared between multiple test cases.
    32  // Hint: use different variables or package names in testcases to keep them uncoupled.
    33  type testCase struct {
    34  	desc, src, res, err string
    35  	skip                string // if not empty, skip this test case (used in case of known error)
    36  	pre                 func() // functions to execute prior eval src, or nil
    37  }
    38  
    39  func TestEvalArithmetic(t *testing.T) {
    40  	i := interp.New(interp.Options{})
    41  	runTests(t, i, []testCase{
    42  		{desc: "add_II", src: "2 + 3", res: "5"},
    43  		{desc: "add_FI", src: "2.3 + 3", res: "5.3"},
    44  		{desc: "add_IF", src: "2 + 3.3", res: "5.3"},
    45  		{desc: "add_SS", src: `"foo" + "bar"`, res: "foobar"},
    46  		{desc: "add_SI", src: `"foo" + 1`, err: "1:28: invalid operation: mismatched types untyped string and untyped int"},
    47  		{desc: "sub_SS", src: `"foo" - "bar"`, err: "1:28: invalid operation: operator - not defined on untyped string"},
    48  		{desc: "sub_II", src: "7 - 3", res: "4"},
    49  		{desc: "sub_FI", src: "7.2 - 3", res: "4.2"},
    50  		{desc: "sub_IF", src: "7 - 3.2", res: "3.8"},
    51  		{desc: "mul_II", src: "2 * 3", res: "6"},
    52  		{desc: "mul_FI", src: "2.2 * 3", res: "6.6"},
    53  		{desc: "mul_IF", src: "3 * 2.2", res: "6.6"},
    54  		{desc: "quo_Z", src: "3 / 0", err: "1:28: invalid operation: division by zero"},
    55  		{desc: "rem_FI", src: "8.2 % 4", err: "1:28: invalid operation: operator % not defined on untyped float"},
    56  		{desc: "rem_Z", src: "8 % 0", err: "1:28: invalid operation: division by zero"},
    57  		{desc: "shl_II", src: "1 << 8", res: "256"},
    58  		{desc: "shl_IN", src: "1 << -1", err: "1:28: invalid operation: shift count type untyped int, must be integer"},
    59  		{desc: "shl_IF", src: "1 << 1.0", res: "2"},
    60  		{desc: "shl_IF1", src: "1 << 1.1", err: "1:28: invalid operation: shift count type untyped float, must be integer"},
    61  		{desc: "shl_IF2", src: "1.0 << 1", res: "2"},
    62  		{desc: "shr_II", src: "1 >> 8", res: "0"},
    63  		{desc: "shr_IN", src: "1 >> -1", err: "1:28: invalid operation: shift count type untyped int, must be integer"},
    64  		{desc: "shr_IF", src: "1 >> 1.0", res: "0"},
    65  		{desc: "shr_IF1", src: "1 >> 1.1", err: "1:28: invalid operation: shift count type untyped float, must be integer"},
    66  		{desc: "neg_I", src: "-2", res: "-2"},
    67  		{desc: "pos_I", src: "+2", res: "2"},
    68  		{desc: "bitnot_I", src: "^2", res: "-3"},
    69  		{desc: "bitnot_F", src: "^0.2", err: "1:28: invalid operation: operator ^ not defined on untyped float"},
    70  		{desc: "not_B", src: "!false", res: "true"},
    71  		{desc: "not_I", src: "!0", err: "1:28: invalid operation: operator ! not defined on untyped int"},
    72  	})
    73  }
    74  
    75  func TestEvalShift(t *testing.T) {
    76  	i := interp.New(interp.Options{})
    77  	runTests(t, i, []testCase{
    78  		{src: "a, b, m := uint32(1), uint32(2), uint32(0); m = a + (1 << b)", res: "5"},
    79  		{src: "c := uint(1); d := uint64(+(-(1 << c)))", res: "18446744073709551614"},
    80  		{src: "e, f := uint32(0), uint32(0); f = 1 << -(e * 2)", res: "1"},
    81  		{src: "p := uint(0xdead); byte((1 << (p & 7)) - 1)", res: "31"},
    82  		{pre: func() { eval(t, i, "const k uint = 1 << 17") }, src: "int(k)", res: "131072"},
    83  	})
    84  }
    85  
    86  func TestOpVarConst(t *testing.T) {
    87  	i := interp.New(interp.Options{})
    88  	runTests(t, i, []testCase{
    89  		{pre: func() { eval(t, i, "const a uint = 8 + 2") }, src: "a", res: "10"},
    90  		{src: "b := uint(5); a+b", res: "15"},
    91  		{src: "b := uint(5); b+a", res: "15"},
    92  		{src: "b := uint(5); b>a", res: "false"},
    93  		{src: "const maxlen = cap(aa); var aa = []int{1,2}", err: "1:20: constant definition loop"},
    94  	})
    95  }
    96  
    97  func TestEvalStar(t *testing.T) {
    98  	i := interp.New(interp.Options{})
    99  	runTests(t, i, []testCase{
   100  		{src: `a := &struct{A int}{1}; b := *a`, res: "{1}"},
   101  		{src: `a := struct{A int}{1}; b := *a`, err: "1:57: invalid operation: cannot indirect \"a\""},
   102  	})
   103  }
   104  
   105  func TestEvalAssign(t *testing.T) {
   106  	i := interp.New(interp.Options{})
   107  	if err := i.Use(interp.Exports{
   108  		"testpkg/testpkg": {
   109  			"val": reflect.ValueOf(int64(11)),
   110  		},
   111  	}); err != nil {
   112  		t.Fatal(err)
   113  	}
   114  
   115  	_, e := i.Eval(`import "testpkg"`)
   116  	if e != nil {
   117  		t.Fatal(e)
   118  	}
   119  
   120  	runTests(t, i, []testCase{
   121  		{src: `a := "Hello"; a += " world"`, res: "Hello world"},
   122  		{src: `b := "Hello"; b += 1`, err: "1:42: invalid operation: mismatched types string and untyped int"},
   123  		{src: `c := "Hello"; c -= " world"`, err: "1:42: invalid operation: operator -= not defined on string"},
   124  		{src: "e := 64.4; e %= 64", err: "1:39: invalid operation: operator %= not defined on float64"},
   125  		{src: "f := int64(3.2)", err: "1:39: cannot convert expression of type untyped float to type int64"},
   126  		{src: "g := 1; g <<= 8", res: "256"},
   127  		{src: "h := 1; h >>= 8", res: "0"},
   128  		{src: "i := 1; j := &i; (*j) = 2", res: "2"},
   129  		{src: "i64 := testpkg.val; i64 == 11", res: "true"},
   130  		{pre: func() { eval(t, i, "k := 1") }, src: `k := "Hello world"`, res: "Hello world"}, // allow reassignment in subsequent evaluations
   131  	})
   132  }
   133  
   134  func TestEvalBuiltin(t *testing.T) {
   135  	i := interp.New(interp.Options{})
   136  	runTests(t, i, []testCase{
   137  		{src: `a := []int{}; a = append(a, 1); a`, res: "[1]"},
   138  		{src: `b := []int{1}; b = append(a, 2, 3); b`, res: "[1 2 3]"},
   139  		{src: `c := []int{1}; d := []int{2, 3}; c = append(c, d...); c`, res: "[1 2 3]"},
   140  		{src: `string(append([]byte("hello "), "world"...))`, res: "hello world"},
   141  		{src: `e := "world"; string(append([]byte("hello "), e...))`, res: "hello world"},
   142  		{src: `b := []int{1}; b = append(1, 2, 3); b`, err: "1:54: first argument to append must be slice; have untyped int"},
   143  		{src: `a1 := []int{0,1,2}; append(a1)`, res: "[0 1 2]"},
   144  		{src: `append(nil)`, err: "first argument to append must be slice; have nil"},
   145  		{src: `g := len(a)`, res: "1"},
   146  		{src: `g := cap(a)`, res: "1"},
   147  		{src: `g := len("test")`, res: "4"},
   148  		{src: `g := len(map[string]string{"a": "b"})`, res: "1"},
   149  		{src: `n := len()`, err: "not enough arguments in call to len"},
   150  		{src: `n := len([]int, 0)`, err: "too many arguments for len"},
   151  		{src: `g := cap("test")`, err: "1:37: invalid argument for cap"},
   152  		{src: `g := cap(map[string]string{"a": "b"})`, err: "1:37: invalid argument for cap"},
   153  		{src: `h := make(chan int, 1); close(h); len(h)`, res: "0"},
   154  		{src: `close(a)`, err: "1:34: invalid operation: non-chan type []int"},
   155  		{src: `h := make(chan int, 1); var i <-chan int = h; close(i)`, err: "1:80: invalid operation: cannot close receive-only channel"},
   156  		{src: `j := make([]int, 2)`, res: "[0 0]"},
   157  		{src: `j := make([]int, 2, 3)`, res: "[0 0]"},
   158  		{src: `j := make(int)`, err: "1:38: cannot make int; type must be slice, map, or channel"},
   159  		{src: `j := make([]int)`, err: "1:33: not enough arguments in call to make"},
   160  		{src: `j := make([]int, 0, 1, 2)`, err: "1:33: too many arguments for make"},
   161  		{src: `j := make([]int, 2, 1)`, err: "1:33: len larger than cap in make"},
   162  		{src: `j := make([]int, "test")`, err: "1:45: cannot convert \"test\" to int"},
   163  		{src: `k := []int{3, 4}; copy(k, []int{1,2}); k`, res: "[1 2]"},
   164  		{src: `f := []byte("Hello"); copy(f, "world"); string(f)`, res: "world"},
   165  		{src: `copy(g, g)`, err: "1:28: copy expects slice arguments"},
   166  		{src: `copy(a, "world")`, err: "1:28: arguments to copy have different element types []int and untyped string"},
   167  		{src: `l := map[string]int{"a": 1, "b": 2}; delete(l, "a"); l`, res: "map[b:2]"},
   168  		{src: `delete(a, 1)`, err: "1:35: first argument to delete must be map; have []int"},
   169  		{src: `l := map[string]int{"a": 1, "b": 2}; delete(l, 1)`, err: "1:75: cannot use untyped int as type string in delete"},
   170  		{src: `a := []int{1,2}; println(a...)`, err: "invalid use of ... with builtin println"},
   171  		{src: `m := complex(3, 2); real(m)`, res: "3"},
   172  		{src: `m := complex(3, 2); imag(m)`, res: "2"},
   173  		{src: `m := complex("test", 2)`, err: "1:33: invalid types string and int"},
   174  		{src: `imag("test")`, err: "1:33: cannot convert \"test\" to complex128"},
   175  		{src: `imag(a)`, err: "1:33: invalid argument type []int for imag"},
   176  		{src: `real(a)`, err: "1:33: invalid argument type []int for real"},
   177  		{src: `t := map[int]int{}; t[123]++; t`, res: "map[123:1]"},
   178  		{src: `t := map[int]int{}; t[123]--; t`, res: "map[123:-1]"},
   179  		{src: `t := map[int]int{}; t[123] += 1; t`, res: "map[123:1]"},
   180  		{src: `t := map[int]int{}; t[123] -= 1; t`, res: "map[123:-1]"},
   181  	})
   182  }
   183  
   184  func TestEvalDecl(t *testing.T) {
   185  	i := interp.New(interp.Options{})
   186  	runTests(t, i, []testCase{
   187  		{pre: func() { eval(t, i, "var i int = 2") }, src: "i", res: "2"},
   188  		{pre: func() { eval(t, i, "var j, k int = 2, 3") }, src: "j", res: "2"},
   189  		{pre: func() { eval(t, i, "var l, m int = 2, 3") }, src: "k", res: "3"},
   190  		{pre: func() { eval(t, i, "func f() int {return 4}") }, src: "f()", res: "4"},
   191  		{pre: func() { eval(t, i, `package foo; var I = 2`) }, src: "foo.I", res: "2"},
   192  		{pre: func() { eval(t, i, `package foo; func F() int {return 5}`) }, src: "foo.F()", res: "5"},
   193  	})
   194  }
   195  
   196  func TestEvalDeclWithExpr(t *testing.T) {
   197  	i := interp.New(interp.Options{})
   198  	runTests(t, i, []testCase{
   199  		{src: `a1 := ""; var a2 int; a2 = 2`, res: "2"},
   200  		{src: `b1 := ""; const b2 = 2; b2`, res: "2"},
   201  		{src: `c1 := ""; var c2, c3 [8]byte; c3[3]`, res: "0"},
   202  	})
   203  }
   204  
   205  func TestEvalFunc(t *testing.T) {
   206  	i := interp.New(interp.Options{})
   207  	runTests(t, i, []testCase{
   208  		{src: `(func () string {return "ok"})()`, res: "ok"},
   209  		{src: `(func () (res string) {res = "ok"; return})()`, res: "ok"},
   210  		{src: `(func () int {f := func() (a, b int) {a, b = 3, 4; return}; x, y := f(); return x+y})()`, res: "7"},
   211  		{src: `(func () int {f := func() (a int, b, c int) {a, b, c = 3, 4, 5; return}; x, y, z := f(); return x+y+z})()`, res: "12"},
   212  		{src: `(func () int {f := func() (a, b, c int) {a, b, c = 3, 4, 5; return}; x, y, z := f(); return x+y+z})()`, res: "12"},
   213  	})
   214  }
   215  
   216  func TestEvalImport(t *testing.T) {
   217  	i := interp.New(interp.Options{})
   218  	if err := i.Use(stdlib.Symbols); err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	runTests(t, i, []testCase{
   222  		{pre: func() { eval(t, i, `import "time"`) }, src: "2 * time.Second", res: "2s"},
   223  	})
   224  }
   225  
   226  func TestEvalStdout(t *testing.T) {
   227  	var out, err bytes.Buffer
   228  	i := interp.New(interp.Options{Stdout: &out, Stderr: &err})
   229  	if err := i.Use(stdlib.Symbols); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	_, e := i.Eval(`import "fmt"; func main() { fmt.Println("hello") }`)
   233  	if e != nil {
   234  		t.Fatal(e)
   235  	}
   236  	wanted := "hello\n"
   237  	if res := out.String(); res != wanted {
   238  		t.Fatalf("got %v, want %v", res, wanted)
   239  	}
   240  }
   241  
   242  func TestEvalNil(t *testing.T) {
   243  	i := interp.New(interp.Options{})
   244  	if err := i.Use(stdlib.Symbols); err != nil {
   245  		t.Fatal(err)
   246  	}
   247  	runTests(t, i, []testCase{
   248  		{desc: "assign nil", src: "a := nil", err: "1:33: use of untyped nil"},
   249  		{desc: "return nil", pre: func() { eval(t, i, "func getNil() error {return nil}") }, src: "getNil()", res: "<nil>"},
   250  		{
   251  			desc: "return func which return error",
   252  			pre: func() {
   253  				eval(t, i, `
   254  					package bar
   255  
   256  					func New() func(string) error {
   257  						return func(v string) error {
   258  							return nil
   259  						}
   260  					}
   261  				`)
   262  				v := eval(t, i, `bar.New()`)
   263  				fn, ok := v.Interface().(func(string) error)
   264  				if !ok {
   265  					t.Fatal("conversion failed")
   266  				}
   267  				if res := fn("hello"); res != nil {
   268  					t.Fatalf("got %v, want nil", res)
   269  				}
   270  			},
   271  		},
   272  		{
   273  			desc: "return nil pointer",
   274  			pre: func() {
   275  				eval(t, i, `
   276  					import "fmt"
   277  
   278  					type Foo struct{}
   279  
   280  					func Hello() *Foo {
   281  						fmt.Println("Hello")
   282  						return nil
   283  					}
   284  				`)
   285  			},
   286  			src: "Hello()",
   287  			res: "<nil>",
   288  		},
   289  		{
   290  			desc: "return nil func",
   291  			pre: func() {
   292  				eval(t, i, `func Bar() func() { return nil }`)
   293  			},
   294  			src: "Bar()",
   295  			res: "<nil>",
   296  		},
   297  	})
   298  }
   299  
   300  func TestEvalStruct0(t *testing.T) {
   301  	i := interp.New(interp.Options{})
   302  	runTests(t, i, []testCase{
   303  		{
   304  			desc: "func field in struct",
   305  			pre: func() {
   306  				eval(t, i, `
   307  					type Fromage struct {
   308  						Name string
   309  						Call func(string) string
   310  					}
   311  
   312  					func f() string {
   313  						a := Fromage{}
   314  						a.Name = "test"
   315  						a.Call = func(s string) string { return s }
   316  
   317  						return a.Call(a.Name)
   318  					}
   319  				`)
   320  			},
   321  			src: "f()",
   322  			res: "test",
   323  		},
   324  		{
   325  			desc: "literal func field in struct",
   326  			pre: func() {
   327  				eval(t, i, `
   328  					type Fromage2 struct {
   329  						Name string
   330  						Call func(string) string
   331  					}
   332  
   333  					func f2() string {
   334  						a := Fromage2{
   335  							"test",
   336  							func(s string) string { return s },
   337  						}
   338  						return a.Call(a.Name)
   339  					}
   340  				`)
   341  			},
   342  			src: "f2()",
   343  			res: "test",
   344  		},
   345  	})
   346  }
   347  
   348  func TestEvalStruct1(t *testing.T) {
   349  	i := interp.New(interp.Options{})
   350  	eval(t, i, `
   351  type Fromage struct {
   352  	Name string
   353  	Call func(string) string
   354  }
   355  
   356  func f() string {
   357  	a := Fromage{
   358  		"test",
   359  		func(s string) string { return s },
   360  	}
   361  
   362  	return a.Call(a.Name)
   363  }
   364  `)
   365  
   366  	v := eval(t, i, `f()`)
   367  	if v.Interface().(string) != "test" {
   368  		t.Fatalf("got %v, want test", v)
   369  	}
   370  }
   371  
   372  func TestEvalComposite0(t *testing.T) {
   373  	i := interp.New(interp.Options{})
   374  	eval(t, i, `
   375  type T struct {
   376  	a, b, c, d, e, f, g, h, i, j, k, l, m, n string
   377  	o map[string]int
   378  	p []string
   379  }
   380  
   381  var a = T{
   382  	o: map[string]int{"truc": 1, "machin": 2},
   383  	p: []string{"hello", "world"},
   384  }
   385  `)
   386  	v := eval(t, i, `a.p[1]`)
   387  	if v.Interface().(string) != "world" {
   388  		t.Fatalf("got %v, want word", v)
   389  	}
   390  }
   391  
   392  func TestEvalCompositeBin0(t *testing.T) {
   393  	i := interp.New(interp.Options{})
   394  	if err := i.Use(stdlib.Symbols); err != nil {
   395  		t.Fatal(err)
   396  	}
   397  	eval(t, i, `
   398  import (
   399  	"fmt"
   400  	"net/http"
   401  	"time"
   402  )
   403  
   404  func Foo() {
   405  	http.DefaultClient = &http.Client{Timeout: 2 * time.Second}
   406  }
   407  `)
   408  	http.DefaultClient = &http.Client{}
   409  	eval(t, i, `Foo()`)
   410  	if http.DefaultClient.Timeout != 2*time.Second {
   411  		t.Fatalf("got %v, want 2s", http.DefaultClient.Timeout)
   412  	}
   413  }
   414  
   415  func TestEvalComparison(t *testing.T) {
   416  	i := interp.New(interp.Options{})
   417  	runTests(t, i, []testCase{
   418  		{src: `2 > 1`, res: "true"},
   419  		{src: `1.2 > 1.1`, res: "true"},
   420  		{src: `"hhh" > "ggg"`, res: "true"},
   421  		{
   422  			desc: "mismatched types",
   423  			src: `
   424  				type Foo string
   425  				type Bar string
   426  
   427  				var a = Foo("test")
   428  				var b = Bar("test")
   429  				var c = a == b
   430  			`,
   431  			err: "7:13: invalid operation: mismatched types main.Foo and main.Bar",
   432  		},
   433  	})
   434  }
   435  
   436  func TestEvalCompositeArray(t *testing.T) {
   437  	i := interp.New(interp.Options{})
   438  	eval(t, i, `const l = 10`)
   439  	runTests(t, i, []testCase{
   440  		{src: "a := []int{1, 2, 7: 20, 30}", res: "[1 2 0 0 0 0 0 20 30]"},
   441  		{src: `a := []int{1, 1.2}`, err: "1:42: 6/5 truncated to int"},
   442  		{src: `a := []int{0:1, 0:1}`, err: "1:46: duplicate index 0 in array or slice literal"},
   443  		{src: `a := []int{1.1:1, 1.2:"test"}`, err: "1:39: index untyped float must be integer constant"},
   444  		{src: `a := [2]int{1, 1.2}`, err: "1:43: 6/5 truncated to int"},
   445  		{src: `a := [1]int{1, 2}`, err: "1:43: index 1 is out of bounds (>= 1)"},
   446  		{src: `b := [l]int{1, 2}`, res: "[1 2 0 0 0 0 0 0 0 0]"},
   447  		{src: `i := 10; a := [i]int{1, 2}`, err: "1:43: non-constant array bound \"i\""},
   448  		{src: `c := [...]float64{1, 3: 3.4, 5}`, res: "[1 0 0 3.4 5]"},
   449  	})
   450  }
   451  
   452  func TestEvalCompositeMap(t *testing.T) {
   453  	i := interp.New(interp.Options{})
   454  	runTests(t, i, []testCase{
   455  		{src: `a := map[string]int{"one":1, "two":2}`, res: "map[one:1 two:2]"},
   456  		{src: `a := map[string]int{1:1, 2:2}`, err: "1:48: cannot convert 1 to string"},
   457  		{src: `a := map[string]int{"one":1, "two":2.2}`, err: "1:63: 11/5 truncated to int"},
   458  		{src: `a := map[string]int{1, "two":2}`, err: "1:48: missing key in map literal"},
   459  		{src: `a := map[string]int{"one":1, "one":2}`, err: "1:57: duplicate key one in map literal"},
   460  	})
   461  }
   462  
   463  func TestEvalCompositeStruct(t *testing.T) {
   464  	i := interp.New(interp.Options{})
   465  	runTests(t, i, []testCase{
   466  		{src: `a := struct{A,B,C int}{}`, res: "{0 0 0}"},
   467  		{src: `a := struct{A,B,C int}{1,2,3}`, res: "{1 2 3}"},
   468  		{src: `a := struct{A,B,C int}{1,2.2,3}`, err: "1:53: 11/5 truncated to int"},
   469  		{src: `a := struct{A,B,C int}{1,2}`, err: "1:53: too few values in struct literal"},
   470  		{src: `a := struct{A,B,C int}{1,2,3,4}`, err: "1:57: too many values in struct literal"},
   471  		{src: `a := struct{A,B,C int}{1,B:2,3}`, err: "1:53: mixture of field:value and value elements in struct literal"},
   472  		{src: `a := struct{A,B,C int}{A:1,B:2,C:3}`, res: "{1 2 3}"},
   473  		{src: `a := struct{A,B,C int}{B:2}`, res: "{0 2 0}"},
   474  		{src: `a := struct{A,B,C int}{A:1,D:2,C:3}`, err: "1:55: unknown field D in struct literal"},
   475  		{src: `a := struct{A,B,C int}{A:1,A:2,C:3}`, err: "1:55: duplicate field name A in struct literal"},
   476  		{src: `a := struct{A,B,C int}{A:1,B:2.2,C:3}`, err: "1:57: 11/5 truncated to int"},
   477  		{src: `a := struct{A,B,C int}{A:1,2,C:3}`, err: "1:55: mixture of field:value and value elements in struct literal"},
   478  	})
   479  }
   480  
   481  func TestEvalSliceExpression(t *testing.T) {
   482  	i := interp.New(interp.Options{})
   483  	runTests(t, i, []testCase{
   484  		{src: `a := []int{0,1,2}[1:3]`, res: "[1 2]"},
   485  		{src: `a := []int{0,1,2}[:3]`, res: "[0 1 2]"},
   486  		{src: `a := []int{0,1,2}[:]`, res: "[0 1 2]"},
   487  		{src: `a := []int{0,1,2,3}[1:3:4]`, res: "[1 2]"},
   488  		{src: `a := []int{0,1,2,3}[:3:4]`, res: "[0 1 2]"},
   489  		{src: `ar := [3]int{0,1,2}; a := ar[1:3]`, res: "[1 2]"},
   490  		{src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"},
   491  		{src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"},
   492  		{src: `s := "hello"[1:3]`, res: "el"},
   493  		{src: `str := "hello"; s := str[1:3]`, res: "el"},
   494  		{src: `a := int(1)[0:1]`, err: "1:33: cannot slice type int"},
   495  		{src: `a := (&[]int{0,1,2,3})[1:3]`, err: "1:33: cannot slice type *[]int"},
   496  		{src: `a := "hello"[1:3:4]`, err: "1:45: invalid operation: 3-index slice of string"},
   497  		{src: `ar := [3]int{0,1,2}; a := ar[:4]`, err: "1:58: index int is out of bounds"},
   498  		{src: `a := []int{0,1,2,3}[1::4]`, err: "1:49: 2nd index required in 3-index slice"},
   499  		{src: `a := []int{0,1,2,3}[1:3:]`, err: "1:51: 3rd index required in 3-index slice"},
   500  		{src: `a := []int{0,1,2}[3:1]`, err: "invalid index values, must be low <= high <= max"},
   501  		{pre: func() { eval(t, i, `type Str = string; var r Str = "truc"`) }, src: `r[1]`, res: "114"},
   502  	})
   503  }
   504  
   505  func TestEvalConversion(t *testing.T) {
   506  	i := interp.New(interp.Options{})
   507  	runTests(t, i, []testCase{
   508  		{src: `a := uint64(1)`, res: "1"},
   509  		{src: `i := 1.1; a := uint64(i)`, res: "1"},
   510  		{src: `b := string(49)`, res: "1"},
   511  		{src: `c := uint64(1.1)`, err: "1:40: cannot convert expression of type untyped float to type uint64"},
   512  	})
   513  }
   514  
   515  func TestEvalUnary(t *testing.T) {
   516  	i := interp.New(interp.Options{})
   517  	runTests(t, i, []testCase{
   518  		{src: "a := -1", res: "-1"},
   519  		{src: "b := +1", res: "1", skip: "BUG"},
   520  		{src: "c := !false", res: "true"},
   521  	})
   522  }
   523  
   524  func TestEvalMethod(t *testing.T) {
   525  	i := interp.New(interp.Options{})
   526  	eval(t, i, `
   527  		type Root struct {
   528  			Name string
   529  		}
   530  
   531  		type One struct {
   532  			Root
   533  		}
   534  
   535  		type Hi interface {
   536  			Hello() string
   537  		}
   538  
   539  		type Hey interface {
   540  			Hello() string
   541  		}
   542  
   543  		func (r *Root) Hello() string { return "Hello " + r.Name }
   544  
   545  		var r = Root{"R"}
   546  		var o = One{r}
   547  		// TODO(mpl): restore empty interfaces when type assertions work (again) on them.
   548  		// var root interface{} = &Root{Name: "test1"}
   549  		// var one interface{} = &One{Root{Name: "test2"}}
   550  		var root Hey = &Root{Name: "test1"}
   551  		var one Hey = &One{Root{Name: "test2"}}
   552  	`)
   553  	runTests(t, i, []testCase{
   554  		{src: "r.Hello()", res: "Hello R"},
   555  		{src: "(&r).Hello()", res: "Hello R"},
   556  		{src: "o.Hello()", res: "Hello R"},
   557  		{src: "(&o).Hello()", res: "Hello R"},
   558  		{src: "root.(Hi).Hello()", res: "Hello test1"},
   559  		{src: "one.(Hi).Hello()", res: "Hello test2"},
   560  	})
   561  }
   562  
   563  func TestEvalChan(t *testing.T) {
   564  	i := interp.New(interp.Options{})
   565  	runTests(t, i, []testCase{
   566  		{
   567  			src: `(func () string {
   568  				messages := make(chan string)
   569  				go func() { messages <- "ping" }()
   570  				msg := <-messages
   571  				return msg
   572  			})()`, res: "ping",
   573  		},
   574  		{
   575  			src: `(func () bool {
   576  				messages := make(chan string)
   577  				go func() { messages <- "ping" }()
   578  				msg, ok := <-messages
   579  				return ok && msg == "ping"
   580  			})()`, res: "true",
   581  		},
   582  		{
   583  			src: `(func () bool {
   584  				messages := make(chan string)
   585  				go func() { messages <- "ping" }()
   586  				var msg string
   587  				var ok bool
   588  				msg, ok = <-messages
   589  				return ok && msg == "ping"
   590  			})()`, res: "true",
   591  		},
   592  	})
   593  }
   594  
   595  func TestEvalFunctionCallWithFunctionParam(t *testing.T) {
   596  	i := interp.New(interp.Options{})
   597  	eval(t, i, `
   598  		func Bar(s string, fn func(string)string) string { return fn(s) }
   599  	`)
   600  
   601  	v := eval(t, i, "Bar")
   602  	bar := v.Interface().(func(string, func(string) string) string)
   603  
   604  	got := bar("hello ", func(s string) string {
   605  		return s + "world!"
   606  	})
   607  
   608  	want := "hello world!"
   609  	if got != want {
   610  		t.Errorf("unexpected result of function eval: got %q, want %q", got, want)
   611  	}
   612  }
   613  
   614  func TestEvalCall(t *testing.T) {
   615  	i := interp.New(interp.Options{})
   616  	runTests(t, i, []testCase{
   617  		{src: ` test := func(a int, b float64) int { return a }
   618  				a := test(1, 2.3)`, res: "1"},
   619  		{src: ` test := func(a int, b float64) int { return a }
   620  				a := test(1)`, err: "2:10: not enough arguments in call to test"},
   621  		{src: ` test := func(a int, b float64) int { return a }
   622  				s := "test"
   623  				a := test(1, s)`, err: "3:18: cannot use type string as type float64"},
   624  		{src: ` test := func(a ...int) int { return 1 }
   625  				a := test([]int{1}...)`, res: "1"},
   626  		{src: ` test := func(a ...int) int { return 1 }
   627  				a := test()`, res: "1"},
   628  		{src: ` test := func(a ...int) int { return 1 }
   629  				blah := func() []int { return []int{1,1} }
   630  				a := test(blah()...)`, res: "1"},
   631  		{src: ` test := func(a ...int) int { return 1 }
   632  				a := test([]string{"1"}...)`, err: "2:15: cannot use []string as type []int"},
   633  		{src: ` test := func(a ...int) int { return 1 }
   634  				i := 1
   635  				a := test(i...)`, err: "3:15: cannot use int as type []int"},
   636  		{src: ` test := func(a int) int { return a }
   637  				a := test([]int{1}...)`, err: "2:10: invalid use of ..., corresponding parameter is non-variadic"},
   638  		{src: ` test := func(a ...int) int { return 1 }
   639  				blah := func() (int, int) { return 1, 1 }
   640  				a := test(blah()...)`, err: "3:15: cannot use ... with 2-valued func() (int,int)"},
   641  		{src: ` test := func(a, b int) int { return a }
   642  				blah := func() (int, int) { return 1, 1 }
   643  				a := test(blah())`, res: "1"},
   644  		{src: ` test := func(a, b int) int { return a }
   645  				blah := func() int { return 1 }
   646  				a := test(blah(), blah())`, res: "1"},
   647  		{src: ` test := func(a, b, c, d int) int { return a }
   648  				blah := func() (int, int) { return 1, 1 }
   649  				a := test(blah(), blah())`, err: "3:15: cannot use func() (int,int) as type int"},
   650  		{src: ` test := func(a, b int) int { return a }
   651  				blah := func() (int, float64) { return 1, 1.1 }
   652  				a := test(blah())`, err: "3:15: cannot use func() (int,float64) as type (int,int)"},
   653  	})
   654  }
   655  
   656  func TestEvalBinCall(t *testing.T) {
   657  	i := interp.New(interp.Options{})
   658  	if err := i.Use(stdlib.Symbols); err != nil {
   659  		t.Fatal(err)
   660  	}
   661  	if _, err := i.Eval(`import "fmt"`); err != nil {
   662  		t.Fatal(err)
   663  	}
   664  	runTests(t, i, []testCase{
   665  		{src: `a := fmt.Sprint(1, 2.3)`, res: "1 2.3"},
   666  		{src: `a := fmt.Sprintf()`, err: "1:33: not enough arguments in call to fmt.Sprintf"},
   667  		{src: `i := 1
   668  			   a := fmt.Sprintf(i)`, err: "2:24: cannot use type int as type string"},
   669  		{src: `a := fmt.Sprint()`, res: ""},
   670  	})
   671  }
   672  
   673  func TestEvalMissingSymbol(t *testing.T) {
   674  	defer func() {
   675  		r := recover()
   676  		if r != nil {
   677  			t.Errorf("unexpected panic: %v", r)
   678  		}
   679  	}()
   680  
   681  	type S2 struct{}
   682  	type S1 struct {
   683  		F S2
   684  	}
   685  	i := interp.New(interp.Options{})
   686  	if err := i.Use(interp.Exports{"p/p": map[string]reflect.Value{
   687  		"S1": reflect.Zero(reflect.TypeOf(&S1{})),
   688  	}}); err != nil {
   689  		t.Fatal(err)
   690  	}
   691  	_, err := i.Eval(`import "p"`)
   692  	if err != nil {
   693  		t.Fatalf("failed to import package: %v", err)
   694  	}
   695  	_, err = i.Eval(`p.S1{F: p.S2{}}`)
   696  	if err == nil {
   697  		t.Error("unexpected nil error for expression with undefined type")
   698  	}
   699  }
   700  
   701  func TestEvalWithContext(t *testing.T) {
   702  	tests := []testCase{
   703  		{
   704  			desc: "for {}",
   705  			src: `(func() {
   706  				      for {}
   707  			      })()`,
   708  		},
   709  		{
   710  			desc: "select {}",
   711  			src: `(func() {
   712  				     select {}
   713  			     })()`,
   714  		},
   715  		{
   716  			desc: "blocked chan send",
   717  			src: `(func() {
   718  			         c := make(chan int)
   719  				     c <- 1
   720  				 })()`,
   721  		},
   722  		{
   723  			desc: "blocked chan recv",
   724  			src: `(func() {
   725  			         c := make(chan int)
   726  				     <-c
   727  			     })()`,
   728  		},
   729  		{
   730  			desc: "blocked chan recv2",
   731  			src: `(func() {
   732  			         c := make(chan int)
   733  				     _, _ = <-c
   734  			     })()`,
   735  		},
   736  		{
   737  			desc: "blocked range chan",
   738  			src: `(func() {
   739  			         c := make(chan int)
   740  				     for range c {}
   741  			     })()`,
   742  		},
   743  		{
   744  			desc: "double lock",
   745  			src: `(func() {
   746  			         var mu sync.Mutex
   747  				     mu.Lock()
   748  				     mu.Lock()
   749  			      })()`,
   750  		},
   751  	}
   752  
   753  	for _, test := range tests {
   754  		done := make(chan struct{})
   755  		src := test.src
   756  		go func() {
   757  			defer close(done)
   758  			i := interp.New(interp.Options{})
   759  			if err := i.Use(stdlib.Symbols); err != nil {
   760  				t.Error(err)
   761  			}
   762  			_, err := i.Eval(`import "sync"`)
   763  			if err != nil {
   764  				t.Errorf(`failed to import "sync": %v`, err)
   765  				return
   766  			}
   767  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   768  			defer cancel()
   769  			_, err = i.EvalWithContext(ctx, src)
   770  			switch err {
   771  			case context.DeadlineExceeded:
   772  				// Successful cancellation.
   773  
   774  				// Check we can still execute an expression.
   775  				v, err := i.EvalWithContext(context.Background(), "1+1\n")
   776  				if err != nil {
   777  					t.Errorf("failed to evaluate expression after cancellation: %v", err)
   778  				}
   779  				got := v.Interface()
   780  				if got != 2 {
   781  					t.Errorf("unexpected result of eval(1+1): got %v, want 2", got)
   782  				}
   783  			case nil:
   784  				t.Errorf("unexpected success evaluating expression %q", test.desc)
   785  			default:
   786  				t.Errorf("failed to evaluate expression %q: %v", test.desc, err)
   787  			}
   788  		}()
   789  		select {
   790  		case <-time.After(time.Second):
   791  			t.Errorf("timeout failed to terminate execution of %q", test.desc)
   792  		case <-done:
   793  		}
   794  	}
   795  }
   796  
   797  func runTests(t *testing.T, i *interp.Interpreter, tests []testCase) {
   798  	t.Helper()
   799  
   800  	for _, test := range tests {
   801  		t.Run(test.desc, func(t *testing.T) {
   802  			if test.skip != "" {
   803  				t.Skip(test.skip)
   804  			}
   805  			if test.pre != nil {
   806  				test.pre()
   807  			}
   808  			if test.src != "" {
   809  				assertEval(t, i, test.src, test.err, test.res)
   810  			}
   811  		})
   812  	}
   813  }
   814  
   815  func eval(t *testing.T, i *interp.Interpreter, src string) reflect.Value {
   816  	t.Helper()
   817  	res, err := i.Eval(src)
   818  	if err != nil {
   819  		t.Logf("Error: %v", err)
   820  		if e, ok := err.(interp.Panic); ok {
   821  			t.Logf(string(e.Stack))
   822  		}
   823  		t.FailNow()
   824  	}
   825  	return res
   826  }
   827  
   828  func assertEval(t *testing.T, i *interp.Interpreter, src, expectedError, expectedRes string) {
   829  	t.Helper()
   830  
   831  	res, err := i.Eval(src)
   832  
   833  	if expectedError != "" {
   834  		if err == nil || !strings.Contains(err.Error(), expectedError) {
   835  			t.Fatalf("got %v, want %s", err, expectedError)
   836  		}
   837  		return
   838  	}
   839  
   840  	if err != nil {
   841  		t.Logf("got an error: %v", err)
   842  		if e, ok := err.(interp.Panic); ok {
   843  			t.Logf(string(e.Stack))
   844  		}
   845  		t.FailNow()
   846  	}
   847  
   848  	if fmt.Sprintf("%v", res) != expectedRes {
   849  		t.Fatalf("got %v, want %s", res, expectedRes)
   850  	}
   851  }
   852  
   853  func TestMultiEval(t *testing.T) {
   854  	t.Skip("fail in CI only ?")
   855  	// catch stdout
   856  	backupStdout := os.Stdout
   857  	defer func() {
   858  		os.Stdout = backupStdout
   859  	}()
   860  	r, w, _ := os.Pipe()
   861  	os.Stdout = w
   862  
   863  	i := interp.New(interp.Options{})
   864  	if err := i.Use(stdlib.Symbols); err != nil {
   865  		t.Fatal(err)
   866  	}
   867  
   868  	f, err := os.Open(filepath.Join("testdata", "multi", "731"))
   869  	if err != nil {
   870  		t.Fatal(err)
   871  	}
   872  	names, err := f.Readdirnames(-1)
   873  	if err != nil {
   874  		t.Fatal(err)
   875  	}
   876  	for _, v := range names {
   877  		if _, err := i.EvalPath(filepath.Join(f.Name(), v)); err != nil {
   878  			t.Fatal(err)
   879  		}
   880  	}
   881  
   882  	// read stdout
   883  	if err = w.Close(); err != nil {
   884  		t.Fatal(err)
   885  	}
   886  	outInterp, err := ioutil.ReadAll(r)
   887  	if err != nil {
   888  		t.Fatal(err)
   889  	}
   890  
   891  	// restore Stdout
   892  	os.Stdout = backupStdout
   893  
   894  	want := "A\nB\n"
   895  	got := string(outInterp)
   896  	if got != want {
   897  		t.Fatalf("unexpected output: got %v, wanted %v", got, want)
   898  	}
   899  }
   900  
   901  func TestMultiEvalNoName(t *testing.T) {
   902  	t.Skip("fail in CI only ?")
   903  	i := interp.New(interp.Options{})
   904  	if err := i.Use(stdlib.Symbols); err != nil {
   905  		t.Fatal(err)
   906  	}
   907  
   908  	f, err := os.Open(filepath.Join("testdata", "multi", "731"))
   909  	if err != nil {
   910  		t.Fatal(err)
   911  	}
   912  	names, err := f.Readdirnames(-1)
   913  	if err != nil {
   914  		t.Fatal(err)
   915  	}
   916  	for k, v := range names {
   917  		data, err := ioutil.ReadFile(filepath.Join(f.Name(), v))
   918  		if err != nil {
   919  			t.Fatal(err)
   920  		}
   921  		_, err = i.Eval(string(data))
   922  		if k == 1 {
   923  			expectedErr := fmt.Errorf("3:8: fmt/%s redeclared in this block", interp.DefaultSourceName)
   924  			if err == nil || err.Error() != expectedErr.Error() {
   925  				t.Fatalf("unexpected result; wanted error %v, got %v", expectedErr, err)
   926  			}
   927  			return
   928  		}
   929  		if err != nil {
   930  			t.Fatal(err)
   931  		}
   932  	}
   933  }
   934  
   935  const goMinorVersionTest = 16
   936  
   937  func TestHasIOFS(t *testing.T) {
   938  	code := `
   939  // +build go1.16
   940  
   941  package main
   942  
   943  import (
   944  	"errors"
   945  	"io/fs"
   946  )
   947  
   948  func main() {
   949  	pe := fs.PathError{}
   950  	pe.Op = "nothing"
   951  	pe.Path = "/nowhere"
   952  	pe.Err = errors.New("an error")
   953  	println(pe.Error())
   954  }
   955  
   956  // Output:
   957  // nothing /nowhere: an error
   958  `
   959  
   960  	var buf bytes.Buffer
   961  	i := interp.New(interp.Options{Stdout: &buf})
   962  	if err := i.Use(interp.Symbols); err != nil {
   963  		t.Fatal(err)
   964  	}
   965  	if err := i.Use(stdlib.Symbols); err != nil {
   966  		t.Fatal(err)
   967  	}
   968  
   969  	if _, err := i.Eval(code); err != nil {
   970  		t.Fatal(err)
   971  	}
   972  
   973  	var expectedOutput string
   974  	var minor int
   975  	var err error
   976  	version := runtime.Version()
   977  	fields := strings.Fields(version)
   978  	// Go stable
   979  	if len(fields) == 1 {
   980  		v := strings.Split(version, ".")
   981  		if len(v) < 2 {
   982  			t.Fatalf("unexpected: %v", version)
   983  		}
   984  		minor, err = strconv.Atoi(v[1])
   985  		if err != nil {
   986  			t.Fatal(err)
   987  		}
   988  	} else {
   989  		// Go devel
   990  		if fields[0] != "devel" {
   991  			t.Fatalf("unexpected: %v", fields[0])
   992  		}
   993  		parts := strings.Split(fields[1], "-")
   994  		if len(parts) != 2 {
   995  			t.Fatalf("unexpected: %v", fields[1])
   996  		}
   997  		minor, err = strconv.Atoi(strings.TrimPrefix(parts[0], "go1."))
   998  		if err != nil {
   999  			t.Fatal(err)
  1000  		}
  1001  	}
  1002  
  1003  	if minor >= goMinorVersionTest {
  1004  		expectedOutput = "nothing /nowhere: an error\n"
  1005  	}
  1006  
  1007  	output := buf.String()
  1008  	if buf.String() != expectedOutput {
  1009  		t.Fatalf("got: %v, wanted: %v", output, expectedOutput)
  1010  	}
  1011  }
  1012  
  1013  func TestImportPathIsKey(t *testing.T) {
  1014  	// No need to check the results of Eval, as TestFile already does it.
  1015  	i := interp.New(interp.Options{GoPath: filepath.FromSlash("../_test/testdata/redeclaration-global7")})
  1016  	if err := i.Use(stdlib.Symbols); err != nil {
  1017  		t.Fatal(err)
  1018  	}
  1019  
  1020  	filePath := filepath.Join("..", "_test", "ipp_as_key.go")
  1021  	if _, err := i.EvalPath(filePath); err != nil {
  1022  		t.Fatal(err)
  1023  	}
  1024  
  1025  	wantScopes := map[string][]string{
  1026  		"main": {
  1027  			"titi/ipp_as_key.go",
  1028  			"tutu/ipp_as_key.go",
  1029  			"main",
  1030  		},
  1031  		"guthib.com/toto": {
  1032  			"quux/titi.go",
  1033  			"Quux",
  1034  		},
  1035  		"guthib.com/bar": {
  1036  			"Quux",
  1037  		},
  1038  		"guthib.com/tata": {
  1039  			"quux/tutu.go",
  1040  			"Quux",
  1041  		},
  1042  		"guthib.com/baz": {
  1043  			"Quux",
  1044  		},
  1045  	}
  1046  	wantPackages := map[string]string{
  1047  		"guthib.com/baz":  "quux",
  1048  		"guthib.com/tata": "tutu",
  1049  		"main":            "main",
  1050  		"guthib.com/bar":  "quux",
  1051  		"guthib.com/toto": "titi",
  1052  	}
  1053  
  1054  	scopes := i.Scopes()
  1055  	if len(scopes) != len(wantScopes) {
  1056  		t.Fatalf("want %d, got %d", len(wantScopes), len(scopes))
  1057  	}
  1058  	for k, v := range scopes {
  1059  		wantSym := wantScopes[k]
  1060  		if len(v) != len(wantSym) {
  1061  			t.Fatalf("want %d, got %d", len(wantSym), len(v))
  1062  		}
  1063  		for _, sym := range wantSym {
  1064  			if _, ok := v[sym]; !ok {
  1065  				t.Fatalf("symbol %s not found in scope %s", sym, k)
  1066  			}
  1067  		}
  1068  	}
  1069  
  1070  	packages := i.Packages()
  1071  	for k, v := range wantPackages {
  1072  		pkg := packages[k]
  1073  		if pkg != v {
  1074  			t.Fatalf("for import path %s, want %s, got %s", k, v, pkg)
  1075  		}
  1076  	}
  1077  }
  1078  
  1079  // The code in hello1.go and hello2.go spawns a "long-running" goroutine, which
  1080  // means each call to EvalPath actually terminates before the evaled code is done
  1081  // running. So this test demonstrates:
  1082  // 1) That two sequential calls to EvalPath don't see their "compilation phases"
  1083  // collide (no data race on the fields of the interpreter), which is somewhat
  1084  // obvious since the calls (and hence the "compilation phases") are sequential too.
  1085  // 2) That two concurrent goroutine runs spawned by the same interpreter do not
  1086  // collide either.
  1087  func TestConcurrentEvals(t *testing.T) {
  1088  	if testing.Short() {
  1089  		return
  1090  	}
  1091  	pin, pout := io.Pipe()
  1092  	defer func() {
  1093  		_ = pin.Close()
  1094  		_ = pout.Close()
  1095  	}()
  1096  	interpr := interp.New(interp.Options{Stdout: pout})
  1097  	if err := interpr.Use(stdlib.Symbols); err != nil {
  1098  		t.Fatal(err)
  1099  	}
  1100  
  1101  	if _, err := interpr.EvalPath("testdata/concurrent/hello1.go"); err != nil {
  1102  		t.Fatal(err)
  1103  	}
  1104  	if _, err := interpr.EvalPath("testdata/concurrent/hello2.go"); err != nil {
  1105  		t.Fatal(err)
  1106  	}
  1107  
  1108  	c := make(chan error)
  1109  	go func() {
  1110  		hello1, hello2 := false, false
  1111  		sc := bufio.NewScanner(pin)
  1112  		for sc.Scan() {
  1113  			l := sc.Text()
  1114  			switch l {
  1115  			case "hello world1":
  1116  				hello1 = true
  1117  			case "hello world2":
  1118  				hello2 = true
  1119  			case "hello world1hello world2", "hello world2hello world1":
  1120  				hello1 = true
  1121  				hello2 = true
  1122  			default:
  1123  				c <- fmt.Errorf("unexpected output: %v", l)
  1124  				return
  1125  			}
  1126  			if hello1 && hello2 {
  1127  				break
  1128  			}
  1129  		}
  1130  		c <- nil
  1131  	}()
  1132  
  1133  	timeout := time.NewTimer(5 * time.Second)
  1134  	select {
  1135  	case <-timeout.C:
  1136  		t.Fatal("timeout")
  1137  	case err := <-c:
  1138  		if err != nil {
  1139  			t.Fatal(err)
  1140  		}
  1141  	}
  1142  }
  1143  
  1144  // TestConcurrentEvals2 shows that even though EvalWithContext calls Eval in a
  1145  // goroutine, it indeed waits for Eval to terminate, and that therefore the code
  1146  // called by EvalWithContext is sequential. And that there is no data race for the
  1147  // interp package global vars or the interpreter fields in this case.
  1148  func TestConcurrentEvals2(t *testing.T) {
  1149  	if testing.Short() {
  1150  		return
  1151  	}
  1152  	pin, pout := io.Pipe()
  1153  	defer func() {
  1154  		_ = pin.Close()
  1155  		_ = pout.Close()
  1156  	}()
  1157  	interpr := interp.New(interp.Options{Stdout: pout})
  1158  	if err := interpr.Use(stdlib.Symbols); err != nil {
  1159  		t.Fatal(err)
  1160  	}
  1161  
  1162  	done := make(chan error)
  1163  	go func() {
  1164  		hello1 := false
  1165  		sc := bufio.NewScanner(pin)
  1166  		for sc.Scan() {
  1167  			l := sc.Text()
  1168  			if hello1 {
  1169  				if l == "hello world2" {
  1170  					break
  1171  				} else {
  1172  					done <- fmt.Errorf("unexpected output: %v", l)
  1173  					return
  1174  				}
  1175  			}
  1176  			if l == "hello world1" {
  1177  				hello1 = true
  1178  			} else {
  1179  				done <- fmt.Errorf("unexpected output: %v", l)
  1180  				return
  1181  			}
  1182  		}
  1183  		done <- nil
  1184  	}()
  1185  
  1186  	ctx := context.Background()
  1187  	if _, err := interpr.EvalWithContext(ctx, `import "time"`); err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  	if _, err := interpr.EvalWithContext(ctx, `time.Sleep(time.Second); println("hello world1")`); err != nil {
  1191  		t.Fatal(err)
  1192  	}
  1193  	if _, err := interpr.EvalWithContext(ctx, `time.Sleep(time.Second); println("hello world2")`); err != nil {
  1194  		t.Fatal(err)
  1195  	}
  1196  
  1197  	timeout := time.NewTimer(5 * time.Second)
  1198  	select {
  1199  	case <-timeout.C:
  1200  		t.Fatal("timeout")
  1201  	case err := <-done:
  1202  		if err != nil {
  1203  			t.Fatal(err)
  1204  		}
  1205  	}
  1206  }
  1207  
  1208  // TestConcurrentEvals3 makes sure that we don't regress into data races at the package level, i.e from:
  1209  // - global vars, which should obviously not be mutated.
  1210  // - when calling Interpreter.Use, the symbols given as argument should be
  1211  // copied when being inserted into interp.binPkg, and not directly used as-is.
  1212  func TestConcurrentEvals3(t *testing.T) {
  1213  	if testing.Short() {
  1214  		return
  1215  	}
  1216  	allDone := make(chan bool)
  1217  	runREPL := func() {
  1218  		done := make(chan error)
  1219  		pinin, poutin := io.Pipe()
  1220  		pinout, poutout := io.Pipe()
  1221  		i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout})
  1222  		if err := i.Use(stdlib.Symbols); err != nil {
  1223  			t.Fatal(err)
  1224  		}
  1225  
  1226  		go func() {
  1227  			_, _ = i.REPL()
  1228  		}()
  1229  
  1230  		input := []string{
  1231  			`hello one`,
  1232  			`hello two`,
  1233  			`hello three`,
  1234  		}
  1235  
  1236  		go func() {
  1237  			sc := bufio.NewScanner(pinout)
  1238  			k := 0
  1239  			for sc.Scan() {
  1240  				l := sc.Text()
  1241  				if l != input[k] {
  1242  					done <- fmt.Errorf("unexpected output, want %q, got %q", input[k], l)
  1243  					return
  1244  				}
  1245  				k++
  1246  				if k > 2 {
  1247  					break
  1248  				}
  1249  			}
  1250  			done <- nil
  1251  		}()
  1252  
  1253  		for _, v := range input {
  1254  			in := strings.NewReader(fmt.Sprintf("println(\"%s\")\n", v))
  1255  			if _, err := io.Copy(poutin, in); err != nil {
  1256  				t.Fatal(err)
  1257  			}
  1258  			time.Sleep(time.Second)
  1259  		}
  1260  
  1261  		if err := <-done; err != nil {
  1262  			t.Fatal(err)
  1263  		}
  1264  		_ = pinin.Close()
  1265  		_ = poutin.Close()
  1266  		_ = pinout.Close()
  1267  		_ = poutout.Close()
  1268  		allDone <- true
  1269  	}
  1270  
  1271  	for i := 0; i < 2; i++ {
  1272  		go func() {
  1273  			runREPL()
  1274  		}()
  1275  	}
  1276  
  1277  	timeout := time.NewTimer(10 * time.Second)
  1278  	for i := 0; i < 2; i++ {
  1279  		select {
  1280  		case <-allDone:
  1281  		case <-timeout.C:
  1282  			t.Fatal("timeout")
  1283  		}
  1284  	}
  1285  }
  1286  
  1287  func TestConcurrentComposite1(t *testing.T) {
  1288  	testConcurrentComposite(t, "./testdata/concurrent/composite/composite_lit.go")
  1289  }
  1290  
  1291  func TestConcurrentComposite2(t *testing.T) {
  1292  	testConcurrentComposite(t, "./testdata/concurrent/composite/composite_sparse.go")
  1293  }
  1294  
  1295  func testConcurrentComposite(t *testing.T, filePath string) {
  1296  	t.Helper()
  1297  
  1298  	if testing.Short() {
  1299  		return
  1300  	}
  1301  	pin, pout := io.Pipe()
  1302  	i := interp.New(interp.Options{Stdout: pout})
  1303  	if err := i.Use(stdlib.Symbols); err != nil {
  1304  		t.Fatal(err)
  1305  	}
  1306  
  1307  	errc := make(chan error)
  1308  	var output string
  1309  	go func() {
  1310  		sc := bufio.NewScanner(pin)
  1311  		k := 0
  1312  		for sc.Scan() {
  1313  			output += sc.Text()
  1314  			k++
  1315  			if k > 1 {
  1316  				break
  1317  			}
  1318  		}
  1319  		errc <- nil
  1320  	}()
  1321  
  1322  	if _, err := i.EvalPath(filePath); err != nil {
  1323  		t.Fatal(err)
  1324  	}
  1325  
  1326  	_ = pin.Close()
  1327  	_ = pout.Close()
  1328  
  1329  	if err := <-errc; err != nil {
  1330  		t.Fatal(err)
  1331  	}
  1332  
  1333  	expected := "{hello}{hello}"
  1334  	if output != expected {
  1335  		t.Fatalf("unexpected output, want %q, got %q", expected, output)
  1336  	}
  1337  }
  1338  
  1339  func TestEvalScanner(t *testing.T) {
  1340  	if testing.Short() {
  1341  		return
  1342  	}
  1343  	type testCase struct {
  1344  		desc      string
  1345  		src       []string
  1346  		errorLine int
  1347  	}
  1348  	tests := []testCase{
  1349  		{
  1350  			desc: "no error",
  1351  			src: []string{
  1352  				`func main() {`,
  1353  				`println("foo")`,
  1354  				`}`,
  1355  			},
  1356  			errorLine: -1,
  1357  		},
  1358  
  1359  		{
  1360  			desc: "no parsing error, but block error",
  1361  			src: []string{
  1362  				`func main() {`,
  1363  				`println(foo)`,
  1364  				`}`,
  1365  			},
  1366  			errorLine: 2,
  1367  		},
  1368  		{
  1369  			desc: "parsing error",
  1370  			src: []string{
  1371  				`func main() {`,
  1372  				`println(/foo)`,
  1373  				`}`,
  1374  			},
  1375  			errorLine: 1,
  1376  		},
  1377  		{
  1378  			desc: "multi-line string literal",
  1379  			src: []string{
  1380  				"var a = `hello",
  1381  				"there, how",
  1382  				"are you?`",
  1383  			},
  1384  			errorLine: -1,
  1385  		},
  1386  
  1387  		{
  1388  			desc: "multi-line comma operand",
  1389  			src: []string{
  1390  				`println(2,`,
  1391  				`3)`,
  1392  			},
  1393  			errorLine: -1,
  1394  		},
  1395  		{
  1396  			desc: "multi-line arithmetic operand",
  1397  			src: []string{
  1398  				`println(2. /`,
  1399  				`3.)`,
  1400  			},
  1401  			errorLine: -1,
  1402  		},
  1403  		{
  1404  			desc: "anonymous func call with no assignment",
  1405  			src: []string{
  1406  				`func() { println(3) }()`,
  1407  			},
  1408  			errorLine: -1,
  1409  		},
  1410  		{
  1411  			// to make sure that special handling of the above anonymous, does not break this general case.
  1412  			desc: "just func",
  1413  			src: []string{
  1414  				`func foo() { println(3) }`,
  1415  			},
  1416  			errorLine: -1,
  1417  		},
  1418  		{
  1419  			// to make sure that special handling of the above anonymous, does not break this general case.
  1420  			desc: "just method",
  1421  			src: []string{
  1422  				`type bar string`,
  1423  				`func (b bar) foo() { println(3) }`,
  1424  			},
  1425  			errorLine: -1,
  1426  		},
  1427  	}
  1428  
  1429  	runREPL := func(t *testing.T, test testCase) {
  1430  		// TODO(mpl): use a pipe for the output as well, just as in TestConcurrentEvals5
  1431  		var stdout bytes.Buffer
  1432  		safeStdout := &safeBuffer{buf: &stdout}
  1433  		var stderr bytes.Buffer
  1434  		safeStderr := &safeBuffer{buf: &stderr}
  1435  		pin, pout := io.Pipe()
  1436  		i := interp.New(interp.Options{Stdin: pin, Stdout: safeStdout, Stderr: safeStderr})
  1437  		defer func() {
  1438  			// Closing the pipe also takes care of making i.REPL terminate,
  1439  			// hence freeing its goroutine.
  1440  			_ = pin.Close()
  1441  			_ = pout.Close()
  1442  		}()
  1443  
  1444  		go func() {
  1445  			_, _ = i.REPL()
  1446  		}()
  1447  		for k, v := range test.src {
  1448  			if _, err := pout.Write([]byte(v + "\n")); err != nil {
  1449  				t.Error(err)
  1450  			}
  1451  			Sleep(100 * time.Millisecond)
  1452  
  1453  			errMsg := safeStderr.String()
  1454  			if k == test.errorLine {
  1455  				if errMsg == "" {
  1456  					t.Fatalf("test %q: statement %q should have produced an error", test.desc, v)
  1457  				}
  1458  				break
  1459  			}
  1460  			if errMsg != "" {
  1461  				t.Fatalf("test %q: unexpected error: %v", test.desc, errMsg)
  1462  			}
  1463  		}
  1464  	}
  1465  
  1466  	for _, test := range tests {
  1467  		runREPL(t, test)
  1468  	}
  1469  }
  1470  
  1471  type safeBuffer struct {
  1472  	mu  sync.RWMutex
  1473  	buf *bytes.Buffer
  1474  }
  1475  
  1476  func (sb *safeBuffer) Read(p []byte) (int, error) {
  1477  	return sb.buf.Read(p)
  1478  }
  1479  
  1480  func (sb *safeBuffer) String() string {
  1481  	sb.mu.RLock()
  1482  	defer sb.mu.RUnlock()
  1483  	return sb.buf.String()
  1484  }
  1485  
  1486  func (sb *safeBuffer) Write(p []byte) (int, error) {
  1487  	sb.mu.Lock()
  1488  	defer sb.mu.Unlock()
  1489  	return sb.buf.Write(p)
  1490  }
  1491  
  1492  const (
  1493  	// CITimeoutMultiplier is the multiplier for all timeouts in the CI.
  1494  	CITimeoutMultiplier = 3
  1495  )
  1496  
  1497  // Sleep pauses the current goroutine for at least the duration d.
  1498  func Sleep(d time.Duration) {
  1499  	d = applyCIMultiplier(d)
  1500  	time.Sleep(d)
  1501  }
  1502  
  1503  func applyCIMultiplier(timeout time.Duration) time.Duration {
  1504  	ci := os.Getenv("CI")
  1505  	if ci == "" {
  1506  		return timeout
  1507  	}
  1508  	b, err := strconv.ParseBool(ci)
  1509  	if err != nil || !b {
  1510  		return timeout
  1511  	}
  1512  	return time.Duration(float64(timeout) * CITimeoutMultiplier)
  1513  }
  1514  
  1515  func TestREPLCommands(t *testing.T) {
  1516  	if testing.Short() {
  1517  		return
  1518  	}
  1519  	_ = os.Setenv("YAEGI_PROMPT", "1") // To force prompts over non-tty streams
  1520  	defer func() {
  1521  		_ = os.Setenv("YAEGI_PROMPT", "0")
  1522  	}()
  1523  	allDone := make(chan bool)
  1524  	runREPL := func() {
  1525  		done := make(chan error)
  1526  		pinin, poutin := io.Pipe()
  1527  		pinout, poutout := io.Pipe()
  1528  		i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout})
  1529  		if err := i.Use(stdlib.Symbols); err != nil {
  1530  			t.Fatal(err)
  1531  		}
  1532  
  1533  		go func() {
  1534  			_, _ = i.REPL()
  1535  		}()
  1536  
  1537  		defer func() {
  1538  			_ = pinin.Close()
  1539  			_ = poutin.Close()
  1540  			_ = pinout.Close()
  1541  			_ = poutout.Close()
  1542  			allDone <- true
  1543  		}()
  1544  
  1545  		input := []string{
  1546  			`1/1`,
  1547  			`7/3`,
  1548  			`16/5`,
  1549  			`3./2`, // float
  1550  			`reflect.TypeOf(math_rand.Int)`,
  1551  			`reflect.TypeOf(crypto_rand.Int)`,
  1552  		}
  1553  		output := []string{
  1554  			`1`,
  1555  			`2`,
  1556  			`3`,
  1557  			`1.5`,
  1558  			`func() int`,
  1559  			`func(io.Reader, *big.Int) (*big.Int, error)`,
  1560  		}
  1561  
  1562  		go func() {
  1563  			sc := bufio.NewScanner(pinout)
  1564  			k := 0
  1565  			for sc.Scan() {
  1566  				l := sc.Text()
  1567  				if l != "> : "+output[k] {
  1568  					done <- fmt.Errorf("unexpected output, want %q, got %q", output[k], l)
  1569  					return
  1570  				}
  1571  				k++
  1572  				if k > 3 {
  1573  					break
  1574  				}
  1575  			}
  1576  			done <- nil
  1577  		}()
  1578  
  1579  		for _, v := range input {
  1580  			in := strings.NewReader(v + "\n")
  1581  			if _, err := io.Copy(poutin, in); err != nil {
  1582  				t.Fatal(err)
  1583  			}
  1584  			select {
  1585  			case err := <-done:
  1586  				if err != nil {
  1587  					t.Fatal(err)
  1588  				}
  1589  				return
  1590  			default:
  1591  				time.Sleep(time.Second)
  1592  			}
  1593  		}
  1594  
  1595  		if err := <-done; err != nil {
  1596  			t.Fatal(err)
  1597  		}
  1598  	}
  1599  
  1600  	go func() {
  1601  		runREPL()
  1602  	}()
  1603  
  1604  	timeout := time.NewTimer(10 * time.Second)
  1605  	select {
  1606  	case <-allDone:
  1607  	case <-timeout.C:
  1608  		t.Fatal("timeout")
  1609  	}
  1610  }
  1611  
  1612  func TestStdio(t *testing.T) {
  1613  	i := interp.New(interp.Options{})
  1614  	if err := i.Use(stdlib.Symbols); err != nil {
  1615  		t.Fatal(err)
  1616  	}
  1617  	i.ImportUsed()
  1618  	if _, err := i.Eval(`var x = os.Stdout`); err != nil {
  1619  		t.Fatal(err)
  1620  	}
  1621  	v, _ := i.Eval(`x`)
  1622  	if _, ok := v.Interface().(*os.File); !ok {
  1623  		t.Fatalf("%v not *os.file", v.Interface())
  1624  	}
  1625  }
  1626  
  1627  func TestIssue1142(t *testing.T) {
  1628  	i := interp.New(interp.Options{})
  1629  	runTests(t, i, []testCase{
  1630  		{src: "a := 1; // foo bar", res: "1"},
  1631  	})
  1632  }
  1633  
  1634  type Issue1149Array [3]float32
  1635  
  1636  func (v Issue1149Array) Foo() string  { return "foo" }
  1637  func (v *Issue1149Array) Bar() string { return "foo" }
  1638  
  1639  func TestIssue1149(t *testing.T) {
  1640  	i := interp.New(interp.Options{})
  1641  	if err := i.Use(interp.Exports{
  1642  		"pkg/pkg": map[string]reflect.Value{
  1643  			"Type": reflect.ValueOf((*Issue1149Array)(nil)),
  1644  		},
  1645  	}); err != nil {
  1646  		t.Fatal(err)
  1647  	}
  1648  	i.ImportUsed()
  1649  
  1650  	_, err := i.Eval(`
  1651  		type Type = pkg.Type
  1652  	`)
  1653  	if err != nil {
  1654  		t.Fatal(err)
  1655  	}
  1656  
  1657  	runTests(t, i, []testCase{
  1658  		{src: "Type{1, 2, 3}.Foo()", res: "foo"},
  1659  		{src: "Type{1, 2, 3}.Bar()", res: "foo"},
  1660  	})
  1661  }
  1662  
  1663  func TestIssue1150(t *testing.T) {
  1664  	i := interp.New(interp.Options{})
  1665  	_, err := i.Eval(`
  1666  		type ArrayT [3]float32
  1667  		type SliceT []float32
  1668  		type StructT struct { A, B, C float32 }
  1669  		type StructT2 struct { A, B, C float32 }
  1670  		type FooerT interface { Foo() string }
  1671  
  1672  		func (v ArrayT) Foo() string { return "foo" }
  1673  		func (v SliceT) Foo() string { return "foo" }
  1674  		func (v StructT) Foo() string { return "foo" }
  1675  		func (v *StructT2) Foo() string { return "foo" }
  1676  
  1677  		type Array = ArrayT
  1678  		type Slice = SliceT
  1679  		type Struct = StructT
  1680  		type Struct2 = StructT2
  1681  		type Fooer = FooerT
  1682  	`)
  1683  	if err != nil {
  1684  		t.Fatal(err)
  1685  	}
  1686  
  1687  	runTests(t, i, []testCase{
  1688  		{desc: "array", src: "Array{1, 2, 3}.Foo()", res: "foo"},
  1689  		{desc: "slice", src: "Slice{1, 2, 3}.Foo()", res: "foo"},
  1690  		{desc: "struct", src: "Struct{1, 2, 3}.Foo()", res: "foo"},
  1691  		{desc: "*struct", src: "Struct2{1, 2, 3}.Foo()", res: "foo"},
  1692  		{desc: "interface", src: "v := Fooer(Array{1, 2, 3}); v.Foo()", res: "foo"},
  1693  	})
  1694  }
  1695  
  1696  func TestIssue1151(t *testing.T) {
  1697  	type pkgStruct struct{ X int }
  1698  	type pkgArray [1]int
  1699  
  1700  	i := interp.New(interp.Options{})
  1701  	if err := i.Use(interp.Exports{
  1702  		"pkg/pkg": map[string]reflect.Value{
  1703  			"Struct": reflect.ValueOf((*pkgStruct)(nil)),
  1704  			"Array":  reflect.ValueOf((*pkgArray)(nil)),
  1705  		},
  1706  	}); err != nil {
  1707  		t.Fatal(err)
  1708  	}
  1709  	i.ImportUsed()
  1710  
  1711  	runTests(t, i, []testCase{
  1712  		{src: "x := pkg.Struct{1}", res: "{1}"},
  1713  		{src: "x := pkg.Array{1}", res: "[1]"},
  1714  	})
  1715  }
  1716  
  1717  func TestPassArgs(t *testing.T) {
  1718  	i := interp.New(interp.Options{Args: []string{"arg0", "arg1"}})
  1719  	if err := i.Use(stdlib.Symbols); err != nil {
  1720  		t.Fatal(err)
  1721  	}
  1722  	i.ImportUsed()
  1723  	runTests(t, i, []testCase{
  1724  		{src: "os.Args", res: "[arg0 arg1]"},
  1725  	})
  1726  }