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