1package goja
2
3import (
4	"errors"
5	"fmt"
6	"math"
7	"reflect"
8	"runtime"
9	"strconv"
10	"strings"
11	"testing"
12	"time"
13
14	"github.com/dop251/goja/parser"
15)
16
17func TestGlobalObjectProto(t *testing.T) {
18	const SCRIPT = `
19	this instanceof Object
20	`
21
22	testScript1(SCRIPT, valueTrue, t)
23}
24
25func TestUnicodeString(t *testing.T) {
26	const SCRIPT = `
27	var s = "Тест";
28	s.length === 4 && s[1] === "е";
29
30	`
31
32	testScript1(SCRIPT, valueTrue, t)
33}
34
35func Test2TierHierarchyProp(t *testing.T) {
36	const SCRIPT = `
37	var a = {};
38	Object.defineProperty(a, "test", {
39		value: 42,
40		writable: false,
41		enumerable: false,
42		configurable: true
43	});
44	var b = Object.create(a);
45	var c = Object.create(b);
46	c.test = 43;
47	c.test === 42 && !b.hasOwnProperty("test");
48
49	`
50
51	testScript1(SCRIPT, valueTrue, t)
52}
53
54func TestConstStringIter(t *testing.T) {
55	const SCRIPT = `
56
57	var count = 0;
58
59	for (var i in "1234") {
60    		for (var j in "1234567") {
61        		count++
62    		}
63	}
64
65	count;
66	`
67
68	testScript1(SCRIPT, intToValue(28), t)
69}
70
71func TestUnicodeConcat(t *testing.T) {
72	const SCRIPT = `
73
74	var s = "тест";
75	var s1 = "test";
76	var s2 = "абвгд";
77
78	s.concat(s1) === "тестtest" && s.concat(s1, s2) === "тестtestабвгд" && s1.concat(s, s2) === "testтестабвгд"
79		&& s.concat(s2) === "тестабвгд";
80
81	`
82
83	testScript1(SCRIPT, valueTrue, t)
84}
85
86func TestIndexOf(t *testing.T) {
87	const SCRIPT = `
88
89	"abc".indexOf("", 4)
90	`
91
92	testScript1(SCRIPT, intToValue(3), t)
93}
94
95func TestUnicodeIndexOf(t *testing.T) {
96	const SCRIPT = `
97	"абвгд".indexOf("вг", 1) === 2 && '中国'.indexOf('国') === 1
98	`
99
100	testScript1(SCRIPT, valueTrue, t)
101}
102
103func TestLastIndexOf(t *testing.T) {
104	const SCRIPT = `
105
106	"abcabab".lastIndexOf("ab", 3)
107	`
108
109	testScript1(SCRIPT, intToValue(3), t)
110}
111
112func TestUnicodeLastIndexOf(t *testing.T) {
113	const SCRIPT = `
114	"абвабаб".lastIndexOf("аб", 3)
115	`
116
117	testScript1(SCRIPT, intToValue(3), t)
118}
119
120func TestUnicodeLastIndexOf1(t *testing.T) {
121	const SCRIPT = `
122	"abꞐcde".lastIndexOf("cd");
123	`
124
125	testScript1(SCRIPT, intToValue(3), t)
126}
127
128func TestNumber(t *testing.T) {
129	const SCRIPT = `
130	(new Number(100111122133144155)).toString()
131	`
132
133	testScript1(SCRIPT, asciiString("100111122133144160"), t)
134}
135
136func TestFractionalNumberToStringRadix(t *testing.T) {
137	const SCRIPT = `
138	(new Number(123.456)).toString(36)
139	`
140
141	testScript1(SCRIPT, asciiString("3f.gez4w97ry"), t)
142}
143
144func TestNumberFormatRounding(t *testing.T) {
145	const SCRIPT = `
146	assert.sameValue((123.456).toExponential(undefined), "1.23456e+2", "undefined");
147	assert.sameValue((0.000001).toPrecision(2), "0.0000010")
148	assert.sameValue((-7).toPrecision(1), "-7");
149	assert.sameValue((-42).toPrecision(1), "-4e+1");
150	assert.sameValue((0.000001).toPrecision(1), "0.000001");
151	assert.sameValue((123.456).toPrecision(1), "1e+2", "1");
152	assert.sameValue((123.456).toPrecision(2), "1.2e+2", "2");
153
154	var n = new Number("0.000000000000000000001"); // 1e-21
155	assert.sameValue((n).toPrecision(1), "1e-21");
156	assert.sameValue((25).toExponential(0), "3e+1");
157	assert.sameValue((-25).toExponential(0), "-3e+1");
158	assert.sameValue((12345).toExponential(3), "1.235e+4");
159	assert.sameValue((25.5).toFixed(0), "26");
160	assert.sameValue((-25.5).toFixed(0), "-26");
161	assert.sameValue((99.9).toFixed(0), "100");
162	assert.sameValue((99.99).toFixed(1), "100.0");
163	`
164	testScript1(TESTLIB+SCRIPT, _undefined, t)
165}
166
167func TestSetFunc(t *testing.T) {
168	const SCRIPT = `
169	sum(40, 2);
170	`
171	r := New()
172	err := r.Set("sum", func(call FunctionCall) Value {
173		return r.ToValue(call.Argument(0).ToInteger() + call.Argument(1).ToInteger())
174	})
175	if err != nil {
176		t.Fatal(err)
177	}
178	v, err := r.RunString(SCRIPT)
179	if err != nil {
180		t.Fatal(err)
181	}
182	if i := v.ToInteger(); i != 42 {
183		t.Fatalf("Expected 42, got: %d", i)
184	}
185}
186
187func ExampleRuntime_Set_lexical() {
188	r := New()
189	_, err := r.RunString("let x")
190	if err != nil {
191		panic(err)
192	}
193	err = r.Set("x", 1)
194	if err != nil {
195		panic(err)
196	}
197	fmt.Print(r.Get("x"), r.GlobalObject().Get("x"))
198	// Output: 1 <nil>
199}
200
201func TestRecursiveRun(t *testing.T) {
202	// Make sure that a recursive call to Run*() correctly sets the environment and no stash or stack
203	// corruptions occur.
204	vm := New()
205	vm.Set("f", func() (Value, error) {
206		return vm.RunString("let x = 1; { let z = 100, z1 = 200, z2 = 300, z3 = 400; } x;")
207	})
208	res, err := vm.RunString(`
209	function f1() {
210		let x = 2;
211		eval('');
212		{
213			let y = 3;
214			let res = f();
215			if (x !== 2) { // check for stash corruption
216				throw new Error("x="+x);
217			}
218			if (y !== 3) { // check for stack corruption
219				throw new Error("y="+y);
220			}
221			return res;
222		}
223	};
224	f1();
225	`)
226	if err != nil {
227		t.Fatal(err)
228	}
229	if !res.SameAs(valueInt(1)) {
230		t.Fatal(res)
231	}
232}
233
234func TestObjectGetSet(t *testing.T) {
235	const SCRIPT = `
236		input.test++;
237		input;
238	`
239	r := New()
240	o := r.NewObject()
241	o.Set("test", 42)
242	r.Set("input", o)
243
244	v, err := r.RunString(SCRIPT)
245	if err != nil {
246		t.Fatal(err)
247	}
248	if o1, ok := v.(*Object); ok {
249		if v1 := o1.Get("test"); v1.Export() != int64(43) {
250			t.Fatalf("Unexpected test value: %v (%T)", v1, v1.Export())
251		}
252	}
253}
254
255func TestThrowFromNativeFunc(t *testing.T) {
256	const SCRIPT = `
257	var thrown;
258	try {
259		f();
260	} catch (e) {
261		thrown = e;
262	}
263	thrown;
264	`
265	r := New()
266	r.Set("f", func(call FunctionCall) Value {
267		panic(r.ToValue("testError"))
268	})
269
270	v, err := r.RunString(SCRIPT)
271	if err != nil {
272		t.Fatal(err)
273	}
274
275	if !v.Equals(asciiString("testError")) {
276		t.Fatalf("Unexpected result: %v", v)
277	}
278}
279
280func TestSetGoFunc(t *testing.T) {
281	const SCRIPT = `
282	f(40, 2)
283	`
284	r := New()
285	r.Set("f", func(a, b int) int {
286		return a + b
287	})
288
289	v, err := r.RunString(SCRIPT)
290	if err != nil {
291		t.Fatal(err)
292	}
293
294	if v.ToInteger() != 42 {
295		t.Fatalf("Unexpected result: %v", v)
296	}
297}
298
299func TestArgsKeys(t *testing.T) {
300	const SCRIPT = `
301	function testArgs2(x, y, z) {
302    		// Properties of the arguments object are enumerable.
303    		return Object.keys(arguments);
304	}
305
306	testArgs2(1,2).length
307	`
308
309	testScript1(SCRIPT, intToValue(2), t)
310}
311
312func TestIPowOverflow(t *testing.T) {
313	const SCRIPT = `
314	Math.pow(65536, 6)
315	`
316
317	testScript1(SCRIPT, floatToValue(7.922816251426434e+28), t)
318}
319
320func TestIPowZero(t *testing.T) {
321	const SCRIPT = `
322	Math.pow(0, 0)
323	`
324
325	testScript1(SCRIPT, intToValue(1), t)
326}
327
328func TestInterrupt(t *testing.T) {
329	const SCRIPT = `
330	var i = 0;
331	for (;;) {
332		i++;
333	}
334	`
335
336	vm := New()
337	time.AfterFunc(200*time.Millisecond, func() {
338		vm.Interrupt("halt")
339	})
340
341	_, err := vm.RunString(SCRIPT)
342	if err == nil {
343		t.Fatal("Err is nil")
344	}
345}
346
347func TestRuntime_ExportToNumbers(t *testing.T) {
348	vm := New()
349	t.Run("int8/no overflow", func(t *testing.T) {
350		var i8 int8
351		err := vm.ExportTo(vm.ToValue(-123), &i8)
352		if err != nil {
353			t.Fatal(err)
354		}
355		if i8 != -123 {
356			t.Fatalf("i8: %d", i8)
357		}
358	})
359
360	t.Run("int8/overflow", func(t *testing.T) {
361		var i8 int8
362		err := vm.ExportTo(vm.ToValue(333), &i8)
363		if err != nil {
364			t.Fatal(err)
365		}
366		if i8 != 77 {
367			t.Fatalf("i8: %d", i8)
368		}
369	})
370
371	t.Run("int64/uint64", func(t *testing.T) {
372		var ui64 uint64
373		err := vm.ExportTo(vm.ToValue(-1), &ui64)
374		if err != nil {
375			t.Fatal(err)
376		}
377		if ui64 != math.MaxUint64 {
378			t.Fatalf("ui64: %d", ui64)
379		}
380	})
381
382	t.Run("int8/float", func(t *testing.T) {
383		var i8 int8
384		err := vm.ExportTo(vm.ToValue(333.9234), &i8)
385		if err != nil {
386			t.Fatal(err)
387		}
388		if i8 != 77 {
389			t.Fatalf("i8: %d", i8)
390		}
391	})
392
393	t.Run("int8/object", func(t *testing.T) {
394		var i8 int8
395		err := vm.ExportTo(vm.NewObject(), &i8)
396		if err != nil {
397			t.Fatal(err)
398		}
399		if i8 != 0 {
400			t.Fatalf("i8: %d", i8)
401		}
402	})
403
404	t.Run("int/object_cust_valueOf", func(t *testing.T) {
405		var i int
406		obj, err := vm.RunString(`
407		({
408			valueOf: function() { return 42; }
409		})
410		`)
411		if err != nil {
412			t.Fatal(err)
413		}
414		err = vm.ExportTo(obj, &i)
415		if err != nil {
416			t.Fatal(err)
417		}
418		if i != 42 {
419			t.Fatalf("i: %d", i)
420		}
421	})
422
423	t.Run("float32/no_trunc", func(t *testing.T) {
424		var f float32
425		err := vm.ExportTo(vm.ToValue(1.234567), &f)
426		if err != nil {
427			t.Fatal(err)
428		}
429		if f != 1.234567 {
430			t.Fatalf("f: %f", f)
431		}
432	})
433
434	t.Run("float32/trunc", func(t *testing.T) {
435		var f float32
436		err := vm.ExportTo(vm.ToValue(1.234567890), &f)
437		if err != nil {
438			t.Fatal(err)
439		}
440		if f != float32(1.234567890) {
441			t.Fatalf("f: %f", f)
442		}
443	})
444
445	t.Run("float64", func(t *testing.T) {
446		var f float64
447		err := vm.ExportTo(vm.ToValue(1.234567), &f)
448		if err != nil {
449			t.Fatal(err)
450		}
451		if f != 1.234567 {
452			t.Fatalf("f: %f", f)
453		}
454	})
455
456	t.Run("float32/object", func(t *testing.T) {
457		var f float32
458		err := vm.ExportTo(vm.NewObject(), &f)
459		if err != nil {
460			t.Fatal(err)
461		}
462		if f == f { // expecting NaN
463			t.Fatalf("f: %f", f)
464		}
465	})
466
467	t.Run("float64/object", func(t *testing.T) {
468		var f float64
469		err := vm.ExportTo(vm.NewObject(), &f)
470		if err != nil {
471			t.Fatal(err)
472		}
473		if f == f { // expecting NaN
474			t.Fatalf("f: %f", f)
475		}
476	})
477
478}
479
480func TestRuntime_ExportToSlice(t *testing.T) {
481	const SCRIPT = `
482	var a = [1, 2, 3];
483	a;
484	`
485
486	vm := New()
487	v, err := vm.RunString(SCRIPT)
488	if err != nil {
489		t.Fatal(err)
490	}
491	var a []string
492	err = vm.ExportTo(v, &a)
493	if err != nil {
494		t.Fatal(err)
495	}
496	if l := len(a); l != 3 {
497		t.Fatalf("Unexpected len: %d", l)
498	}
499	if a[0] != "1" || a[1] != "2" || a[2] != "3" {
500		t.Fatalf("Unexpected value: %+v", a)
501	}
502}
503
504func TestRuntime_ExportToMap(t *testing.T) {
505	const SCRIPT = `
506	var m = {
507		"0": 1,
508		"1": 2,
509		"2": 3,
510	}
511	m;
512	`
513
514	vm := New()
515	v, err := vm.RunString(SCRIPT)
516	if err != nil {
517		t.Fatal(err)
518	}
519	var m map[int]string
520	err = vm.ExportTo(v, &m)
521	if err != nil {
522		t.Fatal(err)
523	}
524	if l := len(m); l != 3 {
525		t.Fatalf("Unexpected len: %d", l)
526	}
527	if m[0] != "1" || m[1] != "2" || m[2] != "3" {
528		t.Fatalf("Unexpected value: %+v", m)
529	}
530}
531
532func TestRuntime_ExportToMap1(t *testing.T) {
533	const SCRIPT = `
534	var m = {
535		"0": 1,
536		"1": 2,
537		"2": 3,
538	}
539	m;
540	`
541
542	vm := New()
543	v, err := vm.RunString(SCRIPT)
544	if err != nil {
545		t.Fatal(err)
546	}
547	var m map[string]string
548	err = vm.ExportTo(v, &m)
549	if err != nil {
550		t.Fatal(err)
551	}
552	if l := len(m); l != 3 {
553		t.Fatalf("Unexpected len: %d", l)
554	}
555	if m["0"] != "1" || m["1"] != "2" || m["2"] != "3" {
556		t.Fatalf("Unexpected value: %+v", m)
557	}
558}
559
560func TestRuntime_ExportToStruct(t *testing.T) {
561	const SCRIPT = `
562	var m = {
563		Test: 1,
564	}
565	m;
566	`
567	vm := New()
568	v, err := vm.RunString(SCRIPT)
569	if err != nil {
570		t.Fatal(err)
571	}
572
573	var o testGoReflectMethod_O
574	err = vm.ExportTo(v, &o)
575	if err != nil {
576		t.Fatal(err)
577	}
578
579	if o.Test != "1" {
580		t.Fatalf("Unexpected value: '%s'", o.Test)
581	}
582
583}
584
585func TestRuntime_ExportToStructPtr(t *testing.T) {
586	const SCRIPT = `
587	var m = {
588		Test: 1,
589	}
590	m;
591	`
592	vm := New()
593	v, err := vm.RunString(SCRIPT)
594	if err != nil {
595		t.Fatal(err)
596	}
597
598	var o *testGoReflectMethod_O
599	err = vm.ExportTo(v, &o)
600	if err != nil {
601		t.Fatal(err)
602	}
603
604	if o.Test != "1" {
605		t.Fatalf("Unexpected value: '%s'", o.Test)
606	}
607
608}
609
610func TestRuntime_ExportToStructAnonymous(t *testing.T) {
611	type BaseTestStruct struct {
612		A int64
613		B int64
614	}
615
616	type TestStruct struct {
617		BaseTestStruct
618		C string
619	}
620
621	const SCRIPT = `
622	var m = {
623		A: 1,
624		B: 2,
625		C: "testC"
626	}
627	m;
628	`
629	vm := New()
630	v, err := vm.RunString(SCRIPT)
631	if err != nil {
632		t.Fatal(err)
633	}
634
635	test := &TestStruct{}
636	err = vm.ExportTo(v, test)
637	if err != nil {
638		t.Fatal(err)
639	}
640
641	if test.A != 1 {
642		t.Fatalf("Unexpected value: '%d'", test.A)
643	}
644	if test.B != 2 {
645		t.Fatalf("Unexpected value: '%d'", test.B)
646	}
647	if test.C != "testC" {
648		t.Fatalf("Unexpected value: '%s'", test.C)
649	}
650
651}
652
653func TestRuntime_ExportToStructFromPtr(t *testing.T) {
654	vm := New()
655	v := vm.ToValue(&testGoReflectMethod_O{
656		field: "5",
657		Test:  "12",
658	})
659
660	var o testGoReflectMethod_O
661	err := vm.ExportTo(v, &o)
662	if err != nil {
663		t.Fatal(err)
664	}
665
666	if o.Test != "12" {
667		t.Fatalf("Unexpected value: '%s'", o.Test)
668	}
669	if o.field != "5" {
670		t.Fatalf("Unexpected value for field: '%s'", o.field)
671	}
672}
673
674func TestRuntime_ExportToStructWithPtrValues(t *testing.T) {
675	type BaseTestStruct struct {
676		A int64
677		B *int64
678	}
679
680	type TestStruct2 struct {
681		E string
682	}
683
684	type TestStruct struct {
685		BaseTestStruct
686		C *string
687		D *TestStruct2
688	}
689
690	const SCRIPT = `
691	var m = {
692		A: 1,
693		B: 2,
694		C: "testC",
695		D: {
696			E: "testE",
697		}
698	}
699	m;
700	`
701	vm := New()
702	v, err := vm.RunString(SCRIPT)
703	if err != nil {
704		t.Fatal(err)
705	}
706
707	test := &TestStruct{}
708	err = vm.ExportTo(v, test)
709	if err != nil {
710		t.Fatal(err)
711	}
712
713	if test.A != 1 {
714		t.Fatalf("Unexpected value: '%d'", test.A)
715	}
716	if test.B == nil || *test.B != 2 {
717		t.Fatalf("Unexpected value: '%v'", test.B)
718	}
719	if test.C == nil || *test.C != "testC" {
720		t.Fatalf("Unexpected value: '%v'", test.C)
721	}
722	if test.D == nil || test.D.E != "testE" {
723		t.Fatalf("Unexpected value: '%s'", test.D.E)
724	}
725
726}
727
728func TestRuntime_ExportToTime(t *testing.T) {
729	const SCRIPT = `
730	var dateStr = "2018-08-13T15:02:13+02:00";
731	var str = "test123";
732	`
733
734	vm := New()
735	_, err := vm.RunString(SCRIPT)
736	if err != nil {
737		t.Fatal(err)
738	}
739
740	var ti time.Time
741	err = vm.ExportTo(vm.Get("dateStr"), &ti)
742	if err != nil {
743		t.Fatal(err)
744	}
745	if ti.Format(time.RFC3339) != "2018-08-13T15:02:13+02:00" {
746		t.Fatalf("Unexpected value: '%s'", ti.Format(time.RFC3339))
747	}
748
749	err = vm.ExportTo(vm.Get("str"), &ti)
750	if err == nil {
751		t.Fatal("Expected err to not be nil")
752	}
753
754	var str string
755	err = vm.ExportTo(vm.Get("dateStr"), &str)
756	if err != nil {
757		t.Fatal(err)
758	}
759	if str != "2018-08-13T15:02:13+02:00" {
760		t.Fatalf("Unexpected value: '%s'", str)
761	}
762
763	d, err := vm.RunString(`new Date(1000)`)
764	if err != nil {
765		t.Fatal(err)
766	}
767
768	ti = time.Time{}
769	err = vm.ExportTo(d, &ti)
770	if err != nil {
771		t.Fatal(err)
772	}
773
774	if ti.UnixNano() != 1000*1e6 {
775		t.Fatal(ti)
776	}
777	if ti.Location() != time.Local {
778		t.Fatalf("Wrong location: %v", ti)
779	}
780}
781
782func ExampleRuntime_ExportTo_func() {
783	const SCRIPT = `
784	function f(param) {
785		return +param + 2;
786	}
787	`
788
789	vm := New()
790	_, err := vm.RunString(SCRIPT)
791	if err != nil {
792		panic(err)
793	}
794
795	var fn func(string) string
796	err = vm.ExportTo(vm.Get("f"), &fn)
797	if err != nil {
798		panic(err)
799	}
800
801	fmt.Println(fn("40")) // note, _this_ value in the function will be undefined.
802	// Output: 42
803}
804
805func ExampleRuntime_ExportTo_funcThrow() {
806	const SCRIPT = `
807	function f(param) {
808		throw new Error("testing");
809	}
810	`
811
812	vm := New()
813	_, err := vm.RunString(SCRIPT)
814	if err != nil {
815		panic(err)
816	}
817
818	var fn func(string) (string, error)
819	err = vm.ExportTo(vm.Get("f"), &fn)
820	if err != nil {
821		panic(err)
822	}
823	_, err = fn("")
824
825	fmt.Println(err)
826	// Output: Error: testing at f (<eval>:3:9(4))
827}
828
829func ExampleRuntime_ExportTo_funcVariadic() {
830	const SCRIPT = `
831	function f() {
832		return Array.prototype.join.call(arguments, ",");
833	}
834	`
835	vm := New()
836	_, err := vm.RunString(SCRIPT)
837	if err != nil {
838		panic(err)
839	}
840
841	var fn func(args ...interface{}) string
842	err = vm.ExportTo(vm.Get("f"), &fn)
843	if err != nil {
844		panic(err)
845	}
846	fmt.Println(fn("a", "b", 42))
847	// Output: a,b,42
848}
849
850func TestRuntime_ExportToFuncFail(t *testing.T) {
851	const SCRIPT = `
852	function f(param) {
853		return +param + 2;
854	}
855	`
856
857	type T struct {
858		Field1 int
859	}
860
861	var fn func(string) (T, error)
862
863	vm := New()
864	_, err := vm.RunString(SCRIPT)
865	if err != nil {
866		t.Fatal(err)
867	}
868
869	err = vm.ExportTo(vm.Get("f"), &fn)
870	if err != nil {
871		t.Fatal(err)
872	}
873
874	if _, err := fn("40"); err == nil {
875		t.Fatal("Expected error")
876	}
877}
878
879func TestRuntime_ExportToCallable(t *testing.T) {
880	const SCRIPT = `
881	function f(param) {
882		return +param + 2;
883	}
884	`
885	vm := New()
886	_, err := vm.RunString(SCRIPT)
887	if err != nil {
888		t.Fatal(err)
889	}
890
891	var c Callable
892	err = vm.ExportTo(vm.Get("f"), &c)
893	if err != nil {
894		t.Fatal(err)
895	}
896
897	res, err := c(Undefined(), vm.ToValue("40"))
898	if err != nil {
899		t.Fatal(err)
900	} else if !res.StrictEquals(vm.ToValue(42)) {
901		t.Fatalf("Unexpected value: %v", res)
902	}
903}
904
905func TestRuntime_ExportToObject(t *testing.T) {
906	const SCRIPT = `
907	var o = {"test": 42};
908	o;
909	`
910	vm := New()
911	_, err := vm.RunString(SCRIPT)
912	if err != nil {
913		t.Fatal(err)
914	}
915
916	var o *Object
917	err = vm.ExportTo(vm.Get("o"), &o)
918	if err != nil {
919		t.Fatal(err)
920	}
921
922	if v := o.Get("test"); !v.StrictEquals(vm.ToValue(42)) {
923		t.Fatalf("Unexpected value: %v", v)
924	}
925}
926
927func ExampleAssertFunction() {
928	vm := New()
929	_, err := vm.RunString(`
930	function sum(a, b) {
931		return a+b;
932	}
933	`)
934	if err != nil {
935		panic(err)
936	}
937	sum, ok := AssertFunction(vm.Get("sum"))
938	if !ok {
939		panic("Not a function")
940	}
941
942	res, err := sum(Undefined(), vm.ToValue(40), vm.ToValue(2))
943	if err != nil {
944		panic(err)
945	}
946	fmt.Println(res)
947	// Output: 42
948}
949
950func TestGoFuncError(t *testing.T) {
951	const SCRIPT = `
952	try {
953		f();
954	} catch (e) {
955		if (!(e instanceof GoError)) {
956			throw(e);
957		}
958		if (e.value.Error() !== "Test") {
959			throw("Unexpected value: " + e.value.Error());
960		}
961	}
962	`
963
964	f := func() error {
965		return errors.New("Test")
966	}
967
968	vm := New()
969	vm.Set("f", f)
970	_, err := vm.RunString(SCRIPT)
971	if err != nil {
972		t.Fatal(err)
973	}
974}
975
976func TestToValueNil(t *testing.T) {
977	type T struct{}
978	var a *T
979	vm := New()
980
981	if v := vm.ToValue(nil); !IsNull(v) {
982		t.Fatalf("nil: %v", v)
983	}
984
985	if v := vm.ToValue(a); !IsNull(v) {
986		t.Fatalf("struct ptr: %v", v)
987	}
988
989	var m map[string]interface{}
990	if v := vm.ToValue(m); !IsNull(v) {
991		t.Fatalf("map[string]interface{}: %v", v)
992	}
993
994	var ar []interface{}
995	if v := vm.ToValue(ar); !IsNull(v) {
996		t.Fatalf("[]interface{}: %v", v)
997	}
998
999	var arptr *[]interface{}
1000	if v := vm.ToValue(arptr); !IsNull(v) {
1001		t.Fatalf("*[]interface{}: %v", v)
1002	}
1003}
1004
1005func TestToValueFloat(t *testing.T) {
1006	vm := New()
1007	vm.Set("f64", float64(123))
1008	vm.Set("f32", float32(321))
1009
1010	v, err := vm.RunString("f64 === 123 && f32 === 321")
1011	if err != nil {
1012		t.Fatal(err)
1013	}
1014	if v.Export().(bool) != true {
1015		t.Fatalf("StrictEquals for golang float failed")
1016	}
1017}
1018
1019func TestToValueInterface(t *testing.T) {
1020
1021	f := func(i interface{}) bool {
1022		return i == t
1023	}
1024	vm := New()
1025	vm.Set("f", f)
1026	vm.Set("t", t)
1027	v, err := vm.RunString(`f(t)`)
1028	if err != nil {
1029		t.Fatal(err)
1030	}
1031	if v != valueTrue {
1032		t.Fatalf("v: %v", v)
1033	}
1034}
1035
1036func TestJSONEscape(t *testing.T) {
1037	const SCRIPT = `
1038	var a = "\\+1";
1039	JSON.stringify(a);
1040	`
1041
1042	testScript1(SCRIPT, asciiString(`"\\+1"`), t)
1043}
1044
1045func TestJSONObjectInArray(t *testing.T) {
1046	const SCRIPT = `
1047	var a = "[{\"a\":1},{\"a\":2}]";
1048	JSON.stringify(JSON.parse(a)) == a;
1049	`
1050
1051	testScript1(SCRIPT, valueTrue, t)
1052}
1053
1054func TestJSONQuirkyNumbers(t *testing.T) {
1055	const SCRIPT = `
1056	var s;
1057	s = JSON.stringify(NaN);
1058	if (s != "null") {
1059		throw new Error("NaN: " + s);
1060	}
1061
1062	s = JSON.stringify(Infinity);
1063	if (s != "null") {
1064		throw new Error("Infinity: " + s);
1065	}
1066
1067	s = JSON.stringify(-Infinity);
1068	if (s != "null") {
1069		throw new Error("-Infinity: " + s);
1070	}
1071
1072	`
1073
1074	testScript1(SCRIPT, _undefined, t)
1075}
1076
1077func TestJSONNil(t *testing.T) {
1078	const SCRIPT = `
1079	JSON.stringify(i);
1080	`
1081
1082	vm := New()
1083	var i interface{}
1084	vm.Set("i", i)
1085	ret, err := vm.RunString(SCRIPT)
1086	if err != nil {
1087		t.Fatal(err)
1088	}
1089
1090	if ret.String() != "null" {
1091		t.Fatalf("Expected 'null', got: %v", ret)
1092	}
1093}
1094
1095type customJsonEncodable struct{}
1096
1097func (*customJsonEncodable) JsonEncodable() interface{} {
1098	return "Test"
1099}
1100
1101func TestJsonEncodable(t *testing.T) {
1102	var s customJsonEncodable
1103
1104	vm := New()
1105	vm.Set("s", &s)
1106
1107	ret, err := vm.RunString("JSON.stringify(s)")
1108	if err != nil {
1109		t.Fatal(err)
1110	}
1111	if !ret.StrictEquals(vm.ToValue("\"Test\"")) {
1112		t.Fatalf("Expected \"Test\", got: %v", ret)
1113	}
1114}
1115
1116func TestSortComparatorReturnValues(t *testing.T) {
1117	const SCRIPT = `
1118	var a = [];
1119	for (var i = 0; i < 12; i++) {
1120	    a[i] = i;
1121	}
1122
1123	a.sort(function(x, y) { return y - x });
1124
1125	for (var i = 0; i < 12; i++) {
1126	    if (a[i] !== 11-i) {
1127		throw new Error("Value at index " + i + " is incorrect: " + a[i]);
1128	    }
1129	}
1130	`
1131
1132	testScript1(SCRIPT, _undefined, t)
1133}
1134
1135func TestSortComparatorReturnValueFloats(t *testing.T) {
1136	const SCRIPT = `
1137	var a = [
1138		5.97,
1139		9.91,
1140		4.13,
1141		9.28,
1142		3.29,
1143	];
1144	a.sort( function(a, b) { return a - b; } );
1145	for (var i = 1; i < a.length; i++) {
1146		if (a[i] < a[i-1]) {
1147			throw new Error("Array is not sorted: " + a);
1148		}
1149	}
1150	`
1151	testScript1(SCRIPT, _undefined, t)
1152}
1153
1154func TestSortComparatorReturnValueNegZero(t *testing.T) {
1155	const SCRIPT = `
1156	var a = [2, 1];
1157	a.sort( function(a, b) { return a > b ? 0 : -0; } );
1158	for (var i = 1; i < a.length; i++) {
1159		if (a[i] < a[i-1]) {
1160			throw new Error("Array is not sorted: " + a);
1161		}
1162	}
1163	`
1164	testScript1(SCRIPT, _undefined, t)
1165}
1166
1167func TestNilApplyArg(t *testing.T) {
1168	const SCRIPT = `
1169	(function x(a, b) {
1170		return a === undefined && b === 1;
1171        }).apply(this, [,1])
1172	`
1173
1174	testScript1(SCRIPT, valueTrue, t)
1175}
1176
1177func TestNilCallArg(t *testing.T) {
1178	const SCRIPT = `
1179	"use strict";
1180	function f(a) {
1181		return this === undefined && a === undefined;
1182	}
1183	`
1184	vm := New()
1185	prg := MustCompile("test.js", SCRIPT, false)
1186	vm.RunProgram(prg)
1187	if f, ok := AssertFunction(vm.Get("f")); ok {
1188		v, err := f(nil, nil)
1189		if err != nil {
1190			t.Fatal(err)
1191		}
1192		if !v.StrictEquals(valueTrue) {
1193			t.Fatalf("Unexpected result: %v", v)
1194		}
1195	}
1196}
1197
1198func TestNullCallArg(t *testing.T) {
1199	const SCRIPT = `
1200	f(null);
1201	`
1202	vm := New()
1203	prg := MustCompile("test.js", SCRIPT, false)
1204	vm.Set("f", func(x *int) bool {
1205		return x == nil
1206	})
1207
1208	v, err := vm.RunProgram(prg)
1209	if err != nil {
1210		t.Fatal(err)
1211	}
1212
1213	if !v.StrictEquals(valueTrue) {
1214		t.Fatalf("Unexpected result: %v", v)
1215	}
1216}
1217
1218func TestObjectKeys(t *testing.T) {
1219	const SCRIPT = `
1220	var o = { a: 1, b: 2, c: 3, d: 4 };
1221	o;
1222	`
1223
1224	vm := New()
1225	prg := MustCompile("test.js", SCRIPT, false)
1226
1227	res, err := vm.RunProgram(prg)
1228	if err != nil {
1229		t.Fatal(err)
1230	}
1231
1232	if o, ok := res.(*Object); ok {
1233		keys := o.Keys()
1234		if !reflect.DeepEqual(keys, []string{"a", "b", "c", "d"}) {
1235			t.Fatalf("Unexpected keys: %v", keys)
1236		}
1237	}
1238}
1239
1240func TestReflectCallExtraArgs(t *testing.T) {
1241	const SCRIPT = `
1242	f(41, "extra")
1243	`
1244	f := func(x int) int {
1245		return x + 1
1246	}
1247
1248	vm := New()
1249	vm.Set("f", f)
1250
1251	prg := MustCompile("test.js", SCRIPT, false)
1252
1253	res, err := vm.RunProgram(prg)
1254	if err != nil {
1255		t.Fatal(err)
1256	}
1257	if !res.StrictEquals(intToValue(42)) {
1258		t.Fatalf("Unexpected result: %v", res)
1259	}
1260}
1261
1262func TestReflectCallNotEnoughArgs(t *testing.T) {
1263	const SCRIPT = `
1264	f(42)
1265	`
1266	vm := New()
1267
1268	f := func(x, y int, z *int, s string) (int, error) {
1269		if z != nil {
1270			return 0, fmt.Errorf("z is not nil")
1271		}
1272		if s != "" {
1273			return 0, fmt.Errorf("s is not \"\"")
1274		}
1275		return x + y, nil
1276	}
1277
1278	vm.Set("f", f)
1279
1280	prg := MustCompile("test.js", SCRIPT, false)
1281
1282	res, err := vm.RunProgram(prg)
1283	if err != nil {
1284		t.Fatal(err)
1285	}
1286	if !res.StrictEquals(intToValue(42)) {
1287		t.Fatalf("Unexpected result: %v", res)
1288	}
1289}
1290
1291func TestReflectCallVariadic(t *testing.T) {
1292	const SCRIPT = `
1293	var r = f("Hello %s, %d", "test", 42);
1294	if (r !== "Hello test, 42") {
1295		throw new Error("test 1 has failed: " + r);
1296	}
1297
1298	r = f("Hello %s, %d", ["test", 42]);
1299	if (r !== "Hello test, 42") {
1300		throw new Error("test 2 has failed: " + r);
1301	}
1302
1303	r = f("Hello %s, %s", "test");
1304	if (r !== "Hello test, %!s(MISSING)") {
1305		throw new Error("test 3 has failed: " + r);
1306	}
1307
1308	r = f();
1309	if (r !== "") {
1310		throw new Error("test 4 has failed: " + r);
1311	}
1312
1313	`
1314
1315	vm := New()
1316	vm.Set("f", fmt.Sprintf)
1317
1318	prg := MustCompile("test.js", SCRIPT, false)
1319
1320	_, err := vm.RunProgram(prg)
1321	if err != nil {
1322		t.Fatal(err)
1323	}
1324}
1325
1326func TestReflectNullValueArgument(t *testing.T) {
1327	rt := New()
1328	rt.Set("fn", func(v Value) {
1329		if v == nil {
1330			t.Error("null becomes nil")
1331		}
1332		if !IsNull(v) {
1333			t.Error("null is not null")
1334		}
1335	})
1336	rt.RunString(`fn(null);`)
1337}
1338
1339type testNativeConstructHelper struct {
1340	rt   *Runtime
1341	base int64
1342	// any other state
1343}
1344
1345func (t *testNativeConstructHelper) calc(call FunctionCall) Value {
1346	return t.rt.ToValue(t.base + call.Argument(0).ToInteger())
1347}
1348
1349func TestNativeConstruct(t *testing.T) {
1350	const SCRIPT = `
1351	var f = new F(40);
1352	f instanceof F && f.method() === 42 && f.calc(2) === 42;
1353	`
1354
1355	rt := New()
1356
1357	method := func(call FunctionCall) Value {
1358		return rt.ToValue(42)
1359	}
1360
1361	rt.Set("F", func(call ConstructorCall) *Object { // constructor signature (as opposed to 'func(FunctionCall) Value')
1362		h := &testNativeConstructHelper{
1363			rt:   rt,
1364			base: call.Argument(0).ToInteger(),
1365		}
1366		call.This.Set("method", method)
1367		call.This.Set("calc", h.calc)
1368		return nil // or any other *Object which will be used instead of call.This
1369	})
1370
1371	prg := MustCompile("test.js", SCRIPT, false)
1372
1373	res, err := rt.RunProgram(prg)
1374	if err != nil {
1375		t.Fatal(err)
1376	}
1377
1378	if !res.StrictEquals(valueTrue) {
1379		t.Fatalf("Unexpected result: %v", res)
1380	}
1381
1382	if fn, ok := AssertFunction(rt.Get("F")); ok {
1383		v, err := fn(nil, rt.ToValue(42))
1384		if err != nil {
1385			t.Fatal(err)
1386		}
1387		if o, ok := v.(*Object); ok {
1388			if o.Get("method") == nil {
1389				t.Fatal("No method")
1390			}
1391		} else {
1392			t.Fatal("Not an object")
1393		}
1394	} else {
1395		t.Fatal("Not a function")
1396	}
1397
1398	resp := &testNativeConstructHelper{}
1399	value := rt.ToValue(resp)
1400	if value.Export() != resp {
1401		t.Fatal("no")
1402	}
1403}
1404
1405func TestCreateObject(t *testing.T) {
1406	const SCRIPT = `
1407	inst instanceof C;
1408	`
1409
1410	r := New()
1411	c := r.ToValue(func(call ConstructorCall) *Object {
1412		return nil
1413	})
1414
1415	proto := c.(*Object).Get("prototype").(*Object)
1416
1417	inst := r.CreateObject(proto)
1418
1419	r.Set("C", c)
1420	r.Set("inst", inst)
1421
1422	prg := MustCompile("test.js", SCRIPT, false)
1423
1424	res, err := r.RunProgram(prg)
1425	if err != nil {
1426		t.Fatal(err)
1427	}
1428
1429	if !res.StrictEquals(valueTrue) {
1430		t.Fatalf("Unexpected result: %v", res)
1431	}
1432}
1433
1434func TestInterruptInWrappedFunction(t *testing.T) {
1435	rt := New()
1436	v, err := rt.RunString(`
1437		var fn = function() {
1438			while (true) {}
1439		};
1440		fn;
1441	`)
1442	if err != nil {
1443		t.Fatal(err)
1444	}
1445	fn, ok := AssertFunction(v)
1446	if !ok {
1447		t.Fatal("Not a function")
1448	}
1449	go func() {
1450		<-time.After(10 * time.Millisecond)
1451		rt.Interrupt(errors.New("hi"))
1452	}()
1453
1454	_, err = fn(nil)
1455	if err == nil {
1456		t.Fatal("expected error")
1457	}
1458	if _, ok := err.(*InterruptedError); !ok {
1459		t.Fatalf("Wrong error type: %T", err)
1460	}
1461}
1462
1463func TestRunLoopPreempt(t *testing.T) {
1464	vm := New()
1465	v, err := vm.RunString("(function() {for (;;) {}})")
1466	if err != nil {
1467		t.Fatal(err)
1468	}
1469
1470	fn, ok := AssertFunction(v)
1471	if !ok {
1472		t.Fatal("Not a function")
1473	}
1474
1475	go func() {
1476		<-time.After(100 * time.Millisecond)
1477		runtime.GC() // this hangs if the vm loop does not have any preemption points
1478		vm.Interrupt(errors.New("hi"))
1479	}()
1480
1481	_, err = fn(nil)
1482	if err == nil {
1483		t.Fatal("expected error")
1484	}
1485	if _, ok := err.(*InterruptedError); !ok {
1486		t.Fatalf("Wrong error type: %T", err)
1487	}
1488}
1489
1490func TestNaN(t *testing.T) {
1491	if !IsNaN(_NaN) {
1492		t.Fatal("IsNaN() doesn't detect NaN")
1493	}
1494	if IsNaN(Undefined()) {
1495		t.Fatal("IsNaN() says undefined is a NaN")
1496	}
1497	if !IsNaN(NaN()) {
1498		t.Fatal("NaN() doesn't return NaN")
1499	}
1500}
1501
1502func TestInf(t *testing.T) {
1503	if !IsInfinity(_positiveInf) {
1504		t.Fatal("IsInfinity() doesn't detect +Inf")
1505	}
1506	if !IsInfinity(_negativeInf) {
1507		t.Fatal("IsInfinity() doesn't detect -Inf")
1508	}
1509	if IsInfinity(Undefined()) {
1510		t.Fatal("IsInfinity() says undefined is a Infinity")
1511	}
1512	if !IsInfinity(PositiveInf()) {
1513		t.Fatal("PositiveInfinity() doesn't return Inf")
1514	}
1515	if !IsInfinity(NegativeInf()) {
1516		t.Fatal("NegativeInfinity() doesn't return Inf")
1517	}
1518}
1519
1520func TestRuntimeNew(t *testing.T) {
1521	vm := New()
1522	v, err := vm.New(vm.Get("Number"), vm.ToValue("12345"))
1523	if err != nil {
1524		t.Fatal(err)
1525	}
1526	if n, ok := v.Export().(int64); ok {
1527		if n != 12345 {
1528			t.Fatalf("n: %v", n)
1529		}
1530	} else {
1531		t.Fatalf("v: %T", v)
1532	}
1533}
1534
1535func TestAutoBoxing(t *testing.T) {
1536	const SCRIPT = `
1537	function f() {
1538		'use strict';
1539		var a = 1;
1540		var thrown1 = false;
1541		var thrown2 = false;
1542		try {
1543			a.test = 42;
1544		} catch (e) {
1545			thrown1 = e instanceof TypeError;
1546		}
1547		try {
1548			a["test1"] = 42;
1549		} catch (e) {
1550			thrown2 = e instanceof TypeError;
1551		}
1552		return thrown1 && thrown2;
1553	}
1554	var a = 1;
1555	a.test = 42; // should not throw
1556	a["test1"] = 42; // should not throw
1557	a.test === undefined && a.test1 === undefined && f();
1558	`
1559
1560	testScript1(SCRIPT, valueTrue, t)
1561}
1562
1563func TestProtoGetter(t *testing.T) {
1564	const SCRIPT = `
1565	({}).__proto__ === Object.prototype && [].__proto__ === Array.prototype;
1566	`
1567	testScript1(SCRIPT, valueTrue, t)
1568}
1569
1570func TestFuncProto(t *testing.T) {
1571	const SCRIPT = `
1572	"use strict";
1573	function A() {}
1574	A.__proto__ = Object;
1575	A.prototype = {};
1576
1577	function B() {}
1578	B.__proto__ = Object.create(null);
1579	var thrown = false;
1580	try {
1581		delete B.prototype;
1582	} catch (e) {
1583		thrown = e instanceof TypeError;
1584	}
1585	thrown;
1586	`
1587	testScript1(SCRIPT, valueTrue, t)
1588}
1589
1590func TestSymbol1(t *testing.T) {
1591	const SCRIPT = `
1592		Symbol.toPrimitive[Symbol.toPrimitive]() === Symbol.toPrimitive;
1593	`
1594
1595	testScript1(SCRIPT, valueTrue, t)
1596}
1597
1598func TestFreezeSymbol(t *testing.T) {
1599	const SCRIPT = `
1600		var s = Symbol(1);
1601		var o = {};
1602		o[s] = 42;
1603		Object.freeze(o);
1604		o[s] = 43;
1605		o[s] === 42 && Object.isFrozen(o);
1606	`
1607
1608	testScript1(SCRIPT, valueTrue, t)
1609}
1610
1611func TestToPropertyKey(t *testing.T) {
1612	const SCRIPT = `
1613	var sym = Symbol(42);
1614	var callCount = 0;
1615
1616	var wrapper = {
1617	  toString: function() {
1618		callCount += 1;
1619		return sym;
1620	  },
1621	  valueOf: function() {
1622		$ERROR("valueOf() called");
1623	  }
1624	};
1625
1626	var o = {};
1627	o[wrapper] = function() { return "test" };
1628	assert.sameValue(o[wrapper], o[sym], "o[wrapper] === o[sym]");
1629	assert.sameValue(o[wrapper](), "test", "o[wrapper]()");
1630	assert.sameValue(o[sym](), "test", "o[sym]()");
1631
1632	var wrapper1 = {};
1633	wrapper1[Symbol.toPrimitive] = function(hint) {
1634		if (hint === "string" || hint === "default") {
1635			return "1";
1636		}
1637		if (hint === "number") {
1638			return 2;
1639		}
1640		$ERROR("Unknown hint value "+hint);
1641	};
1642	var a = [];
1643	a[wrapper1] = 42;
1644	assert.sameValue(a[1], 42, "a[1]");
1645	assert.sameValue(a[1], a[wrapper1], "a[1] === a[wrapper1]");
1646	`
1647
1648	testScript1(TESTLIB+SCRIPT, _undefined, t)
1649}
1650
1651func TestPrimThisValue(t *testing.T) {
1652	const SCRIPT = `
1653	function t() {
1654		'use strict';
1655
1656		Boolean.prototype.toString = function() {
1657		  return typeof this;
1658		};
1659
1660		assert.sameValue(true.toLocaleString(), "boolean");
1661
1662		Boolean.prototype[Symbol.iterator] = function() {
1663			return [typeof this][Symbol.iterator]();
1664		}
1665		var s = new Set(true);
1666		assert.sameValue(s.size, 1, "size");
1667		assert.sameValue(s.has("boolean"), true, "s.has('boolean')");
1668	}
1669	t();
1670	`
1671
1672	testScript1(TESTLIB+SCRIPT, _undefined, t)
1673}
1674
1675func TestPrimThisValueGetter(t *testing.T) {
1676	const SCRIPT = `
1677	function t() {
1678		'use strict';
1679		Object.defineProperty(Boolean.prototype, "toString", {
1680		  get: function() {
1681			var v = typeof this;
1682			return function() {
1683			  return v;
1684			};
1685		  }
1686		});
1687
1688		assert.sameValue(true.toLocaleString(), "boolean");
1689	}
1690	t();
1691	`
1692
1693	testScript1(TESTLIB+SCRIPT, _undefined, t)
1694}
1695
1696func TestObjSetSym(t *testing.T) {
1697	const SCRIPT = `
1698	'use strict';
1699	var sym = Symbol(true);
1700	var p1 = Object.create(null);
1701	var p2 = Object.create(p1);
1702
1703	Object.defineProperty(p1, sym, {
1704	value: 42
1705	});
1706
1707	Object.defineProperty(p2, sym, {
1708	value: 43,
1709	writable: true,
1710	});
1711	var o = Object.create(p2);
1712	o[sym] = 44;
1713	o[sym];
1714	`
1715	testScript1(SCRIPT, intToValue(44), t)
1716}
1717
1718func TestObjSet(t *testing.T) {
1719	const SCRIPT = `
1720	'use strict';
1721	var p1 = Object.create(null);
1722	var p2 = Object.create(p1);
1723
1724	Object.defineProperty(p1, "test", {
1725	value: 42
1726	});
1727
1728	Object.defineProperty(p2, "test", {
1729	value: 43,
1730	writable: true,
1731	});
1732	var o = Object.create(p2);
1733	o.test = 44;
1734	o.test;
1735	`
1736	testScript1(SCRIPT, intToValue(44), t)
1737}
1738
1739func TestToValueNilValue(t *testing.T) {
1740	r := New()
1741	var a Value
1742	r.Set("a", a)
1743	ret, err := r.RunString(`
1744	""+a;
1745	`)
1746	if err != nil {
1747		t.Fatal(err)
1748	}
1749	if !asciiString("null").SameAs(ret) {
1750		t.Fatalf("ret: %v", ret)
1751	}
1752}
1753
1754func TestDateConversion(t *testing.T) {
1755	now := time.Now()
1756	vm := New()
1757	val, err := vm.New(vm.Get("Date").ToObject(vm), vm.ToValue(now.UnixNano()/1e6))
1758	if err != nil {
1759		t.Fatal(err)
1760	}
1761	vm.Set("d", val)
1762	res, err := vm.RunString(`+d`)
1763	if err != nil {
1764		t.Fatal(err)
1765	}
1766	if exp := res.Export(); exp != now.UnixNano()/1e6 {
1767		t.Fatalf("Value does not match: %v", exp)
1768	}
1769	vm.Set("goval", now)
1770	res, err = vm.RunString(`+(new Date(goval.UnixNano()/1e6))`)
1771	if err != nil {
1772		t.Fatal(err)
1773	}
1774	if exp := res.Export(); exp != now.UnixNano()/1e6 {
1775		t.Fatalf("Value does not match: %v", exp)
1776	}
1777}
1778
1779func TestNativeCtorNewTarget(t *testing.T) {
1780	const SCRIPT = `
1781	function NewTarget() {
1782	}
1783
1784	var o = Reflect.construct(Number, [1], NewTarget);
1785	o.__proto__ === NewTarget.prototype && o.toString() === "[object Number]";
1786	`
1787	testScript1(SCRIPT, valueTrue, t)
1788}
1789
1790func TestNativeCtorNonNewCall(t *testing.T) {
1791	vm := New()
1792	vm.Set(`Animal`, func(call ConstructorCall) *Object {
1793		obj := call.This
1794		obj.Set(`name`, call.Argument(0).String())
1795		obj.Set(`eat`, func(call FunctionCall) Value {
1796			self := call.This.(*Object)
1797			return vm.ToValue(fmt.Sprintf("%s eat", self.Get(`name`)))
1798		})
1799		return nil
1800	})
1801	v, err := vm.RunString(`
1802
1803	function __extends(d, b){
1804		function __() {
1805			this.constructor = d;
1806		}
1807		d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
1808	}
1809
1810	var Cat = (function (_super) {
1811		__extends(Cat, _super);
1812		function Cat() {
1813			return _super.call(this, "cat") || this;
1814		}
1815		return Cat;
1816	}(Animal));
1817
1818	var cat = new Cat();
1819	cat instanceof Cat && cat.eat() === "cat eat";
1820	`)
1821	if err != nil {
1822		t.Fatal(err)
1823	}
1824	if v != valueTrue {
1825		t.Fatal(v)
1826	}
1827}
1828
1829func ExampleNewSymbol() {
1830	sym1 := NewSymbol("66")
1831	sym2 := NewSymbol("66")
1832	fmt.Printf("%s %s %v", sym1, sym2, sym1.Equals(sym2))
1833	// Output: 66 66 false
1834}
1835
1836func ExampleObject_SetSymbol() {
1837	type IterResult struct {
1838		Done  bool
1839		Value Value
1840	}
1841
1842	vm := New()
1843	vm.SetFieldNameMapper(UncapFieldNameMapper()) // to use IterResult
1844
1845	o := vm.NewObject()
1846	o.SetSymbol(SymIterator, func() *Object {
1847		count := 0
1848		iter := vm.NewObject()
1849		iter.Set("next", func() IterResult {
1850			if count < 10 {
1851				count++
1852				return IterResult{
1853					Value: vm.ToValue(count),
1854				}
1855			}
1856			return IterResult{
1857				Done: true,
1858			}
1859		})
1860		return iter
1861	})
1862	vm.Set("o", o)
1863
1864	res, err := vm.RunString(`
1865	var acc = "";
1866	for (var v of o) {
1867		acc += v + " ";
1868	}
1869	acc;
1870	`)
1871	if err != nil {
1872		panic(err)
1873	}
1874	fmt.Println(res)
1875	// Output: 1 2 3 4 5 6 7 8 9 10
1876}
1877
1878func ExampleRuntime_NewArray() {
1879	vm := New()
1880	array := vm.NewArray(1, 2, true)
1881	vm.Set("array", array)
1882	res, err := vm.RunString(`
1883	var acc = "";
1884	for (var v of array) {
1885		acc += v + " ";
1886	}
1887	acc;
1888	`)
1889	if err != nil {
1890		panic(err)
1891	}
1892	fmt.Println(res)
1893	// Output: 1 2 true
1894}
1895
1896func ExampleRuntime_SetParserOptions() {
1897	vm := New()
1898	vm.SetParserOptions(parser.WithDisableSourceMaps)
1899
1900	res, err := vm.RunString(`
1901	"I did not hang!";
1902//# sourceMappingURL=/dev/zero`)
1903
1904	if err != nil {
1905		panic(err)
1906	}
1907	fmt.Println(res.String())
1908	// Output: I did not hang!
1909}
1910
1911func TestRuntime_SetParserOptions_Eval(t *testing.T) {
1912	vm := New()
1913	vm.SetParserOptions(parser.WithDisableSourceMaps)
1914
1915	_, err := vm.RunString(`
1916	eval("//# sourceMappingURL=/dev/zero");
1917	`)
1918	if err != nil {
1919		t.Fatal(err)
1920	}
1921}
1922
1923func TestNativeCallWithRuntimeParameter(t *testing.T) {
1924	vm := New()
1925	vm.Set("f", func(_ FunctionCall, r *Runtime) Value {
1926		if r == vm {
1927			return valueTrue
1928		}
1929		return valueFalse
1930	})
1931	ret, err := vm.RunString(`f()`)
1932	if err != nil {
1933		t.Fatal(err)
1934	}
1935	if ret != valueTrue {
1936		t.Fatal(ret)
1937	}
1938}
1939
1940func TestNestedEnumerate(t *testing.T) {
1941	const SCRIPT = `
1942	var o = {baz: true, foo: true, bar: true};
1943	var res = "";
1944	for (var i in o) {
1945		delete o.baz;
1946		Object.defineProperty(o, "hidden", {value: true, configurable: true});
1947		for (var j in o) {
1948			Object.defineProperty(o, "0", {value: true, configurable: true});
1949			Object.defineProperty(o, "1", {value: true, configurable: true});
1950			for (var k in o) {}
1951			res += i + "-" + j + " ";
1952		}
1953	}
1954	assert(compareArray(Reflect.ownKeys(o), ["0","1","foo","bar","hidden"]), "keys");
1955	res;
1956	`
1957	testScript1(TESTLIB+SCRIPT, asciiString("baz-foo baz-bar foo-foo foo-bar bar-foo bar-bar "), t)
1958}
1959
1960func TestAbandonedEnumerate(t *testing.T) {
1961	const SCRIPT = `
1962	var o = {baz: true, foo: true, bar: true};
1963	var res = "";
1964	for (var i in o) {
1965		delete o.baz;
1966		for (var j in o) {
1967			res += i + "-" + j + " ";
1968			break;
1969		}
1970	}
1971	res;
1972	`
1973	testScript1(SCRIPT, asciiString("baz-foo foo-foo bar-foo "), t)
1974}
1975
1976func TestIterCloseThrows(t *testing.T) {
1977	const SCRIPT = `
1978	var returnCount = 0;
1979	var iterable = {};
1980	var iterator = {
1981	  next: function() {
1982		return { value: true };
1983	  },
1984	  return: function() {
1985		returnCount += 1;
1986		throw new Error();
1987	  }
1988	};
1989	iterable[Symbol.iterator] = function() {
1990	  return iterator;
1991	};
1992
1993	try {
1994		for (var i of iterable) {
1995				break;
1996		}
1997	} catch (e) {};
1998	returnCount;
1999	`
2000	testScript1(SCRIPT, valueInt(1), t)
2001}
2002
2003func TestDeclareGlobalFunc(t *testing.T) {
2004	const SCRIPT = `
2005	var initial;
2006
2007	Object.defineProperty(this, 'f', {
2008	  enumerable: true,
2009	  writable: true,
2010	  configurable: false
2011	});
2012
2013	(0,eval)('initial = f; function f() { return 2222; }');
2014	var desc = Object.getOwnPropertyDescriptor(this, "f");
2015	assert(desc.enumerable, "enumerable");
2016	assert(desc.writable, "writable");
2017	assert(!desc.configurable, "configurable");
2018	assert.sameValue(initial(), 2222);
2019	`
2020	testScript1(TESTLIB+SCRIPT, _undefined, t)
2021}
2022
2023func TestStackOverflowError(t *testing.T) {
2024	vm := New()
2025	vm.SetMaxCallStackSize(3)
2026	_, err := vm.RunString(`
2027	function f() {
2028		f();
2029	}
2030	f();
2031	`)
2032	if _, ok := err.(*StackOverflowError); !ok {
2033		t.Fatal(err)
2034	}
2035}
2036
2037func TestStacktraceLocationThrowFromCatch(t *testing.T) {
2038	vm := New()
2039	_, err := vm.RunString(`
2040	function main(arg) {
2041		try {
2042			if (arg === 1) {
2043				return f1();
2044			}
2045			if (arg === 2) {
2046				return f2();
2047			}
2048			if (arg === 3) {
2049				return f3();
2050			}
2051		} catch (e) {
2052			throw e;
2053		}
2054	}
2055	function f1() {}
2056	function f2() {
2057		throw new Error();
2058	}
2059	function f3() {}
2060	main(2);
2061	`)
2062	if err == nil {
2063		t.Fatal("Expected error")
2064	}
2065	stack := err.(*Exception).stack
2066	if len(stack) != 2 {
2067		t.Fatalf("Unexpected stack len: %v", stack)
2068	}
2069	if frame := stack[0]; frame.funcName != "main" || frame.pc != 30 {
2070		t.Fatalf("Unexpected stack frame 0: %#v", frame)
2071	}
2072	if frame := stack[1]; frame.funcName != "" || frame.pc != 7 {
2073		t.Fatalf("Unexpected stack frame 1: %#v", frame)
2074	}
2075}
2076
2077func TestStacktraceLocationThrowFromGo(t *testing.T) {
2078	vm := New()
2079	f := func() {
2080		panic(vm.ToValue("Test"))
2081	}
2082	vm.Set("f", f)
2083	_, err := vm.RunString(`
2084	function main() {
2085		return f();
2086	}
2087	main();
2088	`)
2089	if err == nil {
2090		t.Fatal("Expected error")
2091	}
2092	stack := err.(*Exception).stack
2093	if len(stack) != 3 {
2094		t.Fatalf("Unexpected stack len: %v", stack)
2095	}
2096	if frame := stack[0]; !strings.HasSuffix(frame.funcName.String(), "TestStacktraceLocationThrowFromGo.func1") {
2097		t.Fatalf("Unexpected stack frame 0: %#v", frame)
2098	}
2099	if frame := stack[1]; frame.funcName != "main" || frame.pc != 1 {
2100		t.Fatalf("Unexpected stack frame 1: %#v", frame)
2101	}
2102	if frame := stack[2]; frame.funcName != "" || frame.pc != 3 {
2103		t.Fatalf("Unexpected stack frame 2: %#v", frame)
2104	}
2105}
2106
2107func TestStrToInt64(t *testing.T) {
2108	if _, ok := strToInt64(""); ok {
2109		t.Fatal("<empty>")
2110	}
2111	if n, ok := strToInt64("0"); !ok || n != 0 {
2112		t.Fatal("0", n, ok)
2113	}
2114	if n, ok := strToInt64("-0"); ok {
2115		t.Fatal("-0", n, ok)
2116	}
2117	if n, ok := strToInt64("-1"); !ok || n != -1 {
2118		t.Fatal("-1", n, ok)
2119	}
2120	if n, ok := strToInt64("9223372036854775808"); ok {
2121		t.Fatal("max+1", n, ok)
2122	}
2123	if n, ok := strToInt64("9223372036854775817"); ok {
2124		t.Fatal("9223372036854775817", n, ok)
2125	}
2126	if n, ok := strToInt64("-9223372036854775818"); ok {
2127		t.Fatal("-9223372036854775818", n, ok)
2128	}
2129	if n, ok := strToInt64("9223372036854775807"); !ok || n != 9223372036854775807 {
2130		t.Fatal("max", n, ok)
2131	}
2132	if n, ok := strToInt64("-9223372036854775809"); ok {
2133		t.Fatal("min-1", n, ok)
2134	}
2135	if n, ok := strToInt64("-9223372036854775808"); !ok || n != -9223372036854775808 {
2136		t.Fatal("min", n, ok)
2137	}
2138	if n, ok := strToInt64("-00"); ok {
2139		t.Fatal("-00", n, ok)
2140	}
2141	if n, ok := strToInt64("-01"); ok {
2142		t.Fatal("-01", n, ok)
2143	}
2144}
2145
2146func TestStrToInt32(t *testing.T) {
2147	if _, ok := strToInt32(""); ok {
2148		t.Fatal("<empty>")
2149	}
2150	if n, ok := strToInt32("0"); !ok || n != 0 {
2151		t.Fatal("0", n, ok)
2152	}
2153	if n, ok := strToInt32("-0"); ok {
2154		t.Fatal("-0", n, ok)
2155	}
2156	if n, ok := strToInt32("-1"); !ok || n != -1 {
2157		t.Fatal("-1", n, ok)
2158	}
2159	if n, ok := strToInt32("2147483648"); ok {
2160		t.Fatal("max+1", n, ok)
2161	}
2162	if n, ok := strToInt32("2147483657"); ok {
2163		t.Fatal("2147483657", n, ok)
2164	}
2165	if n, ok := strToInt32("-2147483658"); ok {
2166		t.Fatal("-2147483658", n, ok)
2167	}
2168	if n, ok := strToInt32("2147483647"); !ok || n != 2147483647 {
2169		t.Fatal("max", n, ok)
2170	}
2171	if n, ok := strToInt32("-2147483649"); ok {
2172		t.Fatal("min-1", n, ok)
2173	}
2174	if n, ok := strToInt32("-2147483648"); !ok || n != -2147483648 {
2175		t.Fatal("min", n, ok)
2176	}
2177	if n, ok := strToInt32("-00"); ok {
2178		t.Fatal("-00", n, ok)
2179	}
2180	if n, ok := strToInt32("-01"); ok {
2181		t.Fatal("-01", n, ok)
2182	}
2183}
2184
2185func TestDestructSymbol(t *testing.T) {
2186	const SCRIPT = `
2187	var S = Symbol("S");
2188	var s, rest;
2189
2190	({[S]: s, ...rest} = {[S]: true, test: 1});
2191	assert.sameValue(s, true, "S");
2192	assert(deepEqual(rest, {test: 1}), "rest");
2193	`
2194	testScript1(TESTLIBX+SCRIPT, _undefined, t)
2195}
2196
2197func TestAccessorFuncName(t *testing.T) {
2198	const SCRIPT = `
2199	const namedSym = Symbol('test262');
2200	const emptyStrSym = Symbol("");
2201	const anonSym = Symbol();
2202
2203	const o = {
2204	  get id() {},
2205	  get [anonSym]() {},
2206	  get [namedSym]() {},
2207      get [emptyStrSym]() {},
2208	  set id(v) {},
2209	  set [anonSym](v) {},
2210	  set [namedSym](v) {},
2211      set [emptyStrSym](v) {}
2212	};
2213
2214	let prop;
2215	prop = Object.getOwnPropertyDescriptor(o, 'id');
2216	assert.sameValue(prop.get.name, 'get id');
2217	assert.sameValue(prop.set.name, 'set id');
2218
2219	prop = Object.getOwnPropertyDescriptor(o, anonSym);
2220	assert.sameValue(prop.get.name, 'get ');
2221	assert.sameValue(prop.set.name, 'set ');
2222
2223	prop = Object.getOwnPropertyDescriptor(o, emptyStrSym);
2224	assert.sameValue(prop.get.name, 'get []');
2225	assert.sameValue(prop.set.name, 'set []');
2226
2227	prop = Object.getOwnPropertyDescriptor(o, namedSym);
2228	assert.sameValue(prop.get.name, 'get [test262]');
2229	assert.sameValue(prop.set.name, 'set [test262]');
2230	`
2231	testScript1(TESTLIB+SCRIPT, _undefined, t)
2232}
2233
2234func TestCoverFuncName(t *testing.T) {
2235	const SCRIPT = `
2236	var namedSym = Symbol('');
2237	var anonSym = Symbol();
2238	var o;
2239
2240	o = {
2241	  xId: (0, function() {}),
2242	  id: (function() {}),
2243      id1: function x() {},
2244	  [anonSym]: (function() {}),
2245	  [namedSym]: (function() {})
2246	};
2247
2248	assert(o.xId.name !== 'xId');
2249	assert.sameValue(o.id1.name, 'x');
2250	assert.sameValue(o.id.name, 'id', 'via IdentifierName');
2251	assert.sameValue(o[anonSym].name, '', 'via anonymous Symbol');
2252	assert.sameValue(o[namedSym].name, '[]', 'via Symbol');
2253	`
2254	testScript1(TESTLIB+SCRIPT, _undefined, t)
2255}
2256
2257func TestAnonFuncName(t *testing.T) {
2258	const SCRIPT = `
2259	const d = Object.getOwnPropertyDescriptor((function() {}), 'name');
2260	d !== undefined && d.value === '';
2261	`
2262	testScript1(SCRIPT, valueTrue, t)
2263}
2264
2265func TestStringToBytesConversion(t *testing.T) {
2266	vm := New()
2267	v := vm.ToValue("Test")
2268	var b []byte
2269	err := vm.ExportTo(v, &b)
2270	if err != nil {
2271		t.Fatal(err)
2272	}
2273	if string(b) != "Test" {
2274		t.Fatal(b)
2275	}
2276}
2277
2278/*
2279func TestArrayConcatSparse(t *testing.T) {
2280function foo(a,b,c)
2281  {
2282    arguments[0] = 1; arguments[1] = 'str'; arguments[2] = 2.1;
2283    if(1 === a && 'str' === b && 2.1 === c)
2284      return true;
2285  }
2286
2287
2288	const SCRIPT = `
2289	var a1 = [];
2290	var a2 = [];
2291	a1[500000] = 1;
2292	a2[1000000] = 2;
2293	var a3 = a1.concat(a2);
2294	a3.length === 1500002 && a3[500000] === 1 && a3[1500001] == 2;
2295	`
2296
2297	testScript1(SCRIPT, valueTrue, t)
2298}
2299*/
2300
2301func BenchmarkCallReflect(b *testing.B) {
2302	vm := New()
2303	vm.Set("f", func(v Value) {
2304
2305	})
2306
2307	prg := MustCompile("test.js", "f(null)", true)
2308
2309	b.ResetTimer()
2310	for i := 0; i < b.N; i++ {
2311		vm.RunProgram(prg)
2312	}
2313}
2314
2315func BenchmarkCallNative(b *testing.B) {
2316	vm := New()
2317	vm.Set("f", func(call FunctionCall) (ret Value) {
2318		return
2319	})
2320
2321	prg := MustCompile("test.js", "f(null)", true)
2322
2323	b.ResetTimer()
2324	for i := 0; i < b.N; i++ {
2325		vm.RunProgram(prg)
2326	}
2327}
2328
2329func BenchmarkMainLoop(b *testing.B) {
2330	vm := New()
2331
2332	const SCRIPT = `
2333		for (var i=0; i<100000; i++) {
2334		}
2335	`
2336
2337	prg := MustCompile("test.js", SCRIPT, true)
2338
2339	b.ResetTimer()
2340	for i := 0; i < b.N; i++ {
2341		vm.RunProgram(prg)
2342	}
2343}
2344
2345func BenchmarkStringMapGet(b *testing.B) {
2346	m := make(map[string]Value)
2347	for i := 0; i < 100; i++ {
2348		m[strconv.Itoa(i)] = intToValue(int64(i))
2349	}
2350	b.ResetTimer()
2351	for i := 0; i < b.N; i++ {
2352		if m["50"] == nil {
2353			b.Fatal()
2354		}
2355	}
2356}
2357
2358func BenchmarkValueStringMapGet(b *testing.B) {
2359	m := make(map[valueString]Value)
2360	for i := 0; i < 100; i++ {
2361		m[asciiString(strconv.Itoa(i))] = intToValue(int64(i))
2362	}
2363	b.ResetTimer()
2364	var key valueString = asciiString("50")
2365	for i := 0; i < b.N; i++ {
2366		if m[key] == nil {
2367			b.Fatal()
2368		}
2369	}
2370}
2371
2372func BenchmarkAsciiStringMapGet(b *testing.B) {
2373	m := make(map[asciiString]Value)
2374	for i := 0; i < 100; i++ {
2375		m[asciiString(strconv.Itoa(i))] = intToValue(int64(i))
2376	}
2377	b.ResetTimer()
2378	var key = asciiString("50")
2379	for i := 0; i < b.N; i++ {
2380		if m[key] == nil {
2381			b.Fatal()
2382		}
2383	}
2384}
2385