gitlab.com/ethan.reesor/vscode-notebooks/yaegi@v0.0.0-20220417214422-5c573557938e/interp/interp_eval_test.go (about) 1 package interp_test 2 3 import ( 4 "bufio" 5 "bytes" 6 "context" 7 "fmt" 8 "go/parser" 9 "io" 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 "gitlab.com/ethan.reesor/vscode-notebooks/yaegi/interp" 23 "gitlab.com/ethan.reesor/vscode-notebooks/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 {src: `a, b, c := 1, 1, false; if a == b { c = true }; c`, res: "true"}, 422 {src: `a, b, c := 1, 2, false; if a != b { c = true }; c`, res: "true"}, 423 { 424 desc: "mismatched types", 425 src: ` 426 type Foo string 427 type Bar string 428 429 var a = Foo("test") 430 var b = Bar("test") 431 var c = a == b 432 `, 433 err: "7:13: invalid operation: mismatched types main.Foo and main.Bar", 434 }, 435 }) 436 } 437 438 func TestEvalCompositeArray(t *testing.T) { 439 i := interp.New(interp.Options{}) 440 eval(t, i, `const l = 10`) 441 runTests(t, i, []testCase{ 442 {src: "a := []int{1, 2, 7: 20, 30}", res: "[1 2 0 0 0 0 0 20 30]"}, 443 {src: `a := []int{1, 1.2}`, err: "1:42: 6/5 truncated to int"}, 444 {src: `a := []int{0:1, 0:1}`, err: "1:46: duplicate index 0 in array or slice literal"}, 445 {src: `a := []int{1.1:1, 1.2:"test"}`, err: "1:39: index untyped float must be integer constant"}, 446 {src: `a := [2]int{1, 1.2}`, err: "1:43: 6/5 truncated to int"}, 447 {src: `a := [1]int{1, 2}`, err: "1:43: index 1 is out of bounds (>= 1)"}, 448 {src: `b := [l]int{1, 2}`, res: "[1 2 0 0 0 0 0 0 0 0]"}, 449 {src: `i := 10; a := [i]int{1, 2}`, err: "1:43: non-constant array bound \"i\""}, 450 {src: `c := [...]float64{1, 3: 3.4, 5}`, res: "[1 0 0 3.4 5]"}, 451 }) 452 } 453 454 func TestEvalCompositeMap(t *testing.T) { 455 i := interp.New(interp.Options{}) 456 runTests(t, i, []testCase{ 457 {src: `a := map[string]int{"one":1, "two":2}`, res: "map[one:1 two:2]"}, 458 {src: `a := map[string]int{1:1, 2:2}`, err: "1:48: cannot convert 1 to string"}, 459 {src: `a := map[string]int{"one":1, "two":2.2}`, err: "1:63: 11/5 truncated to int"}, 460 {src: `a := map[string]int{1, "two":2}`, err: "1:48: missing key in map literal"}, 461 {src: `a := map[string]int{"one":1, "one":2}`, err: "1:57: duplicate key one in map literal"}, 462 }) 463 } 464 465 func TestEvalCompositeStruct(t *testing.T) { 466 i := interp.New(interp.Options{}) 467 runTests(t, i, []testCase{ 468 {src: `a := struct{A,B,C int}{}`, res: "{0 0 0}"}, 469 {src: `a := struct{A,B,C int}{1,2,3}`, res: "{1 2 3}"}, 470 {src: `a := struct{A,B,C int}{1,2.2,3}`, err: "1:53: 11/5 truncated to int"}, 471 {src: `a := struct{A,B,C int}{1,2}`, err: "1:53: too few values in struct literal"}, 472 {src: `a := struct{A,B,C int}{1,2,3,4}`, err: "1:57: too many values in struct literal"}, 473 {src: `a := struct{A,B,C int}{1,B:2,3}`, err: "1:53: mixture of field:value and value elements in struct literal"}, 474 {src: `a := struct{A,B,C int}{A:1,B:2,C:3}`, res: "{1 2 3}"}, 475 {src: `a := struct{A,B,C int}{B:2}`, res: "{0 2 0}"}, 476 {src: `a := struct{A,B,C int}{A:1,D:2,C:3}`, err: "1:55: unknown field D in struct literal"}, 477 {src: `a := struct{A,B,C int}{A:1,A:2,C:3}`, err: "1:55: duplicate field name A in struct literal"}, 478 {src: `a := struct{A,B,C int}{A:1,B:2.2,C:3}`, err: "1:57: 11/5 truncated to int"}, 479 {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"}, 480 }) 481 } 482 483 func TestEvalSliceExpression(t *testing.T) { 484 i := interp.New(interp.Options{}) 485 runTests(t, i, []testCase{ 486 {src: `a := []int{0,1,2}[1:3]`, res: "[1 2]"}, 487 {src: `a := []int{0,1,2}[:3]`, res: "[0 1 2]"}, 488 {src: `a := []int{0,1,2}[:]`, res: "[0 1 2]"}, 489 {src: `a := []int{0,1,2,3}[1:3:4]`, res: "[1 2]"}, 490 {src: `a := []int{0,1,2,3}[:3:4]`, res: "[0 1 2]"}, 491 {src: `ar := [3]int{0,1,2}; a := ar[1:3]`, res: "[1 2]"}, 492 {src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"}, 493 {src: `a := (&[3]int{0,1,2})[1:3]`, res: "[1 2]"}, 494 {src: `s := "hello"[1:3]`, res: "el"}, 495 {src: `str := "hello"; s := str[1:3]`, res: "el"}, 496 {src: `a := int(1)[0:1]`, err: "1:33: cannot slice type int"}, 497 {src: `a := (&[]int{0,1,2,3})[1:3]`, err: "1:33: cannot slice type *[]int"}, 498 {src: `a := "hello"[1:3:4]`, err: "1:45: invalid operation: 3-index slice of string"}, 499 {src: `ar := [3]int{0,1,2}; a := ar[:4]`, err: "1:58: index int is out of bounds"}, 500 {src: `a := []int{0,1,2,3}[1::4]`, err: "1:49: 2nd index required in 3-index slice"}, 501 {src: `a := []int{0,1,2,3}[1:3:]`, err: "1:51: 3rd index required in 3-index slice"}, 502 {src: `a := []int{0,1,2}[3:1]`, err: "invalid index values, must be low <= high <= max"}, 503 {pre: func() { eval(t, i, `type Str = string; var r Str = "truc"`) }, src: `r[1]`, res: "114"}, 504 }) 505 } 506 507 func TestEvalConversion(t *testing.T) { 508 i := interp.New(interp.Options{}) 509 runTests(t, i, []testCase{ 510 {src: `a := uint64(1)`, res: "1"}, 511 {src: `i := 1.1; a := uint64(i)`, res: "1"}, 512 {src: `b := string(49)`, res: "1"}, 513 {src: `c := uint64(1.1)`, err: "1:40: cannot convert expression of type untyped float to type uint64"}, 514 }) 515 } 516 517 func TestEvalUnary(t *testing.T) { 518 i := interp.New(interp.Options{}) 519 runTests(t, i, []testCase{ 520 {src: "a := -1", res: "-1"}, 521 {src: "b := +1", res: "1", skip: "BUG"}, 522 {src: "c := !false", res: "true"}, 523 }) 524 } 525 526 func TestEvalMethod(t *testing.T) { 527 i := interp.New(interp.Options{}) 528 eval(t, i, ` 529 type Root struct { 530 Name string 531 } 532 533 type One struct { 534 Root 535 } 536 537 type Hi interface { 538 Hello() string 539 } 540 541 type Hey interface { 542 Hello() string 543 } 544 545 func (r *Root) Hello() string { return "Hello " + r.Name } 546 547 var r = Root{"R"} 548 var o = One{r} 549 // TODO(mpl): restore empty interfaces when type assertions work (again) on them. 550 // var root interface{} = &Root{Name: "test1"} 551 // var one interface{} = &One{Root{Name: "test2"}} 552 var root Hey = &Root{Name: "test1"} 553 var one Hey = &One{Root{Name: "test2"}} 554 `) 555 runTests(t, i, []testCase{ 556 {src: "r.Hello()", res: "Hello R"}, 557 {src: "(&r).Hello()", res: "Hello R"}, 558 {src: "o.Hello()", res: "Hello R"}, 559 {src: "(&o).Hello()", res: "Hello R"}, 560 {src: "root.(Hi).Hello()", res: "Hello test1"}, 561 {src: "one.(Hi).Hello()", res: "Hello test2"}, 562 }) 563 } 564 565 func TestEvalChan(t *testing.T) { 566 i := interp.New(interp.Options{}) 567 runTests(t, i, []testCase{ 568 { 569 src: `(func () string { 570 messages := make(chan string) 571 go func() { messages <- "ping" }() 572 msg := <-messages 573 return msg 574 })()`, res: "ping", 575 }, 576 { 577 src: `(func () bool { 578 messages := make(chan string) 579 go func() { messages <- "ping" }() 580 msg, ok := <-messages 581 return ok && msg == "ping" 582 })()`, res: "true", 583 }, 584 { 585 src: `(func () bool { 586 messages := make(chan string) 587 go func() { messages <- "ping" }() 588 var msg string 589 var ok bool 590 msg, ok = <-messages 591 return ok && msg == "ping" 592 })()`, res: "true", 593 }, 594 }) 595 } 596 597 func TestEvalFunctionCallWithFunctionParam(t *testing.T) { 598 i := interp.New(interp.Options{}) 599 eval(t, i, ` 600 func Bar(s string, fn func(string)string) string { return fn(s) } 601 `) 602 603 v := eval(t, i, "Bar") 604 bar := v.Interface().(func(string, func(string) string) string) 605 606 got := bar("hello ", func(s string) string { 607 return s + "world!" 608 }) 609 610 want := "hello world!" 611 if got != want { 612 t.Errorf("unexpected result of function eval: got %q, want %q", got, want) 613 } 614 } 615 616 func TestEvalCall(t *testing.T) { 617 i := interp.New(interp.Options{}) 618 runTests(t, i, []testCase{ 619 {src: ` test := func(a int, b float64) int { return a } 620 a := test(1, 2.3)`, res: "1"}, 621 {src: ` test := func(a int, b float64) int { return a } 622 a := test(1)`, err: "2:10: not enough arguments in call to test"}, 623 {src: ` test := func(a int, b float64) int { return a } 624 s := "test" 625 a := test(1, s)`, err: "3:18: cannot use type string as type float64"}, 626 {src: ` test := func(a ...int) int { return 1 } 627 a := test([]int{1}...)`, res: "1"}, 628 {src: ` test := func(a ...int) int { return 1 } 629 a := test()`, res: "1"}, 630 {src: ` test := func(a ...int) int { return 1 } 631 blah := func() []int { return []int{1,1} } 632 a := test(blah()...)`, res: "1"}, 633 {src: ` test := func(a ...int) int { return 1 } 634 a := test([]string{"1"}...)`, err: "2:15: cannot use []string as type []int"}, 635 {src: ` test := func(a ...int) int { return 1 } 636 i := 1 637 a := test(i...)`, err: "3:15: cannot use int as type []int"}, 638 {src: ` test := func(a int) int { return a } 639 a := test([]int{1}...)`, err: "2:10: invalid use of ..., corresponding parameter is non-variadic"}, 640 {src: ` test := func(a ...int) int { return 1 } 641 blah := func() (int, int) { return 1, 1 } 642 a := test(blah()...)`, err: "3:15: cannot use ... with 2-valued func() (int,int)"}, 643 {src: ` test := func(a, b int) int { return a } 644 blah := func() (int, int) { return 1, 1 } 645 a := test(blah())`, res: "1"}, 646 {src: ` test := func(a, b int) int { return a } 647 blah := func() int { return 1 } 648 a := test(blah(), blah())`, res: "1"}, 649 {src: ` test := func(a, b, c, d int) int { return a } 650 blah := func() (int, int) { return 1, 1 } 651 a := test(blah(), blah())`, err: "3:15: cannot use func() (int,int) as type int"}, 652 {src: ` test := func(a, b int) int { return a } 653 blah := func() (int, float64) { return 1, 1.1 } 654 a := test(blah())`, err: "3:15: cannot use func() (int,float64) as type (int,int)"}, 655 }) 656 } 657 658 func TestEvalBinCall(t *testing.T) { 659 i := interp.New(interp.Options{}) 660 if err := i.Use(stdlib.Symbols); err != nil { 661 t.Fatal(err) 662 } 663 if _, err := i.Eval(`import "fmt"`); err != nil { 664 t.Fatal(err) 665 } 666 runTests(t, i, []testCase{ 667 {src: `a := fmt.Sprint(1, 2.3)`, res: "1 2.3"}, 668 {src: `a := fmt.Sprintf()`, err: "1:33: not enough arguments in call to fmt.Sprintf"}, 669 {src: `i := 1 670 a := fmt.Sprintf(i)`, err: "2:24: cannot use type int as type string"}, 671 {src: `a := fmt.Sprint()`, res: ""}, 672 }) 673 } 674 675 func TestEvalMissingSymbol(t *testing.T) { 676 defer func() { 677 r := recover() 678 if r != nil { 679 t.Errorf("unexpected panic: %v", r) 680 } 681 }() 682 683 type S2 struct{} 684 type S1 struct { 685 F S2 686 } 687 i := interp.New(interp.Options{}) 688 if err := i.Use(interp.Exports{"p/p": map[string]reflect.Value{ 689 "S1": reflect.Zero(reflect.TypeOf(&S1{})), 690 }}); err != nil { 691 t.Fatal(err) 692 } 693 _, err := i.Eval(`import "p"`) 694 if err != nil { 695 t.Fatalf("failed to import package: %v", err) 696 } 697 _, err = i.Eval(`p.S1{F: p.S2{}}`) 698 if err == nil { 699 t.Error("unexpected nil error for expression with undefined type") 700 } 701 } 702 703 func TestEvalWithContext(t *testing.T) { 704 tests := []testCase{ 705 { 706 desc: "for {}", 707 src: `(func() { 708 for {} 709 })()`, 710 }, 711 { 712 desc: "select {}", 713 src: `(func() { 714 select {} 715 })()`, 716 }, 717 { 718 desc: "blocked chan send", 719 src: `(func() { 720 c := make(chan int) 721 c <- 1 722 })()`, 723 }, 724 { 725 desc: "blocked chan recv", 726 src: `(func() { 727 c := make(chan int) 728 <-c 729 })()`, 730 }, 731 { 732 desc: "blocked chan recv2", 733 src: `(func() { 734 c := make(chan int) 735 _, _ = <-c 736 })()`, 737 }, 738 { 739 desc: "blocked range chan", 740 src: `(func() { 741 c := make(chan int) 742 for range c {} 743 })()`, 744 }, 745 { 746 desc: "double lock", 747 src: `(func() { 748 var mu sync.Mutex 749 mu.Lock() 750 mu.Lock() 751 })()`, 752 }, 753 } 754 755 for _, test := range tests { 756 done := make(chan struct{}) 757 src := test.src 758 go func() { 759 defer close(done) 760 i := interp.New(interp.Options{}) 761 if err := i.Use(stdlib.Symbols); err != nil { 762 t.Error(err) 763 } 764 _, err := i.Eval(`import "sync"`) 765 if err != nil { 766 t.Errorf(`failed to import "sync": %v`, err) 767 return 768 } 769 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 770 defer cancel() 771 _, err = i.EvalWithContext(ctx, src) 772 switch err { 773 case context.DeadlineExceeded: 774 // Successful cancellation. 775 776 // Check we can still execute an expression. 777 v, err := i.EvalWithContext(context.Background(), "1+1\n") 778 if err != nil { 779 t.Errorf("failed to evaluate expression after cancellation: %v", err) 780 } 781 got := v.Interface() 782 if got != 2 { 783 t.Errorf("unexpected result of eval(1+1): got %v, want 2", got) 784 } 785 case nil: 786 t.Errorf("unexpected success evaluating expression %q", test.desc) 787 default: 788 t.Errorf("failed to evaluate expression %q: %v", test.desc, err) 789 } 790 }() 791 select { 792 case <-time.After(time.Second): 793 t.Errorf("timeout failed to terminate execution of %q", test.desc) 794 case <-done: 795 } 796 } 797 } 798 799 func runTests(t *testing.T, i *interp.Interpreter, tests []testCase) { 800 t.Helper() 801 802 for _, test := range tests { 803 t.Run(test.desc, func(t *testing.T) { 804 if test.skip != "" { 805 t.Skip(test.skip) 806 } 807 if test.pre != nil { 808 test.pre() 809 } 810 if test.src != "" { 811 assertEval(t, i, test.src, test.err, test.res) 812 } 813 }) 814 } 815 } 816 817 func eval(t *testing.T, i *interp.Interpreter, src string) reflect.Value { 818 t.Helper() 819 res, err := i.Eval(src) 820 if err != nil { 821 t.Logf("Error: %v", err) 822 if e, ok := err.(interp.Panic); ok { 823 t.Logf(string(e.Stack)) 824 } 825 t.FailNow() 826 } 827 return res 828 } 829 830 func assertEval(t *testing.T, i *interp.Interpreter, src, expectedError, expectedRes string) { 831 t.Helper() 832 833 res, err := i.Eval(src) 834 835 if expectedError != "" { 836 if err == nil || !strings.Contains(err.Error(), expectedError) { 837 t.Fatalf("got %v, want %s", err, expectedError) 838 } 839 return 840 } 841 842 if err != nil { 843 t.Logf("got an error: %v", err) 844 if e, ok := err.(interp.Panic); ok { 845 t.Logf(string(e.Stack)) 846 } 847 t.FailNow() 848 } 849 850 if fmt.Sprintf("%v", res) != expectedRes { 851 t.Fatalf("got %v, want %s", res, expectedRes) 852 } 853 } 854 855 func TestMultiEval(t *testing.T) { 856 t.Skip("fail in CI only ?") 857 // catch stdout 858 backupStdout := os.Stdout 859 defer func() { 860 os.Stdout = backupStdout 861 }() 862 r, w, _ := os.Pipe() 863 os.Stdout = w 864 865 i := interp.New(interp.Options{}) 866 if err := i.Use(stdlib.Symbols); err != nil { 867 t.Fatal(err) 868 } 869 870 f, err := os.Open(filepath.Join("testdata", "multi", "731")) 871 if err != nil { 872 t.Fatal(err) 873 } 874 names, err := f.Readdirnames(-1) 875 if err != nil { 876 t.Fatal(err) 877 } 878 for _, v := range names { 879 if _, err := i.EvalPath(filepath.Join(f.Name(), v)); err != nil { 880 t.Fatal(err) 881 } 882 } 883 884 // read stdout 885 if err = w.Close(); err != nil { 886 t.Fatal(err) 887 } 888 outInterp, err := io.ReadAll(r) 889 if err != nil { 890 t.Fatal(err) 891 } 892 893 // restore Stdout 894 os.Stdout = backupStdout 895 896 want := "A\nB\n" 897 got := string(outInterp) 898 if got != want { 899 t.Fatalf("unexpected output: got %v, wanted %v", got, want) 900 } 901 } 902 903 func TestMultiEvalNoName(t *testing.T) { 904 t.Skip("fail in CI only ?") 905 i := interp.New(interp.Options{}) 906 if err := i.Use(stdlib.Symbols); err != nil { 907 t.Fatal(err) 908 } 909 910 f, err := os.Open(filepath.Join("testdata", "multi", "731")) 911 if err != nil { 912 t.Fatal(err) 913 } 914 names, err := f.Readdirnames(-1) 915 if err != nil { 916 t.Fatal(err) 917 } 918 for k, v := range names { 919 data, err := os.ReadFile(filepath.Join(f.Name(), v)) 920 if err != nil { 921 t.Fatal(err) 922 } 923 _, err = i.Eval(string(data)) 924 if k == 1 { 925 expectedErr := fmt.Errorf("3:8: fmt/%s redeclared in this block", interp.DefaultSourceName) 926 if err == nil || err.Error() != expectedErr.Error() { 927 t.Fatalf("unexpected result; wanted error %v, got %v", expectedErr, err) 928 } 929 return 930 } 931 if err != nil { 932 t.Fatal(err) 933 } 934 } 935 } 936 937 const goMinorVersionTest = 16 938 939 func TestHasIOFS(t *testing.T) { 940 code := ` 941 // +build go1.16 942 943 package main 944 945 import ( 946 "errors" 947 "io/fs" 948 ) 949 950 func main() { 951 pe := fs.PathError{} 952 pe.Op = "nothing" 953 pe.Path = "/nowhere" 954 pe.Err = errors.New("an error") 955 println(pe.Error()) 956 } 957 958 // Output: 959 // nothing /nowhere: an error 960 ` 961 962 var buf bytes.Buffer 963 i := interp.New(interp.Options{Stdout: &buf}) 964 if err := i.Use(interp.Symbols); err != nil { 965 t.Fatal(err) 966 } 967 if err := i.Use(stdlib.Symbols); err != nil { 968 t.Fatal(err) 969 } 970 971 if _, err := i.Eval(code); err != nil { 972 t.Fatal(err) 973 } 974 975 var expectedOutput string 976 var minor int 977 var err error 978 version := runtime.Version() 979 fields := strings.Fields(version) 980 // Go stable 981 if len(fields) == 1 { 982 v := strings.Split(version, ".") 983 if len(v) < 2 { 984 t.Fatalf("unexpected: %v", version) 985 } 986 minor, err = strconv.Atoi(v[1]) 987 if err != nil { 988 t.Fatal(err) 989 } 990 } else { 991 // Go devel 992 if fields[0] != "devel" { 993 t.Fatalf("unexpected: %v", fields[0]) 994 } 995 parts := strings.Split(fields[1], "-") 996 if len(parts) != 2 { 997 t.Fatalf("unexpected: %v", fields[1]) 998 } 999 minor, err = strconv.Atoi(strings.TrimPrefix(parts[0], "go1.")) 1000 if err != nil { 1001 t.Fatal(err) 1002 } 1003 } 1004 1005 if minor >= goMinorVersionTest { 1006 expectedOutput = "nothing /nowhere: an error\n" 1007 } 1008 1009 output := buf.String() 1010 if buf.String() != expectedOutput { 1011 t.Fatalf("got: %v, wanted: %v", output, expectedOutput) 1012 } 1013 } 1014 1015 func TestImportPathIsKey(t *testing.T) { 1016 // No need to check the results of Eval, as TestFile already does it. 1017 i := interp.New(interp.Options{GoPath: filepath.FromSlash("../_test/testdata/redeclaration-global7")}) 1018 if err := i.Use(stdlib.Symbols); err != nil { 1019 t.Fatal(err) 1020 } 1021 1022 filePath := filepath.Join("..", "_test", "ipp_as_key.go") 1023 if _, err := i.EvalPath(filePath); err != nil { 1024 t.Fatal(err) 1025 } 1026 1027 wantScopes := map[string][]string{ 1028 "main": { 1029 "titi/ipp_as_key.go", 1030 "tutu/ipp_as_key.go", 1031 "main", 1032 }, 1033 "guthib.com/toto": { 1034 "quux/titi.go", 1035 "Quux", 1036 }, 1037 "guthib.com/bar": { 1038 "Quux", 1039 }, 1040 "guthib.com/tata": { 1041 "quux/tutu.go", 1042 "Quux", 1043 }, 1044 "guthib.com/baz": { 1045 "Quux", 1046 }, 1047 } 1048 wantPackages := map[string]string{ 1049 "guthib.com/baz": "quux", 1050 "guthib.com/tata": "tutu", 1051 "main": "main", 1052 "guthib.com/bar": "quux", 1053 "guthib.com/toto": "titi", 1054 } 1055 1056 scopes := i.Scopes() 1057 if len(scopes) != len(wantScopes) { 1058 t.Fatalf("want %d, got %d", len(wantScopes), len(scopes)) 1059 } 1060 for k, v := range scopes { 1061 wantSym := wantScopes[k] 1062 if len(v) != len(wantSym) { 1063 t.Fatalf("want %d, got %d", len(wantSym), len(v)) 1064 } 1065 for _, sym := range wantSym { 1066 if _, ok := v[sym]; !ok { 1067 t.Fatalf("symbol %s not found in scope %s", sym, k) 1068 } 1069 } 1070 } 1071 1072 packages := i.Packages() 1073 for k, v := range wantPackages { 1074 pkg := packages[k] 1075 if pkg != v { 1076 t.Fatalf("for import path %s, want %s, got %s", k, v, pkg) 1077 } 1078 } 1079 } 1080 1081 // The code in hello1.go and hello2.go spawns a "long-running" goroutine, which 1082 // means each call to EvalPath actually terminates before the evaled code is done 1083 // running. So this test demonstrates: 1084 // 1) That two sequential calls to EvalPath don't see their "compilation phases" 1085 // collide (no data race on the fields of the interpreter), which is somewhat 1086 // obvious since the calls (and hence the "compilation phases") are sequential too. 1087 // 2) That two concurrent goroutine runs spawned by the same interpreter do not 1088 // collide either. 1089 func TestConcurrentEvals(t *testing.T) { 1090 if testing.Short() { 1091 return 1092 } 1093 pin, pout := io.Pipe() 1094 defer func() { 1095 _ = pin.Close() 1096 _ = pout.Close() 1097 }() 1098 interpr := interp.New(interp.Options{Stdout: pout}) 1099 if err := interpr.Use(stdlib.Symbols); err != nil { 1100 t.Fatal(err) 1101 } 1102 1103 if _, err := interpr.EvalPath("testdata/concurrent/hello1.go"); err != nil { 1104 t.Fatal(err) 1105 } 1106 if _, err := interpr.EvalPath("testdata/concurrent/hello2.go"); err != nil { 1107 t.Fatal(err) 1108 } 1109 1110 c := make(chan error) 1111 go func() { 1112 hello1, hello2 := false, false 1113 sc := bufio.NewScanner(pin) 1114 for sc.Scan() { 1115 l := sc.Text() 1116 switch l { 1117 case "hello world1": 1118 hello1 = true 1119 case "hello world2": 1120 hello2 = true 1121 case "hello world1hello world2", "hello world2hello world1": 1122 hello1 = true 1123 hello2 = true 1124 default: 1125 c <- fmt.Errorf("unexpected output: %v", l) 1126 return 1127 } 1128 if hello1 && hello2 { 1129 break 1130 } 1131 } 1132 c <- nil 1133 }() 1134 1135 timeout := time.NewTimer(5 * time.Second) 1136 select { 1137 case <-timeout.C: 1138 t.Fatal("timeout") 1139 case err := <-c: 1140 if err != nil { 1141 t.Fatal(err) 1142 } 1143 } 1144 } 1145 1146 // TestConcurrentEvals2 shows that even though EvalWithContext calls Eval in a 1147 // goroutine, it indeed waits for Eval to terminate, and that therefore the code 1148 // called by EvalWithContext is sequential. And that there is no data race for the 1149 // interp package global vars or the interpreter fields in this case. 1150 func TestConcurrentEvals2(t *testing.T) { 1151 if testing.Short() { 1152 return 1153 } 1154 pin, pout := io.Pipe() 1155 defer func() { 1156 _ = pin.Close() 1157 _ = pout.Close() 1158 }() 1159 interpr := interp.New(interp.Options{Stdout: pout}) 1160 if err := interpr.Use(stdlib.Symbols); err != nil { 1161 t.Fatal(err) 1162 } 1163 1164 done := make(chan error) 1165 go func() { 1166 hello1 := false 1167 sc := bufio.NewScanner(pin) 1168 for sc.Scan() { 1169 l := sc.Text() 1170 if hello1 { 1171 if l == "hello world2" { 1172 break 1173 } else { 1174 done <- fmt.Errorf("unexpected output: %v", l) 1175 return 1176 } 1177 } 1178 if l == "hello world1" { 1179 hello1 = true 1180 } else { 1181 done <- fmt.Errorf("unexpected output: %v", l) 1182 return 1183 } 1184 } 1185 done <- nil 1186 }() 1187 1188 ctx := context.Background() 1189 if _, err := interpr.EvalWithContext(ctx, `import "time"`); err != nil { 1190 t.Fatal(err) 1191 } 1192 if _, err := interpr.EvalWithContext(ctx, `time.Sleep(time.Second); println("hello world1")`); err != nil { 1193 t.Fatal(err) 1194 } 1195 if _, err := interpr.EvalWithContext(ctx, `time.Sleep(time.Second); println("hello world2")`); err != nil { 1196 t.Fatal(err) 1197 } 1198 1199 timeout := time.NewTimer(5 * time.Second) 1200 select { 1201 case <-timeout.C: 1202 t.Fatal("timeout") 1203 case err := <-done: 1204 if err != nil { 1205 t.Fatal(err) 1206 } 1207 } 1208 } 1209 1210 // TestConcurrentEvals3 makes sure that we don't regress into data races at the package level, i.e from: 1211 // - global vars, which should obviously not be mutated. 1212 // - when calling Interpreter.Use, the symbols given as argument should be 1213 // copied when being inserted into interp.binPkg, and not directly used as-is. 1214 func TestConcurrentEvals3(t *testing.T) { 1215 if testing.Short() { 1216 return 1217 } 1218 allDone := make(chan bool) 1219 runREPL := func() { 1220 done := make(chan error) 1221 pinin, poutin := io.Pipe() 1222 pinout, poutout := io.Pipe() 1223 i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout}) 1224 if err := i.Use(stdlib.Symbols); err != nil { 1225 t.Fatal(err) 1226 } 1227 1228 go func() { 1229 _, _ = i.REPL() 1230 }() 1231 1232 input := []string{ 1233 `hello one`, 1234 `hello two`, 1235 `hello three`, 1236 } 1237 1238 go func() { 1239 sc := bufio.NewScanner(pinout) 1240 k := 0 1241 for sc.Scan() { 1242 l := sc.Text() 1243 if l != input[k] { 1244 done <- fmt.Errorf("unexpected output, want %q, got %q", input[k], l) 1245 return 1246 } 1247 k++ 1248 if k > 2 { 1249 break 1250 } 1251 } 1252 done <- nil 1253 }() 1254 1255 for _, v := range input { 1256 in := strings.NewReader(fmt.Sprintf("println(\"%s\")\n", v)) 1257 if _, err := io.Copy(poutin, in); err != nil { 1258 t.Fatal(err) 1259 } 1260 time.Sleep(time.Second) 1261 } 1262 1263 if err := <-done; err != nil { 1264 t.Fatal(err) 1265 } 1266 _ = pinin.Close() 1267 _ = poutin.Close() 1268 _ = pinout.Close() 1269 _ = poutout.Close() 1270 allDone <- true 1271 } 1272 1273 for i := 0; i < 2; i++ { 1274 go func() { 1275 runREPL() 1276 }() 1277 } 1278 1279 timeout := time.NewTimer(10 * time.Second) 1280 for i := 0; i < 2; i++ { 1281 select { 1282 case <-allDone: 1283 case <-timeout.C: 1284 t.Fatal("timeout") 1285 } 1286 } 1287 } 1288 1289 func TestConcurrentComposite1(t *testing.T) { 1290 testConcurrentComposite(t, "./testdata/concurrent/composite/composite_lit.go") 1291 } 1292 1293 func TestConcurrentComposite2(t *testing.T) { 1294 testConcurrentComposite(t, "./testdata/concurrent/composite/composite_sparse.go") 1295 } 1296 1297 func testConcurrentComposite(t *testing.T, filePath string) { 1298 t.Helper() 1299 1300 if testing.Short() { 1301 return 1302 } 1303 pin, pout := io.Pipe() 1304 i := interp.New(interp.Options{Stdout: pout}) 1305 if err := i.Use(stdlib.Symbols); err != nil { 1306 t.Fatal(err) 1307 } 1308 1309 errc := make(chan error) 1310 var output string 1311 go func() { 1312 sc := bufio.NewScanner(pin) 1313 k := 0 1314 for sc.Scan() { 1315 output += sc.Text() 1316 k++ 1317 if k > 1 { 1318 break 1319 } 1320 } 1321 errc <- nil 1322 }() 1323 1324 if _, err := i.EvalPath(filePath); err != nil { 1325 t.Fatal(err) 1326 } 1327 1328 _ = pin.Close() 1329 _ = pout.Close() 1330 1331 if err := <-errc; err != nil { 1332 t.Fatal(err) 1333 } 1334 1335 expected := "{hello}{hello}" 1336 if output != expected { 1337 t.Fatalf("unexpected output, want %q, got %q", expected, output) 1338 } 1339 } 1340 1341 func TestEvalScanner(t *testing.T) { 1342 if testing.Short() { 1343 return 1344 } 1345 type testCase struct { 1346 desc string 1347 src []string 1348 errorLine int 1349 } 1350 tests := []testCase{ 1351 { 1352 desc: "no error", 1353 src: []string{ 1354 `func main() {`, 1355 `println("foo")`, 1356 `}`, 1357 }, 1358 errorLine: -1, 1359 }, 1360 1361 { 1362 desc: "no parsing error, but block error", 1363 src: []string{ 1364 `func main() {`, 1365 `println(foo)`, 1366 `}`, 1367 }, 1368 errorLine: 2, 1369 }, 1370 { 1371 desc: "parsing error", 1372 src: []string{ 1373 `func main() {`, 1374 `println(/foo)`, 1375 `}`, 1376 }, 1377 errorLine: 1, 1378 }, 1379 { 1380 desc: "multi-line string literal", 1381 src: []string{ 1382 "var a = `hello", 1383 "there, how", 1384 "are you?`", 1385 }, 1386 errorLine: -1, 1387 }, 1388 1389 { 1390 desc: "multi-line comma operand", 1391 src: []string{ 1392 `println(2,`, 1393 `3)`, 1394 }, 1395 errorLine: -1, 1396 }, 1397 { 1398 desc: "multi-line arithmetic operand", 1399 src: []string{ 1400 `println(2. /`, 1401 `3.)`, 1402 }, 1403 errorLine: -1, 1404 }, 1405 { 1406 desc: "anonymous func call with no assignment", 1407 src: []string{ 1408 `func() { println(3) }()`, 1409 }, 1410 errorLine: -1, 1411 }, 1412 { 1413 // to make sure that special handling of the above anonymous, does not break this general case. 1414 desc: "just func", 1415 src: []string{ 1416 `func foo() { println(3) }`, 1417 }, 1418 errorLine: -1, 1419 }, 1420 { 1421 // to make sure that special handling of the above anonymous, does not break this general case. 1422 desc: "just method", 1423 src: []string{ 1424 `type bar string`, 1425 `func (b bar) foo() { println(3) }`, 1426 }, 1427 errorLine: -1, 1428 }, 1429 } 1430 1431 runREPL := func(t *testing.T, test testCase) { 1432 // TODO(mpl): use a pipe for the output as well, just as in TestConcurrentEvals5 1433 var stdout bytes.Buffer 1434 safeStdout := &safeBuffer{buf: &stdout} 1435 var stderr bytes.Buffer 1436 safeStderr := &safeBuffer{buf: &stderr} 1437 pin, pout := io.Pipe() 1438 i := interp.New(interp.Options{Stdin: pin, Stdout: safeStdout, Stderr: safeStderr}) 1439 defer func() { 1440 // Closing the pipe also takes care of making i.REPL terminate, 1441 // hence freeing its goroutine. 1442 _ = pin.Close() 1443 _ = pout.Close() 1444 }() 1445 1446 go func() { 1447 _, _ = i.REPL() 1448 }() 1449 for k, v := range test.src { 1450 if _, err := pout.Write([]byte(v + "\n")); err != nil { 1451 t.Error(err) 1452 } 1453 Sleep(100 * time.Millisecond) 1454 1455 errMsg := safeStderr.String() 1456 if k == test.errorLine { 1457 if errMsg == "" { 1458 t.Fatalf("test %q: statement %q should have produced an error", test.desc, v) 1459 } 1460 break 1461 } 1462 if errMsg != "" { 1463 t.Fatalf("test %q: unexpected error: %v", test.desc, errMsg) 1464 } 1465 } 1466 } 1467 1468 for _, test := range tests { 1469 runREPL(t, test) 1470 } 1471 } 1472 1473 type safeBuffer struct { 1474 mu sync.RWMutex 1475 buf *bytes.Buffer 1476 } 1477 1478 func (sb *safeBuffer) Read(p []byte) (int, error) { 1479 return sb.buf.Read(p) 1480 } 1481 1482 func (sb *safeBuffer) String() string { 1483 sb.mu.RLock() 1484 defer sb.mu.RUnlock() 1485 return sb.buf.String() 1486 } 1487 1488 func (sb *safeBuffer) Write(p []byte) (int, error) { 1489 sb.mu.Lock() 1490 defer sb.mu.Unlock() 1491 return sb.buf.Write(p) 1492 } 1493 1494 const ( 1495 // CITimeoutMultiplier is the multiplier for all timeouts in the CI. 1496 CITimeoutMultiplier = 3 1497 ) 1498 1499 // Sleep pauses the current goroutine for at least the duration d. 1500 func Sleep(d time.Duration) { 1501 d = applyCIMultiplier(d) 1502 time.Sleep(d) 1503 } 1504 1505 func applyCIMultiplier(timeout time.Duration) time.Duration { 1506 ci := os.Getenv("CI") 1507 if ci == "" { 1508 return timeout 1509 } 1510 b, err := strconv.ParseBool(ci) 1511 if err != nil || !b { 1512 return timeout 1513 } 1514 return time.Duration(float64(timeout) * CITimeoutMultiplier) 1515 } 1516 1517 func TestREPLCommands(t *testing.T) { 1518 if testing.Short() { 1519 return 1520 } 1521 _ = os.Setenv("YAEGI_PROMPT", "1") // To force prompts over non-tty streams 1522 defer func() { 1523 _ = os.Setenv("YAEGI_PROMPT", "0") 1524 }() 1525 allDone := make(chan bool) 1526 runREPL := func() { 1527 done := make(chan error) 1528 pinin, poutin := io.Pipe() 1529 pinout, poutout := io.Pipe() 1530 i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout}) 1531 if err := i.Use(stdlib.Symbols); err != nil { 1532 t.Fatal(err) 1533 } 1534 1535 go func() { 1536 _, _ = i.REPL() 1537 }() 1538 1539 defer func() { 1540 _ = pinin.Close() 1541 _ = poutin.Close() 1542 _ = pinout.Close() 1543 _ = poutout.Close() 1544 allDone <- true 1545 }() 1546 1547 input := []string{ 1548 `1/1`, 1549 `7/3`, 1550 `16/5`, 1551 `3./2`, // float 1552 `reflect.TypeOf(math_rand.Int)`, 1553 `reflect.TypeOf(crypto_rand.Int)`, 1554 } 1555 output := []string{ 1556 `1`, 1557 `2`, 1558 `3`, 1559 `1.5`, 1560 `func() int`, 1561 `func(io.Reader, *big.Int) (*big.Int, error)`, 1562 } 1563 1564 go func() { 1565 sc := bufio.NewScanner(pinout) 1566 k := 0 1567 for sc.Scan() { 1568 l := sc.Text() 1569 if l != "> : "+output[k] { 1570 done <- fmt.Errorf("unexpected output, want %q, got %q", output[k], l) 1571 return 1572 } 1573 k++ 1574 if k > 3 { 1575 break 1576 } 1577 } 1578 done <- nil 1579 }() 1580 1581 for _, v := range input { 1582 in := strings.NewReader(v + "\n") 1583 if _, err := io.Copy(poutin, in); err != nil { 1584 t.Fatal(err) 1585 } 1586 select { 1587 case err := <-done: 1588 if err != nil { 1589 t.Fatal(err) 1590 } 1591 return 1592 default: 1593 time.Sleep(time.Second) 1594 } 1595 } 1596 1597 if err := <-done; err != nil { 1598 t.Fatal(err) 1599 } 1600 } 1601 1602 go func() { 1603 runREPL() 1604 }() 1605 1606 timeout := time.NewTimer(10 * time.Second) 1607 select { 1608 case <-allDone: 1609 case <-timeout.C: 1610 t.Fatal("timeout") 1611 } 1612 } 1613 1614 func TestStdio(t *testing.T) { 1615 i := interp.New(interp.Options{}) 1616 if err := i.Use(stdlib.Symbols); err != nil { 1617 t.Fatal(err) 1618 } 1619 i.ImportUsed() 1620 if _, err := i.Eval(`var x = os.Stdout`); err != nil { 1621 t.Fatal(err) 1622 } 1623 v, _ := i.Eval(`x`) 1624 if _, ok := v.Interface().(*os.File); !ok { 1625 t.Fatalf("%v not *os.file", v.Interface()) 1626 } 1627 } 1628 1629 func TestIssue1142(t *testing.T) { 1630 i := interp.New(interp.Options{}) 1631 runTests(t, i, []testCase{ 1632 {src: "a := 1; // foo bar", res: "1"}, 1633 }) 1634 } 1635 1636 type Issue1149Array [3]float32 1637 1638 func (v Issue1149Array) Foo() string { return "foo" } 1639 func (v *Issue1149Array) Bar() string { return "foo" } 1640 1641 func TestIssue1149(t *testing.T) { 1642 i := interp.New(interp.Options{}) 1643 if err := i.Use(interp.Exports{ 1644 "pkg/pkg": map[string]reflect.Value{ 1645 "Type": reflect.ValueOf((*Issue1149Array)(nil)), 1646 }, 1647 }); err != nil { 1648 t.Fatal(err) 1649 } 1650 i.ImportUsed() 1651 1652 _, err := i.Eval(` 1653 type Type = pkg.Type 1654 `) 1655 if err != nil { 1656 t.Fatal(err) 1657 } 1658 1659 runTests(t, i, []testCase{ 1660 {src: "Type{1, 2, 3}.Foo()", res: "foo"}, 1661 {src: "Type{1, 2, 3}.Bar()", res: "foo"}, 1662 }) 1663 } 1664 1665 func TestIssue1150(t *testing.T) { 1666 i := interp.New(interp.Options{}) 1667 _, err := i.Eval(` 1668 type ArrayT [3]float32 1669 type SliceT []float32 1670 type StructT struct { A, B, C float32 } 1671 type StructT2 struct { A, B, C float32 } 1672 type FooerT interface { Foo() string } 1673 1674 func (v ArrayT) Foo() string { return "foo" } 1675 func (v SliceT) Foo() string { return "foo" } 1676 func (v StructT) Foo() string { return "foo" } 1677 func (v *StructT2) Foo() string { return "foo" } 1678 1679 type Array = ArrayT 1680 type Slice = SliceT 1681 type Struct = StructT 1682 type Struct2 = StructT2 1683 type Fooer = FooerT 1684 `) 1685 if err != nil { 1686 t.Fatal(err) 1687 } 1688 1689 runTests(t, i, []testCase{ 1690 {desc: "array", src: "Array{1, 2, 3}.Foo()", res: "foo"}, 1691 {desc: "slice", src: "Slice{1, 2, 3}.Foo()", res: "foo"}, 1692 {desc: "struct", src: "Struct{1, 2, 3}.Foo()", res: "foo"}, 1693 {desc: "*struct", src: "Struct2{1, 2, 3}.Foo()", res: "foo"}, 1694 {desc: "interface", src: "v := Fooer(Array{1, 2, 3}); v.Foo()", res: "foo"}, 1695 }) 1696 } 1697 1698 func TestIssue1151(t *testing.T) { 1699 type pkgStruct struct{ X int } 1700 type pkgArray [1]int 1701 1702 i := interp.New(interp.Options{}) 1703 if err := i.Use(interp.Exports{ 1704 "pkg/pkg": map[string]reflect.Value{ 1705 "Struct": reflect.ValueOf((*pkgStruct)(nil)), 1706 "Array": reflect.ValueOf((*pkgArray)(nil)), 1707 }, 1708 }); err != nil { 1709 t.Fatal(err) 1710 } 1711 i.ImportUsed() 1712 1713 runTests(t, i, []testCase{ 1714 {src: "x := pkg.Struct{1}", res: "{1}"}, 1715 {src: "x := pkg.Array{1}", res: "[1]"}, 1716 }) 1717 } 1718 1719 func TestPassArgs(t *testing.T) { 1720 i := interp.New(interp.Options{Args: []string{"arg0", "arg1"}}) 1721 if err := i.Use(stdlib.Symbols); err != nil { 1722 t.Fatal(err) 1723 } 1724 i.ImportUsed() 1725 runTests(t, i, []testCase{ 1726 {src: "os.Args", res: "[arg0 arg1]"}, 1727 }) 1728 } 1729 1730 func TestRestrictedEnv(t *testing.T) { 1731 i := interp.New(interp.Options{Env: []string{"foo=bar"}}) 1732 if err := i.Use(stdlib.Symbols); err != nil { 1733 t.Fatal(err) 1734 } 1735 i.ImportUsed() 1736 runTests(t, i, []testCase{ 1737 {src: `os.Getenv("foo")`, res: "bar"}, 1738 {src: `s, ok := os.LookupEnv("foo"); s`, res: "bar"}, 1739 {src: `s, ok := os.LookupEnv("foo"); ok`, res: "true"}, 1740 {src: `s, ok := os.LookupEnv("PATH"); s`, res: ""}, 1741 {src: `s, ok := os.LookupEnv("PATH"); ok`, res: "false"}, 1742 {src: `os.Setenv("foo", "baz"); os.Environ()`, res: "[foo=baz]"}, 1743 {src: `os.ExpandEnv("foo is ${foo}")`, res: "foo is baz"}, 1744 {src: `os.Unsetenv("foo"); os.Environ()`, res: "[]"}, 1745 {src: `os.Setenv("foo", "baz"); os.Environ()`, res: "[foo=baz]"}, 1746 {src: `os.Clearenv(); os.Environ()`, res: "[]"}, 1747 {src: `os.Setenv("foo", "baz"); os.Environ()`, res: "[foo=baz]"}, 1748 }) 1749 if s, ok := os.LookupEnv("foo"); ok { 1750 t.Fatal("expected \"\", got " + s) 1751 } 1752 } 1753 1754 func TestIssue1383(t *testing.T) { 1755 const src = ` 1756 package main 1757 1758 func main() { 1759 fmt.Println("Hello") 1760 } 1761 ` 1762 1763 interp := interp.New(interp.Options{}) 1764 err := interp.Use(stdlib.Symbols) 1765 if err != nil { 1766 t.Fatal(err) 1767 } 1768 _, err = interp.Eval(`import "fmt"`) 1769 if err != nil { 1770 t.Fatal(err) 1771 } 1772 1773 ast, err := parser.ParseFile(interp.FileSet(), "_.go", src, parser.DeclarationErrors) 1774 if err != nil { 1775 t.Fatal(err) 1776 } 1777 prog, err := interp.CompileAST(ast) 1778 if err != nil { 1779 t.Fatal(err) 1780 } 1781 _, err = interp.Execute(prog) 1782 if err != nil { 1783 t.Fatal(err) 1784 } 1785 } 1786 1787 func TestIssue1388(t *testing.T) { 1788 i := interp.New(interp.Options{Env: []string{"foo=bar"}}) 1789 err := i.Use(stdlib.Symbols) 1790 if err != nil { 1791 t.Fatal(err) 1792 } 1793 1794 _, err = i.Eval(`x := errors.New("")`) 1795 if err == nil { 1796 t.Fatal("Expected an error") 1797 } 1798 1799 _, err = i.Eval(`import "errors"`) 1800 if err != nil { 1801 t.Fatal(err) 1802 } 1803 1804 _, err = i.Eval(`x := errors.New("")`) 1805 if err != nil { 1806 t.Fatal(err) 1807 } 1808 }