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