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