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