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