github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/runtime_test.go (about)

     1  package goja
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"reflect"
     8  	"runtime"
     9  	"strconv"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/nuvolaris/goja/parser"
    15  )
    16  
    17  func TestGlobalObjectProto(t *testing.T) {
    18  	const SCRIPT = `
    19  	this instanceof Object
    20  	`
    21  
    22  	testScript(SCRIPT, valueTrue, t)
    23  }
    24  
    25  func TestUnicodeString(t *testing.T) {
    26  	const SCRIPT = `
    27  	var s = "Тест";
    28  	s.length === 4 && s[1] === "е";
    29  
    30  	`
    31  
    32  	testScript(SCRIPT, valueTrue, t)
    33  }
    34  
    35  func 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  	testScript(SCRIPT, valueTrue, t)
    52  }
    53  
    54  func 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  	testScript(SCRIPT, intToValue(28), t)
    69  }
    70  
    71  func 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  	testScript(SCRIPT, valueTrue, t)
    84  }
    85  
    86  func TestIndexOf(t *testing.T) {
    87  	const SCRIPT = `
    88  
    89  	"abc".indexOf("", 4)
    90  	`
    91  
    92  	testScript(SCRIPT, intToValue(3), t)
    93  }
    94  
    95  func TestUnicodeIndexOf(t *testing.T) {
    96  	const SCRIPT = `
    97  	"абвгд".indexOf("вг", 1) === 2 && '中国'.indexOf('国') === 1
    98  	`
    99  
   100  	testScript(SCRIPT, valueTrue, t)
   101  }
   102  
   103  func TestLastIndexOf(t *testing.T) {
   104  	const SCRIPT = `
   105  
   106  	"abcabab".lastIndexOf("ab", 3)
   107  	`
   108  
   109  	testScript(SCRIPT, intToValue(3), t)
   110  }
   111  
   112  func TestUnicodeLastIndexOf(t *testing.T) {
   113  	const SCRIPT = `
   114  	"абвабаб".lastIndexOf("аб", 3)
   115  	`
   116  
   117  	testScript(SCRIPT, intToValue(3), t)
   118  }
   119  
   120  func TestUnicodeLastIndexOf1(t *testing.T) {
   121  	const SCRIPT = `
   122  	"abꞐcde".lastIndexOf("cd");
   123  	`
   124  
   125  	testScript(SCRIPT, intToValue(3), t)
   126  }
   127  
   128  func TestNumber(t *testing.T) {
   129  	const SCRIPT = `
   130  	(new Number(100111122133144155)).toString()
   131  	`
   132  
   133  	testScript(SCRIPT, asciiString("100111122133144160"), t)
   134  }
   135  
   136  func TestFractionalNumberToStringRadix(t *testing.T) {
   137  	const SCRIPT = `
   138  	(new Number(123.456)).toString(36)
   139  	`
   140  
   141  	testScript(SCRIPT, asciiString("3f.gez4w97ry"), t)
   142  }
   143  
   144  func 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  	testScriptWithTestLib(SCRIPT, _undefined, t)
   165  }
   166  
   167  func TestBinOctalNumbers(t *testing.T) {
   168  	const SCRIPT = `
   169  	0b111;
   170  	`
   171  
   172  	testScript(SCRIPT, valueInt(7), t)
   173  }
   174  
   175  func TestSetFunc(t *testing.T) {
   176  	const SCRIPT = `
   177  	sum(40, 2);
   178  	`
   179  	r := New()
   180  	err := r.Set("sum", func(call FunctionCall) Value {
   181  		return r.ToValue(call.Argument(0).ToInteger() + call.Argument(1).ToInteger())
   182  	})
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  	v, err := r.RunString(SCRIPT)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	if i := v.ToInteger(); i != 42 {
   191  		t.Fatalf("Expected 42, got: %d", i)
   192  	}
   193  }
   194  
   195  func ExampleRuntime_Set_lexical() {
   196  	r := New()
   197  	_, err := r.RunString("let x")
   198  	if err != nil {
   199  		panic(err)
   200  	}
   201  	err = r.Set("x", 1)
   202  	if err != nil {
   203  		panic(err)
   204  	}
   205  	fmt.Print(r.Get("x"), r.GlobalObject().Get("x"))
   206  	// Output: 1 <nil>
   207  }
   208  
   209  func TestRecursiveRun(t *testing.T) {
   210  	// Make sure that a recursive call to Run*() correctly sets the environment and no stash or stack
   211  	// corruptions occur.
   212  	vm := New()
   213  	vm.Set("f", func() (Value, error) {
   214  		return vm.RunString("let x = 1; { let z = 100, z1 = 200, z2 = 300, z3 = 400; x = x + z3} x;")
   215  	})
   216  	res, err := vm.RunString(`
   217  	function f1() {
   218  		let x = 2;
   219  		eval('');
   220  		{
   221  			let y = 3;
   222  			let res = f();
   223  			if (x !== 2) { // check for stash corruption
   224  				throw new Error("x="+x);
   225  			}
   226  			if (y !== 3) { // check for stack corruption
   227  				throw new Error("y="+y);
   228  			}
   229  			return res;
   230  		}
   231  	};
   232  	f1();
   233  	`)
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  	if !res.SameAs(valueInt(401)) {
   238  		t.Fatal(res)
   239  	}
   240  }
   241  
   242  func TestRecursiveRunWithNArgs(t *testing.T) {
   243  	vm := New()
   244  	vm.Set("f", func() (Value, error) {
   245  		return vm.RunString(`
   246  		{
   247  			let a = 0;
   248  			let b = 1;
   249  			a = 2; // this used to to corrupt b, because its location on the stack was off by vm.args (1 in our case)
   250  			b;
   251  		}
   252  	`)
   253  	})
   254  	_, err := vm.RunString(`
   255  		(function(arg) { // need an ES function call with an argument to set vm.args
   256  			let res = f();
   257  			if (res !== 1) {
   258  				throw new Error(res);
   259  			}
   260  		})(123);
   261  	`)
   262  	if err != nil {
   263  		t.Fatal(err)
   264  	}
   265  }
   266  
   267  func TestRecursiveRunCallee(t *testing.T) {
   268  	// Make sure that a recursive call to Run*() correctly sets the callee (i.e. stack[sb-1])
   269  	vm := New()
   270  	vm.Set("f", func() (Value, error) {
   271  		return vm.RunString("this; (() => 1)()")
   272  	})
   273  	res, err := vm.RunString(`
   274  		f(123, 123);
   275  	`)
   276  	if err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	if !res.SameAs(valueInt(1)) {
   280  		t.Fatal(res)
   281  	}
   282  }
   283  
   284  func TestObjectGetSet(t *testing.T) {
   285  	const SCRIPT = `
   286  		input.test++;
   287  		input;
   288  	`
   289  	r := New()
   290  	o := r.NewObject()
   291  	o.Set("test", 42)
   292  	r.Set("input", o)
   293  
   294  	v, err := r.RunString(SCRIPT)
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  	if o1, ok := v.(*Object); ok {
   299  		if v1 := o1.Get("test"); v1.Export() != int64(43) {
   300  			t.Fatalf("Unexpected test value: %v (%T)", v1, v1.Export())
   301  		}
   302  	}
   303  }
   304  
   305  func TestThrowFromNativeFunc(t *testing.T) {
   306  	const SCRIPT = `
   307  	var thrown;
   308  	try {
   309  		f();
   310  	} catch (e) {
   311  		thrown = e;
   312  	}
   313  	thrown;
   314  	`
   315  	r := New()
   316  	r.Set("f", func(call FunctionCall) Value {
   317  		panic(r.ToValue("testError"))
   318  	})
   319  
   320  	v, err := r.RunString(SCRIPT)
   321  	if err != nil {
   322  		t.Fatal(err)
   323  	}
   324  
   325  	if !v.Equals(asciiString("testError")) {
   326  		t.Fatalf("Unexpected result: %v", v)
   327  	}
   328  }
   329  
   330  func TestSetGoFunc(t *testing.T) {
   331  	const SCRIPT = `
   332  	f(40, 2)
   333  	`
   334  	r := New()
   335  	r.Set("f", func(a, b int) int {
   336  		return a + b
   337  	})
   338  
   339  	v, err := r.RunString(SCRIPT)
   340  	if err != nil {
   341  		t.Fatal(err)
   342  	}
   343  
   344  	if v.ToInteger() != 42 {
   345  		t.Fatalf("Unexpected result: %v", v)
   346  	}
   347  }
   348  
   349  func TestSetFuncVariadic(t *testing.T) {
   350  	vm := New()
   351  	vm.Set("f", func(s string, g ...Value) {
   352  		something := g[0].ToObject(vm).Get(s).ToInteger()
   353  		if something != 5 {
   354  			t.Fatal()
   355  		}
   356  	})
   357  	_, err := vm.RunString(`
   358             f("something", {something: 5})
   359  	`)
   360  	if err != nil {
   361  		t.Fatal(err)
   362  	}
   363  }
   364  
   365  func TestSetFuncVariadicFuncArg(t *testing.T) {
   366  	vm := New()
   367  	vm.Set("f", func(s string, g ...Value) {
   368  		if f, ok := AssertFunction(g[0]); ok {
   369  			v, err := f(nil)
   370  			if err != nil {
   371  				t.Fatal(err)
   372  			}
   373  			if v != valueTrue {
   374  				t.Fatal(v)
   375  			}
   376  		}
   377  	})
   378  	_, err := vm.RunString(`
   379             f("something", () => true)
   380  	`)
   381  	if err != nil {
   382  		t.Fatal(err)
   383  	}
   384  }
   385  
   386  func TestArgsKeys(t *testing.T) {
   387  	const SCRIPT = `
   388  	function testArgs2(x, y, z) {
   389      		// Properties of the arguments object are enumerable.
   390      		return Object.keys(arguments);
   391  	}
   392  
   393  	testArgs2(1,2).length
   394  	`
   395  
   396  	testScript(SCRIPT, intToValue(2), t)
   397  }
   398  
   399  func TestIPowOverflow(t *testing.T) {
   400  	const SCRIPT = `
   401  	assert.sameValue(Math.pow(65536, 6), 7.922816251426434e+28);
   402  	assert.sameValue(Math.pow(10, 19), 1e19);
   403  	assert.sameValue(Math.pow(2097151, 3), 9223358842721534000);
   404  	assert.sameValue(Math.pow(2097152, 3), 9223372036854776000);
   405  	assert.sameValue(Math.pow(-2097151, 3), -9223358842721534000);
   406  	assert.sameValue(Math.pow(-2097152, 3), -9223372036854776000);
   407  	assert.sameValue(Math.pow(9007199254740992, 0), 1);
   408  	assert.sameValue(Math.pow(-9007199254740992, 0), 1);
   409  	assert.sameValue(Math.pow(0, 0), 1);
   410  	`
   411  
   412  	testScriptWithTestLib(SCRIPT, _undefined, t)
   413  }
   414  
   415  func TestIPow(t *testing.T) {
   416  	if res := ipow(-9223372036854775808, 1); res != -9223372036854775808 {
   417  		t.Fatal(res)
   418  	}
   419  
   420  	if res := ipow(9223372036854775807, 1); res != 9223372036854775807 {
   421  		t.Fatal(res)
   422  	}
   423  
   424  	if res := ipow(-9223372036854775807, 1); res != -9223372036854775807 {
   425  		t.Fatal(res)
   426  	}
   427  
   428  	if res := ipow(9223372036854775807, 0); res != 1 {
   429  		t.Fatal(res)
   430  	}
   431  
   432  	if res := ipow(-9223372036854775807, 0); res != 1 {
   433  		t.Fatal(res)
   434  	}
   435  
   436  	if res := ipow(-9223372036854775808, 0); res != 1 {
   437  		t.Fatal(res)
   438  	}
   439  }
   440  
   441  func TestInterrupt(t *testing.T) {
   442  	const SCRIPT = `
   443  	var i = 0;
   444  	for (;;) {
   445  		i++;
   446  	}
   447  	`
   448  
   449  	vm := New()
   450  	time.AfterFunc(200*time.Millisecond, func() {
   451  		vm.Interrupt("halt")
   452  	})
   453  
   454  	_, err := vm.RunString(SCRIPT)
   455  	if err == nil {
   456  		t.Fatal("Err is nil")
   457  	}
   458  }
   459  
   460  func TestRuntime_ExportToNumbers(t *testing.T) {
   461  	vm := New()
   462  	t.Run("int8/no overflow", func(t *testing.T) {
   463  		var i8 int8
   464  		err := vm.ExportTo(vm.ToValue(-123), &i8)
   465  		if err != nil {
   466  			t.Fatal(err)
   467  		}
   468  		if i8 != -123 {
   469  			t.Fatalf("i8: %d", i8)
   470  		}
   471  	})
   472  
   473  	t.Run("int8/overflow", func(t *testing.T) {
   474  		var i8 int8
   475  		err := vm.ExportTo(vm.ToValue(333), &i8)
   476  		if err != nil {
   477  			t.Fatal(err)
   478  		}
   479  		if i8 != 77 {
   480  			t.Fatalf("i8: %d", i8)
   481  		}
   482  	})
   483  
   484  	t.Run("int64/uint64", func(t *testing.T) {
   485  		var ui64 uint64
   486  		err := vm.ExportTo(vm.ToValue(-1), &ui64)
   487  		if err != nil {
   488  			t.Fatal(err)
   489  		}
   490  		if ui64 != math.MaxUint64 {
   491  			t.Fatalf("ui64: %d", ui64)
   492  		}
   493  	})
   494  
   495  	t.Run("int8/float", func(t *testing.T) {
   496  		var i8 int8
   497  		err := vm.ExportTo(vm.ToValue(333.9234), &i8)
   498  		if err != nil {
   499  			t.Fatal(err)
   500  		}
   501  		if i8 != 77 {
   502  			t.Fatalf("i8: %d", i8)
   503  		}
   504  	})
   505  
   506  	t.Run("int8/object", func(t *testing.T) {
   507  		var i8 int8
   508  		err := vm.ExportTo(vm.NewObject(), &i8)
   509  		if err != nil {
   510  			t.Fatal(err)
   511  		}
   512  		if i8 != 0 {
   513  			t.Fatalf("i8: %d", i8)
   514  		}
   515  	})
   516  
   517  	t.Run("int/object_cust_valueOf", func(t *testing.T) {
   518  		var i int
   519  		obj, err := vm.RunString(`
   520  		({
   521  			valueOf: function() { return 42; }
   522  		})
   523  		`)
   524  		if err != nil {
   525  			t.Fatal(err)
   526  		}
   527  		err = vm.ExportTo(obj, &i)
   528  		if err != nil {
   529  			t.Fatal(err)
   530  		}
   531  		if i != 42 {
   532  			t.Fatalf("i: %d", i)
   533  		}
   534  	})
   535  
   536  	t.Run("float32/no_trunc", func(t *testing.T) {
   537  		var f float32
   538  		err := vm.ExportTo(vm.ToValue(1.234567), &f)
   539  		if err != nil {
   540  			t.Fatal(err)
   541  		}
   542  		if f != 1.234567 {
   543  			t.Fatalf("f: %f", f)
   544  		}
   545  	})
   546  
   547  	t.Run("float32/trunc", func(t *testing.T) {
   548  		var f float32
   549  		err := vm.ExportTo(vm.ToValue(1.234567890), &f)
   550  		if err != nil {
   551  			t.Fatal(err)
   552  		}
   553  		if f != float32(1.234567890) {
   554  			t.Fatalf("f: %f", f)
   555  		}
   556  	})
   557  
   558  	t.Run("float64", func(t *testing.T) {
   559  		var f float64
   560  		err := vm.ExportTo(vm.ToValue(1.234567), &f)
   561  		if err != nil {
   562  			t.Fatal(err)
   563  		}
   564  		if f != 1.234567 {
   565  			t.Fatalf("f: %f", f)
   566  		}
   567  	})
   568  
   569  	t.Run("float32/object", func(t *testing.T) {
   570  		var f float32
   571  		err := vm.ExportTo(vm.NewObject(), &f)
   572  		if err != nil {
   573  			t.Fatal(err)
   574  		}
   575  		if f == f { // expecting NaN
   576  			t.Fatalf("f: %f", f)
   577  		}
   578  	})
   579  
   580  	t.Run("float64/object", func(t *testing.T) {
   581  		var f float64
   582  		err := vm.ExportTo(vm.NewObject(), &f)
   583  		if err != nil {
   584  			t.Fatal(err)
   585  		}
   586  		if f == f { // expecting NaN
   587  			t.Fatalf("f: %f", f)
   588  		}
   589  	})
   590  
   591  }
   592  
   593  func TestRuntime_ExportToSlice(t *testing.T) {
   594  	const SCRIPT = `
   595  	var a = [1, 2, 3];
   596  	a;
   597  	`
   598  
   599  	vm := New()
   600  	v, err := vm.RunString(SCRIPT)
   601  	if err != nil {
   602  		t.Fatal(err)
   603  	}
   604  	var a []string
   605  	err = vm.ExportTo(v, &a)
   606  	if err != nil {
   607  		t.Fatal(err)
   608  	}
   609  	if l := len(a); l != 3 {
   610  		t.Fatalf("Unexpected len: %d", l)
   611  	}
   612  	if a[0] != "1" || a[1] != "2" || a[2] != "3" {
   613  		t.Fatalf("Unexpected value: %+v", a)
   614  	}
   615  }
   616  
   617  func TestRuntime_ExportToMap(t *testing.T) {
   618  	const SCRIPT = `
   619  	var m = {
   620  		"0": 1,
   621  		"1": 2,
   622  		"2": 3,
   623  	}
   624  	m;
   625  	`
   626  
   627  	vm := New()
   628  	v, err := vm.RunString(SCRIPT)
   629  	if err != nil {
   630  		t.Fatal(err)
   631  	}
   632  	var m map[int]string
   633  	err = vm.ExportTo(v, &m)
   634  	if err != nil {
   635  		t.Fatal(err)
   636  	}
   637  	if l := len(m); l != 3 {
   638  		t.Fatalf("Unexpected len: %d", l)
   639  	}
   640  	if m[0] != "1" || m[1] != "2" || m[2] != "3" {
   641  		t.Fatalf("Unexpected value: %+v", m)
   642  	}
   643  }
   644  
   645  func TestRuntime_ExportToMap1(t *testing.T) {
   646  	const SCRIPT = `
   647  	var m = {
   648  		"0": 1,
   649  		"1": 2,
   650  		"2": 3,
   651  	}
   652  	m;
   653  	`
   654  
   655  	vm := New()
   656  	v, err := vm.RunString(SCRIPT)
   657  	if err != nil {
   658  		t.Fatal(err)
   659  	}
   660  	var m map[string]string
   661  	err = vm.ExportTo(v, &m)
   662  	if err != nil {
   663  		t.Fatal(err)
   664  	}
   665  	if l := len(m); l != 3 {
   666  		t.Fatalf("Unexpected len: %d", l)
   667  	}
   668  	if m["0"] != "1" || m["1"] != "2" || m["2"] != "3" {
   669  		t.Fatalf("Unexpected value: %+v", m)
   670  	}
   671  }
   672  
   673  func TestRuntime_ExportToStruct(t *testing.T) {
   674  	const SCRIPT = `
   675  	var m = {
   676  		Test: 1,
   677  	}
   678  	m;
   679  	`
   680  	vm := New()
   681  	v, err := vm.RunString(SCRIPT)
   682  	if err != nil {
   683  		t.Fatal(err)
   684  	}
   685  
   686  	var o testGoReflectMethod_O
   687  	err = vm.ExportTo(v, &o)
   688  	if err != nil {
   689  		t.Fatal(err)
   690  	}
   691  
   692  	if o.Test != "1" {
   693  		t.Fatalf("Unexpected value: '%s'", o.Test)
   694  	}
   695  
   696  }
   697  
   698  func TestRuntime_ExportToStructPtr(t *testing.T) {
   699  	const SCRIPT = `
   700  	var m = {
   701  		Test: 1,
   702  	}
   703  	m;
   704  	`
   705  	vm := New()
   706  	v, err := vm.RunString(SCRIPT)
   707  	if err != nil {
   708  		t.Fatal(err)
   709  	}
   710  
   711  	var o *testGoReflectMethod_O
   712  	err = vm.ExportTo(v, &o)
   713  	if err != nil {
   714  		t.Fatal(err)
   715  	}
   716  
   717  	if o.Test != "1" {
   718  		t.Fatalf("Unexpected value: '%s'", o.Test)
   719  	}
   720  
   721  }
   722  
   723  func TestRuntime_ExportToStructAnonymous(t *testing.T) {
   724  	type BaseTestStruct struct {
   725  		A int64
   726  		B int64
   727  	}
   728  
   729  	type TestStruct struct {
   730  		BaseTestStruct
   731  		C string
   732  	}
   733  
   734  	const SCRIPT = `
   735  	var m = {
   736  		A: 1,
   737  		B: 2,
   738  		C: "testC"
   739  	}
   740  	m;
   741  	`
   742  	vm := New()
   743  	v, err := vm.RunString(SCRIPT)
   744  	if err != nil {
   745  		t.Fatal(err)
   746  	}
   747  
   748  	test := &TestStruct{}
   749  	err = vm.ExportTo(v, test)
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  
   754  	if test.A != 1 {
   755  		t.Fatalf("Unexpected value: '%d'", test.A)
   756  	}
   757  	if test.B != 2 {
   758  		t.Fatalf("Unexpected value: '%d'", test.B)
   759  	}
   760  	if test.C != "testC" {
   761  		t.Fatalf("Unexpected value: '%s'", test.C)
   762  	}
   763  
   764  }
   765  
   766  func TestRuntime_ExportToStructFromPtr(t *testing.T) {
   767  	vm := New()
   768  	v := vm.ToValue(&testGoReflectMethod_O{
   769  		field: "5",
   770  		Test:  "12",
   771  	})
   772  
   773  	var o testGoReflectMethod_O
   774  	err := vm.ExportTo(v, &o)
   775  	if err != nil {
   776  		t.Fatal(err)
   777  	}
   778  
   779  	if o.Test != "12" {
   780  		t.Fatalf("Unexpected value: '%s'", o.Test)
   781  	}
   782  	if o.field != "5" {
   783  		t.Fatalf("Unexpected value for field: '%s'", o.field)
   784  	}
   785  }
   786  
   787  func TestRuntime_ExportToStructWithPtrValues(t *testing.T) {
   788  	type BaseTestStruct struct {
   789  		A int64
   790  		B *int64
   791  	}
   792  
   793  	type TestStruct2 struct {
   794  		E string
   795  	}
   796  
   797  	type TestStruct struct {
   798  		BaseTestStruct
   799  		C *string
   800  		D *TestStruct2
   801  	}
   802  
   803  	const SCRIPT = `
   804  	var m = {
   805  		A: 1,
   806  		B: 2,
   807  		C: "testC",
   808  		D: {
   809  			E: "testE",
   810  		}
   811  	}
   812  	m;
   813  	`
   814  	vm := New()
   815  	v, err := vm.RunString(SCRIPT)
   816  	if err != nil {
   817  		t.Fatal(err)
   818  	}
   819  
   820  	test := &TestStruct{}
   821  	err = vm.ExportTo(v, test)
   822  	if err != nil {
   823  		t.Fatal(err)
   824  	}
   825  
   826  	if test.A != 1 {
   827  		t.Fatalf("Unexpected value: '%d'", test.A)
   828  	}
   829  	if test.B == nil || *test.B != 2 {
   830  		t.Fatalf("Unexpected value: '%v'", test.B)
   831  	}
   832  	if test.C == nil || *test.C != "testC" {
   833  		t.Fatalf("Unexpected value: '%v'", test.C)
   834  	}
   835  	if test.D == nil || test.D.E != "testE" {
   836  		t.Fatalf("Unexpected value: '%s'", test.D.E)
   837  	}
   838  
   839  }
   840  
   841  func TestRuntime_ExportToTime(t *testing.T) {
   842  	const SCRIPT = `
   843  	var dateStr = "2018-08-13T15:02:13+02:00";
   844  	var str = "test123";
   845  	`
   846  
   847  	vm := New()
   848  	_, err := vm.RunString(SCRIPT)
   849  	if err != nil {
   850  		t.Fatal(err)
   851  	}
   852  
   853  	var ti time.Time
   854  	err = vm.ExportTo(vm.Get("dateStr"), &ti)
   855  	if err != nil {
   856  		t.Fatal(err)
   857  	}
   858  	if ti.Format(time.RFC3339) != "2018-08-13T15:02:13+02:00" {
   859  		t.Fatalf("Unexpected value: '%s'", ti.Format(time.RFC3339))
   860  	}
   861  
   862  	err = vm.ExportTo(vm.Get("str"), &ti)
   863  	if err == nil {
   864  		t.Fatal("Expected err to not be nil")
   865  	}
   866  
   867  	var str string
   868  	err = vm.ExportTo(vm.Get("dateStr"), &str)
   869  	if err != nil {
   870  		t.Fatal(err)
   871  	}
   872  	if str != "2018-08-13T15:02:13+02:00" {
   873  		t.Fatalf("Unexpected value: '%s'", str)
   874  	}
   875  
   876  	d, err := vm.RunString(`new Date(1000)`)
   877  	if err != nil {
   878  		t.Fatal(err)
   879  	}
   880  
   881  	ti = time.Time{}
   882  	err = vm.ExportTo(d, &ti)
   883  	if err != nil {
   884  		t.Fatal(err)
   885  	}
   886  
   887  	if ti.UnixNano() != 1000*1e6 {
   888  		t.Fatal(ti)
   889  	}
   890  	if ti.Location() != time.Local {
   891  		t.Fatalf("Wrong location: %v", ti)
   892  	}
   893  }
   894  
   895  func ExampleRuntime_ExportTo_func() {
   896  	const SCRIPT = `
   897  	function f(param) {
   898  		return +param + 2;
   899  	}
   900  	`
   901  
   902  	vm := New()
   903  	_, err := vm.RunString(SCRIPT)
   904  	if err != nil {
   905  		panic(err)
   906  	}
   907  
   908  	var fn func(string) string
   909  	err = vm.ExportTo(vm.Get("f"), &fn)
   910  	if err != nil {
   911  		panic(err)
   912  	}
   913  
   914  	fmt.Println(fn("40")) // note, _this_ value in the function will be undefined.
   915  	// Output: 42
   916  }
   917  
   918  func ExampleRuntime_ExportTo_funcThrow() {
   919  	const SCRIPT = `
   920  	function f(param) {
   921  		throw new Error("testing");
   922  	}
   923  	`
   924  
   925  	vm := New()
   926  	_, err := vm.RunString(SCRIPT)
   927  	if err != nil {
   928  		panic(err)
   929  	}
   930  
   931  	var fn func(string) (string, error)
   932  	err = vm.ExportTo(vm.Get("f"), &fn)
   933  	if err != nil {
   934  		panic(err)
   935  	}
   936  	_, err = fn("")
   937  
   938  	fmt.Println(err)
   939  	// Output: Error: testing at f (<eval>:3:9(3))
   940  }
   941  
   942  func ExampleRuntime_ExportTo_funcVariadic() {
   943  	const SCRIPT = `
   944  	function f() {
   945  		return Array.prototype.join.call(arguments, ",");
   946  	}
   947  	`
   948  	vm := New()
   949  	_, err := vm.RunString(SCRIPT)
   950  	if err != nil {
   951  		panic(err)
   952  	}
   953  
   954  	var fn func(args ...interface{}) string
   955  	err = vm.ExportTo(vm.Get("f"), &fn)
   956  	if err != nil {
   957  		panic(err)
   958  	}
   959  	fmt.Println(fn("a", "b", 42))
   960  	// Output: a,b,42
   961  }
   962  
   963  func TestRuntime_ExportToFuncFail(t *testing.T) {
   964  	const SCRIPT = `
   965  	function f(param) {
   966  		return +param + 2;
   967  	}
   968  	`
   969  
   970  	type T struct {
   971  		Field1 int
   972  	}
   973  
   974  	var fn func(string) (T, error)
   975  
   976  	vm := New()
   977  	_, err := vm.RunString(SCRIPT)
   978  	if err != nil {
   979  		t.Fatal(err)
   980  	}
   981  
   982  	err = vm.ExportTo(vm.Get("f"), &fn)
   983  	if err != nil {
   984  		t.Fatal(err)
   985  	}
   986  
   987  	if _, err := fn("40"); err == nil {
   988  		t.Fatal("Expected error")
   989  	}
   990  }
   991  
   992  func TestRuntime_ExportToCallable(t *testing.T) {
   993  	const SCRIPT = `
   994  	function f(param) {
   995  		return +param + 2;
   996  	}
   997  	`
   998  	vm := New()
   999  	_, err := vm.RunString(SCRIPT)
  1000  	if err != nil {
  1001  		t.Fatal(err)
  1002  	}
  1003  
  1004  	var c Callable
  1005  	err = vm.ExportTo(vm.Get("f"), &c)
  1006  	if err != nil {
  1007  		t.Fatal(err)
  1008  	}
  1009  
  1010  	res, err := c(Undefined(), vm.ToValue("40"))
  1011  	if err != nil {
  1012  		t.Fatal(err)
  1013  	} else if !res.StrictEquals(vm.ToValue(42)) {
  1014  		t.Fatalf("Unexpected value: %v", res)
  1015  	}
  1016  }
  1017  
  1018  func TestRuntime_ExportToObject(t *testing.T) {
  1019  	const SCRIPT = `
  1020  	var o = {"test": 42};
  1021  	o;
  1022  	`
  1023  	vm := New()
  1024  	_, err := vm.RunString(SCRIPT)
  1025  	if err != nil {
  1026  		t.Fatal(err)
  1027  	}
  1028  
  1029  	var o *Object
  1030  	err = vm.ExportTo(vm.Get("o"), &o)
  1031  	if err != nil {
  1032  		t.Fatal(err)
  1033  	}
  1034  
  1035  	if v := o.Get("test"); !v.StrictEquals(vm.ToValue(42)) {
  1036  		t.Fatalf("Unexpected value: %v", v)
  1037  	}
  1038  }
  1039  
  1040  func ExampleAssertFunction() {
  1041  	vm := New()
  1042  	_, err := vm.RunString(`
  1043  	function sum(a, b) {
  1044  		return a+b;
  1045  	}
  1046  	`)
  1047  	if err != nil {
  1048  		panic(err)
  1049  	}
  1050  	sum, ok := AssertFunction(vm.Get("sum"))
  1051  	if !ok {
  1052  		panic("Not a function")
  1053  	}
  1054  
  1055  	res, err := sum(Undefined(), vm.ToValue(40), vm.ToValue(2))
  1056  	if err != nil {
  1057  		panic(err)
  1058  	}
  1059  	fmt.Println(res)
  1060  	// Output: 42
  1061  }
  1062  
  1063  func TestGoFuncError(t *testing.T) {
  1064  	const SCRIPT = `
  1065  	try {
  1066  		f();
  1067  	} catch (e) {
  1068  		if (!(e instanceof GoError)) {
  1069  			throw(e);
  1070  		}
  1071  		if (e.value.Error() !== "Test") {
  1072  			throw("Unexpected value: " + e.value.Error());
  1073  		}
  1074  	}
  1075  	`
  1076  
  1077  	f := func() error {
  1078  		return errors.New("Test")
  1079  	}
  1080  
  1081  	vm := New()
  1082  	vm.Set("f", f)
  1083  	_, err := vm.RunString(SCRIPT)
  1084  	if err != nil {
  1085  		t.Fatal(err)
  1086  	}
  1087  }
  1088  
  1089  func TestToValueNil(t *testing.T) {
  1090  	type T struct{}
  1091  	var a *T
  1092  	vm := New()
  1093  
  1094  	if v := vm.ToValue(nil); !IsNull(v) {
  1095  		t.Fatalf("nil: %v", v)
  1096  	}
  1097  
  1098  	if v := vm.ToValue(a); !IsNull(v) {
  1099  		t.Fatalf("struct ptr: %v", v)
  1100  	}
  1101  
  1102  	var m map[string]interface{}
  1103  	if v := vm.ToValue(m); !IsNull(v) {
  1104  		t.Fatalf("map[string]interface{}: %v", v)
  1105  	}
  1106  
  1107  	var ar []interface{}
  1108  	if v := vm.ToValue(ar); IsNull(v) {
  1109  		t.Fatalf("[]interface{}: %v", v)
  1110  	}
  1111  
  1112  	var arptr *[]interface{}
  1113  	if v := vm.ToValue(arptr); !IsNull(v) {
  1114  		t.Fatalf("*[]interface{}: %v", v)
  1115  	}
  1116  }
  1117  
  1118  func TestToValueFloat(t *testing.T) {
  1119  	vm := New()
  1120  	vm.Set("f64", float64(123))
  1121  	vm.Set("f32", float32(321))
  1122  
  1123  	v, err := vm.RunString("f64 === 123 && f32 === 321")
  1124  	if err != nil {
  1125  		t.Fatal(err)
  1126  	}
  1127  	if v.Export().(bool) != true {
  1128  		t.Fatalf("StrictEquals for golang float failed")
  1129  	}
  1130  }
  1131  
  1132  func TestToValueInterface(t *testing.T) {
  1133  
  1134  	f := func(i interface{}) bool {
  1135  		return i == t
  1136  	}
  1137  	vm := New()
  1138  	vm.Set("f", f)
  1139  	vm.Set("t", t)
  1140  	v, err := vm.RunString(`f(t)`)
  1141  	if err != nil {
  1142  		t.Fatal(err)
  1143  	}
  1144  	if v != valueTrue {
  1145  		t.Fatalf("v: %v", v)
  1146  	}
  1147  }
  1148  
  1149  func TestJSONEscape(t *testing.T) {
  1150  	const SCRIPT = `
  1151  	var a = "\\+1";
  1152  	JSON.stringify(a);
  1153  	`
  1154  
  1155  	testScript(SCRIPT, asciiString(`"\\+1"`), t)
  1156  }
  1157  
  1158  func TestJSONObjectInArray(t *testing.T) {
  1159  	const SCRIPT = `
  1160  	var a = "[{\"a\":1},{\"a\":2}]";
  1161  	JSON.stringify(JSON.parse(a)) == a;
  1162  	`
  1163  
  1164  	testScript(SCRIPT, valueTrue, t)
  1165  }
  1166  
  1167  func TestJSONQuirkyNumbers(t *testing.T) {
  1168  	const SCRIPT = `
  1169  	var s;
  1170  	s = JSON.stringify(NaN);
  1171  	if (s != "null") {
  1172  		throw new Error("NaN: " + s);
  1173  	}
  1174  
  1175  	s = JSON.stringify(Infinity);
  1176  	if (s != "null") {
  1177  		throw new Error("Infinity: " + s);
  1178  	}
  1179  
  1180  	s = JSON.stringify(-Infinity);
  1181  	if (s != "null") {
  1182  		throw new Error("-Infinity: " + s);
  1183  	}
  1184  
  1185  	`
  1186  
  1187  	testScript(SCRIPT, _undefined, t)
  1188  }
  1189  
  1190  func TestJSONNil(t *testing.T) {
  1191  	const SCRIPT = `
  1192  	JSON.stringify(i);
  1193  	`
  1194  
  1195  	vm := New()
  1196  	var i interface{}
  1197  	vm.Set("i", i)
  1198  	ret, err := vm.RunString(SCRIPT)
  1199  	if err != nil {
  1200  		t.Fatal(err)
  1201  	}
  1202  
  1203  	if ret.String() != "null" {
  1204  		t.Fatalf("Expected 'null', got: %v", ret)
  1205  	}
  1206  }
  1207  
  1208  type customJsonEncodable struct{}
  1209  
  1210  func (*customJsonEncodable) JsonEncodable() interface{} {
  1211  	return "Test"
  1212  }
  1213  
  1214  func TestJsonEncodable(t *testing.T) {
  1215  	var s customJsonEncodable
  1216  
  1217  	vm := New()
  1218  	vm.Set("s", &s)
  1219  
  1220  	ret, err := vm.RunString("JSON.stringify(s)")
  1221  	if err != nil {
  1222  		t.Fatal(err)
  1223  	}
  1224  	if !ret.StrictEquals(vm.ToValue("\"Test\"")) {
  1225  		t.Fatalf("Expected \"Test\", got: %v", ret)
  1226  	}
  1227  }
  1228  
  1229  func TestSortComparatorReturnValues(t *testing.T) {
  1230  	const SCRIPT = `
  1231  	var a = [];
  1232  	for (var i = 0; i < 12; i++) {
  1233  	    a[i] = i;
  1234  	}
  1235  
  1236  	a.sort(function(x, y) { return y - x });
  1237  
  1238  	for (var i = 0; i < 12; i++) {
  1239  	    if (a[i] !== 11-i) {
  1240  		throw new Error("Value at index " + i + " is incorrect: " + a[i]);
  1241  	    }
  1242  	}
  1243  	`
  1244  
  1245  	testScript(SCRIPT, _undefined, t)
  1246  }
  1247  
  1248  func TestSortComparatorReturnValueFloats(t *testing.T) {
  1249  	const SCRIPT = `
  1250  	var a = [
  1251  		5.97,
  1252  		9.91,
  1253  		4.13,
  1254  		9.28,
  1255  		3.29,
  1256  	];
  1257  	a.sort( function(a, b) { return a - b; } );
  1258  	for (var i = 1; i < a.length; i++) {
  1259  		if (a[i] < a[i-1]) {
  1260  			throw new Error("Array is not sorted: " + a);
  1261  		}
  1262  	}
  1263  	`
  1264  	testScript(SCRIPT, _undefined, t)
  1265  }
  1266  
  1267  func TestSortComparatorReturnValueNegZero(t *testing.T) {
  1268  	const SCRIPT = `
  1269  	var a = [2, 1];
  1270  	a.sort( function(a, b) { return a > b ? 0 : -0; } );
  1271  	for (var i = 1; i < a.length; i++) {
  1272  		if (a[i] < a[i-1]) {
  1273  			throw new Error("Array is not sorted: " + a);
  1274  		}
  1275  	}
  1276  	`
  1277  	testScript(SCRIPT, _undefined, t)
  1278  }
  1279  
  1280  func TestNilApplyArg(t *testing.T) {
  1281  	const SCRIPT = `
  1282  	(function x(a, b) {
  1283  		return a === undefined && b === 1;
  1284          }).apply(this, [,1])
  1285  	`
  1286  
  1287  	testScript(SCRIPT, valueTrue, t)
  1288  }
  1289  
  1290  func TestNilCallArg(t *testing.T) {
  1291  	const SCRIPT = `
  1292  	"use strict";
  1293  	function f(a) {
  1294  		return this === undefined && a === undefined;
  1295  	}
  1296  	`
  1297  	vm := New()
  1298  	prg := MustCompile("test.js", SCRIPT, false)
  1299  	vm.RunProgram(prg)
  1300  	if f, ok := AssertFunction(vm.Get("f")); ok {
  1301  		v, err := f(nil, nil)
  1302  		if err != nil {
  1303  			t.Fatal(err)
  1304  		}
  1305  		if !v.StrictEquals(valueTrue) {
  1306  			t.Fatalf("Unexpected result: %v", v)
  1307  		}
  1308  	}
  1309  }
  1310  
  1311  func TestNullCallArg(t *testing.T) {
  1312  	const SCRIPT = `
  1313  	f(null);
  1314  	`
  1315  	vm := New()
  1316  	prg := MustCompile("test.js", SCRIPT, false)
  1317  	vm.Set("f", func(x *int) bool {
  1318  		return x == nil
  1319  	})
  1320  
  1321  	v, err := vm.RunProgram(prg)
  1322  	if err != nil {
  1323  		t.Fatal(err)
  1324  	}
  1325  
  1326  	if !v.StrictEquals(valueTrue) {
  1327  		t.Fatalf("Unexpected result: %v", v)
  1328  	}
  1329  }
  1330  
  1331  func TestObjectKeys(t *testing.T) {
  1332  	const SCRIPT = `
  1333  	var o = { a: 1, b: 2, c: 3, d: 4 };
  1334  	o;
  1335  	`
  1336  
  1337  	vm := New()
  1338  	prg := MustCompile("test.js", SCRIPT, false)
  1339  
  1340  	res, err := vm.RunProgram(prg)
  1341  	if err != nil {
  1342  		t.Fatal(err)
  1343  	}
  1344  
  1345  	if o, ok := res.(*Object); ok {
  1346  		keys := o.Keys()
  1347  		if !reflect.DeepEqual(keys, []string{"a", "b", "c", "d"}) {
  1348  			t.Fatalf("Unexpected keys: %v", keys)
  1349  		}
  1350  	}
  1351  }
  1352  
  1353  func TestReflectCallExtraArgs(t *testing.T) {
  1354  	const SCRIPT = `
  1355  	f(41, "extra")
  1356  	`
  1357  	f := func(x int) int {
  1358  		return x + 1
  1359  	}
  1360  
  1361  	vm := New()
  1362  	vm.Set("f", f)
  1363  
  1364  	prg := MustCompile("test.js", SCRIPT, false)
  1365  
  1366  	res, err := vm.RunProgram(prg)
  1367  	if err != nil {
  1368  		t.Fatal(err)
  1369  	}
  1370  	if !res.StrictEquals(intToValue(42)) {
  1371  		t.Fatalf("Unexpected result: %v", res)
  1372  	}
  1373  }
  1374  
  1375  func TestReflectCallNotEnoughArgs(t *testing.T) {
  1376  	const SCRIPT = `
  1377  	f(42)
  1378  	`
  1379  	vm := New()
  1380  
  1381  	f := func(x, y int, z *int, s string) (int, error) {
  1382  		if z != nil {
  1383  			return 0, fmt.Errorf("z is not nil")
  1384  		}
  1385  		if s != "" {
  1386  			return 0, fmt.Errorf("s is not \"\"")
  1387  		}
  1388  		return x + y, nil
  1389  	}
  1390  
  1391  	vm.Set("f", f)
  1392  
  1393  	prg := MustCompile("test.js", SCRIPT, false)
  1394  
  1395  	res, err := vm.RunProgram(prg)
  1396  	if err != nil {
  1397  		t.Fatal(err)
  1398  	}
  1399  	if !res.StrictEquals(intToValue(42)) {
  1400  		t.Fatalf("Unexpected result: %v", res)
  1401  	}
  1402  }
  1403  
  1404  func TestReflectCallVariadic(t *testing.T) {
  1405  	const SCRIPT = `
  1406  	var r = f("Hello %s, %d", "test", 42);
  1407  	if (r !== "Hello test, 42") {
  1408  		throw new Error("test 1 has failed: " + r);
  1409  	}
  1410  
  1411  	r = f("Hello %s, %s", "test");
  1412  	if (r !== "Hello test, %!s(MISSING)") {
  1413  		throw new Error("test 2 has failed: " + r);
  1414  	}
  1415  
  1416  	r = f();
  1417  	if (r !== "") {
  1418  		throw new Error("test 3 has failed: " + r);
  1419  	}
  1420  
  1421  	`
  1422  
  1423  	vm := New()
  1424  	vm.Set("f", fmt.Sprintf)
  1425  
  1426  	prg := MustCompile("test.js", SCRIPT, false)
  1427  
  1428  	_, err := vm.RunProgram(prg)
  1429  	if err != nil {
  1430  		t.Fatal(err)
  1431  	}
  1432  }
  1433  
  1434  func TestReflectNullValueArgument(t *testing.T) {
  1435  	rt := New()
  1436  	rt.Set("fn", func(v Value) {
  1437  		if v == nil {
  1438  			t.Error("null becomes nil")
  1439  		}
  1440  		if !IsNull(v) {
  1441  			t.Error("null is not null")
  1442  		}
  1443  	})
  1444  	rt.RunString(`fn(null);`)
  1445  }
  1446  
  1447  type testNativeConstructHelper struct {
  1448  	rt   *Runtime
  1449  	base int64
  1450  	// any other state
  1451  }
  1452  
  1453  func (t *testNativeConstructHelper) calc(call FunctionCall) Value {
  1454  	return t.rt.ToValue(t.base + call.Argument(0).ToInteger())
  1455  }
  1456  
  1457  func TestNativeConstruct(t *testing.T) {
  1458  	const SCRIPT = `
  1459  	var f = new F(40);
  1460  	f instanceof F && f.method() === 42 && f.calc(2) === 42;
  1461  	`
  1462  
  1463  	rt := New()
  1464  
  1465  	method := func(call FunctionCall) Value {
  1466  		return rt.ToValue(42)
  1467  	}
  1468  
  1469  	rt.Set("F", func(call ConstructorCall) *Object { // constructor signature (as opposed to 'func(FunctionCall) Value')
  1470  		h := &testNativeConstructHelper{
  1471  			rt:   rt,
  1472  			base: call.Argument(0).ToInteger(),
  1473  		}
  1474  		call.This.Set("method", method)
  1475  		call.This.Set("calc", h.calc)
  1476  		return nil // or any other *Object which will be used instead of call.This
  1477  	})
  1478  
  1479  	prg := MustCompile("test.js", SCRIPT, false)
  1480  
  1481  	res, err := rt.RunProgram(prg)
  1482  	if err != nil {
  1483  		t.Fatal(err)
  1484  	}
  1485  
  1486  	if !res.StrictEquals(valueTrue) {
  1487  		t.Fatalf("Unexpected result: %v", res)
  1488  	}
  1489  
  1490  	if fn, ok := AssertFunction(rt.Get("F")); ok {
  1491  		v, err := fn(nil, rt.ToValue(42))
  1492  		if err != nil {
  1493  			t.Fatal(err)
  1494  		}
  1495  		if o, ok := v.(*Object); ok {
  1496  			if o.Get("method") == nil {
  1497  				t.Fatal("No method")
  1498  			}
  1499  		} else {
  1500  			t.Fatal("Not an object")
  1501  		}
  1502  	} else {
  1503  		t.Fatal("Not a function")
  1504  	}
  1505  
  1506  	resp := &testNativeConstructHelper{}
  1507  	value := rt.ToValue(resp)
  1508  	if value.Export() != resp {
  1509  		t.Fatal("no")
  1510  	}
  1511  }
  1512  
  1513  func TestCreateObject(t *testing.T) {
  1514  	const SCRIPT = `
  1515  	inst instanceof C;
  1516  	`
  1517  
  1518  	r := New()
  1519  	c := r.ToValue(func(call ConstructorCall) *Object {
  1520  		return nil
  1521  	})
  1522  
  1523  	proto := c.(*Object).Get("prototype").(*Object)
  1524  
  1525  	inst := r.CreateObject(proto)
  1526  
  1527  	r.Set("C", c)
  1528  	r.Set("inst", inst)
  1529  
  1530  	prg := MustCompile("test.js", SCRIPT, false)
  1531  
  1532  	res, err := r.RunProgram(prg)
  1533  	if err != nil {
  1534  		t.Fatal(err)
  1535  	}
  1536  
  1537  	if !res.StrictEquals(valueTrue) {
  1538  		t.Fatalf("Unexpected result: %v", res)
  1539  	}
  1540  }
  1541  
  1542  func TestInterruptInWrappedFunction(t *testing.T) {
  1543  	rt := New()
  1544  	v, err := rt.RunString(`
  1545  		var fn = function() {
  1546  			while (true) {}
  1547  		};
  1548  		fn;
  1549  	`)
  1550  	if err != nil {
  1551  		t.Fatal(err)
  1552  	}
  1553  	fn, ok := AssertFunction(v)
  1554  	if !ok {
  1555  		t.Fatal("Not a function")
  1556  	}
  1557  	go func() {
  1558  		<-time.After(10 * time.Millisecond)
  1559  		rt.Interrupt(errors.New("hi"))
  1560  	}()
  1561  
  1562  	_, err = fn(nil)
  1563  	if err == nil {
  1564  		t.Fatal("expected error")
  1565  	}
  1566  	if _, ok := err.(*InterruptedError); !ok {
  1567  		t.Fatalf("Wrong error type: %T", err)
  1568  	}
  1569  }
  1570  
  1571  func TestInterruptInWrappedFunction2(t *testing.T) {
  1572  	rt := New()
  1573  	// this test panics as otherwise goja will recover and possibly loop
  1574  	var called bool
  1575  	rt.Set("v", rt.ToValue(func() {
  1576  		if called {
  1577  			go func() {
  1578  				panic("this should never get called twice")
  1579  			}()
  1580  		}
  1581  		called = true
  1582  		rt.Interrupt("here is the error")
  1583  	}))
  1584  
  1585  	rt.Set("s", rt.ToValue(func(a Callable) (Value, error) {
  1586  		return a(nil)
  1587  	}))
  1588  
  1589  	rt.Set("k", rt.ToValue(func(e Value) {
  1590  		go func() {
  1591  			panic("this should never get called actually")
  1592  		}()
  1593  	}))
  1594  	_, err := rt.RunString(`
  1595          Promise.resolve().then(()=>k()); // this should never resolve
  1596          while(true) {
  1597              try{
  1598                  s(() =>{
  1599                      v();
  1600                  })
  1601                  break;
  1602              } catch (e) {
  1603                  k(e);
  1604              }
  1605          }
  1606  	`)
  1607  	if err == nil {
  1608  		t.Fatal("expected error but got no error")
  1609  	}
  1610  	intErr := new(InterruptedError)
  1611  	if !errors.As(err, &intErr) {
  1612  		t.Fatalf("Wrong error type: %T", err)
  1613  	}
  1614  	if !strings.Contains(intErr.Error(), "here is the error") {
  1615  		t.Fatalf("Wrong error message: %q", intErr.Error())
  1616  	}
  1617  	_, err = rt.RunString(`Promise.resolve().then(()=>globalThis.S=5)`)
  1618  	if err != nil {
  1619  		t.Fatal(err)
  1620  	}
  1621  	s := rt.Get("S")
  1622  	if s == nil || s.ToInteger() != 5 {
  1623  		t.Fatalf("Wrong value for S %v", s)
  1624  	}
  1625  }
  1626  
  1627  func TestInterruptInWrappedFunction2Recover(t *testing.T) {
  1628  	rt := New()
  1629  	// this test panics as otherwise goja will recover and possibly loop
  1630  	var vCalled int
  1631  	rt.Set("v", rt.ToValue(func() {
  1632  		if vCalled == 0 {
  1633  			rt.Interrupt("here is the error")
  1634  		}
  1635  		vCalled++
  1636  	}))
  1637  
  1638  	rt.Set("s", rt.ToValue(func(a Callable) (Value, error) {
  1639  		v, err := a(nil)
  1640  		if err != nil {
  1641  			intErr := new(InterruptedError)
  1642  			if errors.As(err, &intErr) {
  1643  				rt.ClearInterrupt()
  1644  				return nil, errors.New("oops we got interrupted let's not that")
  1645  			}
  1646  		}
  1647  		return v, err
  1648  	}))
  1649  	var kCalled int
  1650  
  1651  	rt.Set("k", rt.ToValue(func(e Value) {
  1652  		kCalled++
  1653  	}))
  1654  	_, err := rt.RunString(`
  1655          Promise.resolve().then(()=>k());
  1656          while(true) {
  1657              try{
  1658                  s(() => {
  1659                      v();
  1660                  })
  1661                  break;
  1662              } catch (e) {
  1663                  k(e);
  1664              }
  1665          }
  1666  	`)
  1667  	if err != nil {
  1668  		t.Fatal(err)
  1669  	}
  1670  	if vCalled != 2 {
  1671  		t.Fatalf("v was not called exactly twice but %d times", vCalled)
  1672  	}
  1673  	if kCalled != 2 {
  1674  		t.Fatalf("k was not called exactly twice but %d times", kCalled)
  1675  	}
  1676  	_, err = rt.RunString(`Promise.resolve().then(()=>globalThis.S=5)`)
  1677  	if err != nil {
  1678  		t.Fatal(err)
  1679  	}
  1680  	s := rt.Get("S")
  1681  	if s == nil || s.ToInteger() != 5 {
  1682  		t.Fatalf("Wrong value for S %v", s)
  1683  	}
  1684  }
  1685  
  1686  func TestInterruptInWrappedFunctionExpectInteruptError(t *testing.T) {
  1687  	rt := New()
  1688  	// this test panics as otherwise goja will recover and possibly loop
  1689  	rt.Set("v", rt.ToValue(func() {
  1690  		rt.Interrupt("here is the error")
  1691  	}))
  1692  
  1693  	rt.Set("s", rt.ToValue(func(a Callable) (Value, error) {
  1694  		return a(nil)
  1695  	}))
  1696  
  1697  	_, err := rt.RunString(`
  1698          s(() =>{
  1699              v();
  1700          })
  1701  	`)
  1702  	if err == nil {
  1703  		t.Fatal("expected error but got no error")
  1704  	}
  1705  	var intErr *InterruptedError
  1706  	if !errors.As(err, &intErr) {
  1707  		t.Fatalf("Wrong error type: %T", err)
  1708  	}
  1709  	if !strings.Contains(intErr.Error(), "here is the error") {
  1710  		t.Fatalf("Wrong error message: %q", intErr.Error())
  1711  	}
  1712  }
  1713  
  1714  func TestInterruptInWrappedFunctionExpectStackOverflowError(t *testing.T) {
  1715  	rt := New()
  1716  	rt.SetMaxCallStackSize(5)
  1717  	// this test panics as otherwise goja will recover and possibly loop
  1718  	rt.Set("v", rt.ToValue(func() {
  1719  		_, err := rt.RunString(`
  1720  		(function loop() { loop() })();
  1721  		`)
  1722  		if err != nil {
  1723  			panic(err)
  1724  		}
  1725  	}))
  1726  
  1727  	rt.Set("s", rt.ToValue(func(a Callable) (Value, error) {
  1728  		return a(nil)
  1729  	}))
  1730  
  1731  	_, err := rt.RunString(`
  1732          s(() =>{
  1733              v();
  1734          })
  1735  	`)
  1736  	if err == nil {
  1737  		t.Fatal("expected error but got no error")
  1738  	}
  1739  	var soErr *StackOverflowError
  1740  	if !errors.As(err, &soErr) {
  1741  		t.Fatalf("Wrong error type: %T", err)
  1742  	}
  1743  }
  1744  
  1745  func TestRunLoopPreempt(t *testing.T) {
  1746  	vm := New()
  1747  	v, err := vm.RunString("(function() {for (;;) {}})")
  1748  	if err != nil {
  1749  		t.Fatal(err)
  1750  	}
  1751  
  1752  	fn, ok := AssertFunction(v)
  1753  	if !ok {
  1754  		t.Fatal("Not a function")
  1755  	}
  1756  
  1757  	go func() {
  1758  		<-time.After(100 * time.Millisecond)
  1759  		runtime.GC() // this hangs if the vm loop does not have any preemption points
  1760  		vm.Interrupt(errors.New("hi"))
  1761  	}()
  1762  
  1763  	_, err = fn(nil)
  1764  	if err == nil {
  1765  		t.Fatal("expected error")
  1766  	}
  1767  	if _, ok := err.(*InterruptedError); !ok {
  1768  		t.Fatalf("Wrong error type: %T", err)
  1769  	}
  1770  }
  1771  
  1772  func TestNaN(t *testing.T) {
  1773  	if !IsNaN(_NaN) {
  1774  		t.Fatal("IsNaN() doesn't detect NaN")
  1775  	}
  1776  	if IsNaN(Undefined()) {
  1777  		t.Fatal("IsNaN() says undefined is a NaN")
  1778  	}
  1779  	if !IsNaN(NaN()) {
  1780  		t.Fatal("NaN() doesn't return NaN")
  1781  	}
  1782  }
  1783  
  1784  func TestInf(t *testing.T) {
  1785  	if !IsInfinity(_positiveInf) {
  1786  		t.Fatal("IsInfinity() doesn't detect +Inf")
  1787  	}
  1788  	if !IsInfinity(_negativeInf) {
  1789  		t.Fatal("IsInfinity() doesn't detect -Inf")
  1790  	}
  1791  	if IsInfinity(Undefined()) {
  1792  		t.Fatal("IsInfinity() says undefined is a Infinity")
  1793  	}
  1794  	if !IsInfinity(PositiveInf()) {
  1795  		t.Fatal("PositiveInfinity() doesn't return Inf")
  1796  	}
  1797  	if !IsInfinity(NegativeInf()) {
  1798  		t.Fatal("NegativeInfinity() doesn't return Inf")
  1799  	}
  1800  }
  1801  
  1802  func TestRuntimeNew(t *testing.T) {
  1803  	vm := New()
  1804  	v, err := vm.New(vm.Get("Number"), vm.ToValue("12345"))
  1805  	if err != nil {
  1806  		t.Fatal(err)
  1807  	}
  1808  	if n, ok := v.Export().(int64); ok {
  1809  		if n != 12345 {
  1810  			t.Fatalf("n: %v", n)
  1811  		}
  1812  	} else {
  1813  		t.Fatalf("v: %T", v)
  1814  	}
  1815  }
  1816  
  1817  func TestAutoBoxing(t *testing.T) {
  1818  	const SCRIPT = `
  1819  	function f() {
  1820  		'use strict';
  1821  		var a = 1;
  1822  		var thrown1 = false;
  1823  		var thrown2 = false;
  1824  		try {
  1825  			a.test = 42;
  1826  		} catch (e) {
  1827  			thrown1 = e instanceof TypeError;
  1828  		}
  1829  		try {
  1830  			a["test1"] = 42;
  1831  		} catch (e) {
  1832  			thrown2 = e instanceof TypeError;
  1833  		}
  1834  		return thrown1 && thrown2;
  1835  	}
  1836  	var a = 1;
  1837  	a.test = 42; // should not throw
  1838  	a["test1"] = 42; // should not throw
  1839  	a.test === undefined && a.test1 === undefined && f();
  1840  	`
  1841  
  1842  	testScript(SCRIPT, valueTrue, t)
  1843  }
  1844  
  1845  func TestProtoGetter(t *testing.T) {
  1846  	const SCRIPT = `
  1847  	({}).__proto__ === Object.prototype && [].__proto__ === Array.prototype;
  1848  	`
  1849  	testScript(SCRIPT, valueTrue, t)
  1850  }
  1851  
  1852  func TestSymbol1(t *testing.T) {
  1853  	const SCRIPT = `
  1854  		Symbol.toPrimitive[Symbol.toPrimitive]() === Symbol.toPrimitive;
  1855  	`
  1856  
  1857  	testScript(SCRIPT, valueTrue, t)
  1858  }
  1859  
  1860  func TestFreezeSymbol(t *testing.T) {
  1861  	const SCRIPT = `
  1862  		var s = Symbol(1);
  1863  		var o = {};
  1864  		o[s] = 42;
  1865  		Object.freeze(o);
  1866  		o[s] = 43;
  1867  		o[s] === 42 && Object.isFrozen(o);
  1868  	`
  1869  
  1870  	testScript(SCRIPT, valueTrue, t)
  1871  }
  1872  
  1873  func TestToPropertyKey(t *testing.T) {
  1874  	const SCRIPT = `
  1875  	var sym = Symbol(42);
  1876  	var callCount = 0;
  1877  
  1878  	var wrapper = {
  1879  	  toString: function() {
  1880  		callCount += 1;
  1881  		return sym;
  1882  	  },
  1883  	  valueOf: function() {
  1884  		$ERROR("valueOf() called");
  1885  	  }
  1886  	};
  1887  
  1888  	var o = {};
  1889  	o[wrapper] = function() { return "test" };
  1890  	assert.sameValue(o[wrapper], o[sym], "o[wrapper] === o[sym]");
  1891  	assert.sameValue(o[wrapper](), "test", "o[wrapper]()");
  1892  	assert.sameValue(o[sym](), "test", "o[sym]()");
  1893  
  1894  	var wrapper1 = {};
  1895  	wrapper1[Symbol.toPrimitive] = function(hint) {
  1896  		if (hint === "string" || hint === "default") {
  1897  			return "1";
  1898  		}
  1899  		if (hint === "number") {
  1900  			return 2;
  1901  		}
  1902  		$ERROR("Unknown hint value "+hint);
  1903  	};
  1904  	var a = [];
  1905  	a[wrapper1] = 42;
  1906  	assert.sameValue(a[1], 42, "a[1]");
  1907  	assert.sameValue(a[1], a[wrapper1], "a[1] === a[wrapper1]");
  1908  	`
  1909  
  1910  	testScriptWithTestLib(SCRIPT, _undefined, t)
  1911  }
  1912  
  1913  func TestPrimThisValue(t *testing.T) {
  1914  	const SCRIPT = `
  1915  	function t() {
  1916  		'use strict';
  1917  
  1918  		Boolean.prototype.toString = function() {
  1919  		  return typeof this;
  1920  		};
  1921  
  1922  		assert.sameValue(true.toLocaleString(), "boolean");
  1923  
  1924  		Boolean.prototype[Symbol.iterator] = function() {
  1925  			return [typeof this][Symbol.iterator]();
  1926  		}
  1927  		var s = new Set(true);
  1928  		assert.sameValue(s.size, 1, "size");
  1929  		assert.sameValue(s.has("boolean"), true, "s.has('boolean')");
  1930  	}
  1931  	t();
  1932  	`
  1933  
  1934  	testScriptWithTestLib(SCRIPT, _undefined, t)
  1935  }
  1936  
  1937  func TestPrimThisValueGetter(t *testing.T) {
  1938  	const SCRIPT = `
  1939  	function t() {
  1940  		'use strict';
  1941  		Object.defineProperty(Boolean.prototype, "toString", {
  1942  		  get: function() {
  1943  			var v = typeof this;
  1944  			return function() {
  1945  			  return v;
  1946  			};
  1947  		  }
  1948  		});
  1949  
  1950  		assert.sameValue(true.toLocaleString(), "boolean");
  1951  	}
  1952  	t();
  1953  	`
  1954  
  1955  	testScriptWithTestLib(SCRIPT, _undefined, t)
  1956  }
  1957  
  1958  func TestObjSetSym(t *testing.T) {
  1959  	const SCRIPT = `
  1960  	'use strict';
  1961  	var sym = Symbol(true);
  1962  	var p1 = Object.create(null);
  1963  	var p2 = Object.create(p1);
  1964  	
  1965  	Object.defineProperty(p1, sym, {
  1966  	value: 42
  1967  	});
  1968  	
  1969  	Object.defineProperty(p2, sym, {
  1970  	value: 43,
  1971  	writable: true,
  1972  	});
  1973  	var o = Object.create(p2);
  1974  	o[sym] = 44;
  1975  	o[sym];
  1976  	`
  1977  	testScript(SCRIPT, intToValue(44), t)
  1978  }
  1979  
  1980  func TestObjSet(t *testing.T) {
  1981  	const SCRIPT = `
  1982  	'use strict';
  1983  	var p1 = Object.create(null);
  1984  	var p2 = Object.create(p1);
  1985  	
  1986  	Object.defineProperty(p1, "test", {
  1987  	value: 42
  1988  	});
  1989  	
  1990  	Object.defineProperty(p2, "test", {
  1991  	value: 43,
  1992  	writable: true,
  1993  	});
  1994  	var o = Object.create(p2);
  1995  	o.test = 44;
  1996  	o.test;
  1997  	`
  1998  	testScript(SCRIPT, intToValue(44), t)
  1999  }
  2000  
  2001  func TestToValueNilValue(t *testing.T) {
  2002  	r := New()
  2003  	var a Value
  2004  	r.Set("a", a)
  2005  	ret, err := r.RunString(`
  2006  	""+a;
  2007  	`)
  2008  	if err != nil {
  2009  		t.Fatal(err)
  2010  	}
  2011  	if !asciiString("null").SameAs(ret) {
  2012  		t.Fatalf("ret: %v", ret)
  2013  	}
  2014  }
  2015  
  2016  func TestDateConversion(t *testing.T) {
  2017  	now := time.Now()
  2018  	vm := New()
  2019  	val, err := vm.New(vm.Get("Date").ToObject(vm), vm.ToValue(now.UnixNano()/1e6))
  2020  	if err != nil {
  2021  		t.Fatal(err)
  2022  	}
  2023  	vm.Set("d", val)
  2024  	res, err := vm.RunString(`+d`)
  2025  	if err != nil {
  2026  		t.Fatal(err)
  2027  	}
  2028  	if exp := res.Export(); exp != now.UnixNano()/1e6 {
  2029  		t.Fatalf("Value does not match: %v", exp)
  2030  	}
  2031  	vm.Set("goval", now)
  2032  	res, err = vm.RunString(`+(new Date(goval.UnixNano()/1e6))`)
  2033  	if err != nil {
  2034  		t.Fatal(err)
  2035  	}
  2036  	if exp := res.Export(); exp != now.UnixNano()/1e6 {
  2037  		t.Fatalf("Value does not match: %v", exp)
  2038  	}
  2039  }
  2040  
  2041  func TestNativeCtorNewTarget(t *testing.T) {
  2042  	const SCRIPT = `
  2043  	function NewTarget() {
  2044  	}
  2045  
  2046  	var o = Reflect.construct(Number, [1], NewTarget);
  2047  	o.__proto__ === NewTarget.prototype && o.toString() === "[object Number]";
  2048  	`
  2049  	testScript(SCRIPT, valueTrue, t)
  2050  }
  2051  
  2052  func TestNativeCtorNonNewCall(t *testing.T) {
  2053  	vm := New()
  2054  	vm.Set(`Animal`, func(call ConstructorCall) *Object {
  2055  		obj := call.This
  2056  		obj.Set(`name`, call.Argument(0).String())
  2057  		obj.Set(`eat`, func(call FunctionCall) Value {
  2058  			self := call.This.(*Object)
  2059  			return vm.ToValue(fmt.Sprintf("%s eat", self.Get(`name`)))
  2060  		})
  2061  		return nil
  2062  	})
  2063  	v, err := vm.RunString(`
  2064  
  2065  	function __extends(d, b){
  2066  		function __() {
  2067  			this.constructor = d;
  2068  		}
  2069  		d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  2070  	}
  2071  
  2072  	var Cat = (function (_super) {
  2073  		__extends(Cat, _super);
  2074  		function Cat() {
  2075  			return _super.call(this, "cat") || this;
  2076  		}
  2077  		return Cat;
  2078  	}(Animal));
  2079  
  2080  	var cat = new Cat();
  2081  	cat instanceof Cat && cat.eat() === "cat eat";
  2082  	`)
  2083  	if err != nil {
  2084  		t.Fatal(err)
  2085  	}
  2086  	if v != valueTrue {
  2087  		t.Fatal(v)
  2088  	}
  2089  }
  2090  
  2091  func ExampleNewSymbol() {
  2092  	sym1 := NewSymbol("66")
  2093  	sym2 := NewSymbol("66")
  2094  	fmt.Printf("%s %s %v", sym1, sym2, sym1.Equals(sym2))
  2095  	// Output: 66 66 false
  2096  }
  2097  
  2098  func ExampleObject_SetSymbol() {
  2099  	type IterResult struct {
  2100  		Done  bool
  2101  		Value Value
  2102  	}
  2103  
  2104  	vm := New()
  2105  	vm.SetFieldNameMapper(UncapFieldNameMapper()) // to use IterResult
  2106  
  2107  	o := vm.NewObject()
  2108  	o.SetSymbol(SymIterator, func() *Object {
  2109  		count := 0
  2110  		iter := vm.NewObject()
  2111  		iter.Set("next", func() IterResult {
  2112  			if count < 10 {
  2113  				count++
  2114  				return IterResult{
  2115  					Value: vm.ToValue(count),
  2116  				}
  2117  			}
  2118  			return IterResult{
  2119  				Done: true,
  2120  			}
  2121  		})
  2122  		return iter
  2123  	})
  2124  	vm.Set("o", o)
  2125  
  2126  	res, err := vm.RunString(`
  2127  	var acc = "";
  2128  	for (var v of o) {
  2129  		acc += v + " ";
  2130  	}
  2131  	acc;
  2132  	`)
  2133  	if err != nil {
  2134  		panic(err)
  2135  	}
  2136  	fmt.Println(res)
  2137  	// Output: 1 2 3 4 5 6 7 8 9 10
  2138  }
  2139  
  2140  func ExampleRuntime_NewArray() {
  2141  	vm := New()
  2142  	array := vm.NewArray(1, 2, true)
  2143  	vm.Set("array", array)
  2144  	res, err := vm.RunString(`
  2145  	var acc = "";
  2146  	for (var v of array) {
  2147  		acc += v + " ";
  2148  	}
  2149  	acc;
  2150  	`)
  2151  	if err != nil {
  2152  		panic(err)
  2153  	}
  2154  	fmt.Println(res)
  2155  	// Output: 1 2 true
  2156  }
  2157  
  2158  func ExampleRuntime_SetParserOptions() {
  2159  	vm := New()
  2160  	vm.SetParserOptions(parser.WithDisableSourceMaps)
  2161  
  2162  	res, err := vm.RunString(`
  2163  	"I did not hang!";
  2164  //# sourceMappingURL=/dev/zero`)
  2165  
  2166  	if err != nil {
  2167  		panic(err)
  2168  	}
  2169  	fmt.Println(res.String())
  2170  	// Output: I did not hang!
  2171  }
  2172  
  2173  func TestRuntime_SetParserOptions_Eval(t *testing.T) {
  2174  	vm := New()
  2175  	vm.SetParserOptions(parser.WithDisableSourceMaps)
  2176  
  2177  	_, err := vm.RunString(`
  2178  	eval("//# sourceMappingURL=/dev/zero");
  2179  	`)
  2180  	if err != nil {
  2181  		t.Fatal(err)
  2182  	}
  2183  }
  2184  
  2185  func TestNativeCallWithRuntimeParameter(t *testing.T) {
  2186  	vm := New()
  2187  	vm.Set("f", func(_ FunctionCall, r *Runtime) Value {
  2188  		if r == vm {
  2189  			return valueTrue
  2190  		}
  2191  		return valueFalse
  2192  	})
  2193  	ret, err := vm.RunString(`f()`)
  2194  	if err != nil {
  2195  		t.Fatal(err)
  2196  	}
  2197  	if ret != valueTrue {
  2198  		t.Fatal(ret)
  2199  	}
  2200  }
  2201  
  2202  func TestNestedEnumerate(t *testing.T) {
  2203  	const SCRIPT = `
  2204  	var o = {baz: true, foo: true, bar: true};
  2205  	var res = "";
  2206  	for (var i in o) {
  2207  		delete o.baz;
  2208  		Object.defineProperty(o, "hidden", {value: true, configurable: true});
  2209  		for (var j in o) {
  2210  			Object.defineProperty(o, "0", {value: true, configurable: true});
  2211  			Object.defineProperty(o, "1", {value: true, configurable: true});
  2212  			for (var k in o) {}
  2213  			res += i + "-" + j + " ";
  2214  		}
  2215  	}
  2216  	assert(compareArray(Reflect.ownKeys(o), ["0","1","foo","bar","hidden"]), "keys");
  2217  	res;
  2218  	`
  2219  	testScriptWithTestLib(SCRIPT, asciiString("baz-foo baz-bar foo-foo foo-bar bar-foo bar-bar "), t)
  2220  }
  2221  
  2222  func TestAbandonedEnumerate(t *testing.T) {
  2223  	const SCRIPT = `
  2224  	var o = {baz: true, foo: true, bar: true};
  2225  	var res = "";
  2226  	for (var i in o) {
  2227  		delete o.baz;
  2228  		for (var j in o) {
  2229  			res += i + "-" + j + " ";
  2230  			break;
  2231  		}
  2232  	}
  2233  	res;
  2234  	`
  2235  	testScript(SCRIPT, asciiString("baz-foo foo-foo bar-foo "), t)
  2236  }
  2237  
  2238  func TestIterCloseThrows(t *testing.T) {
  2239  	const SCRIPT = `
  2240  	var returnCount = 0;
  2241  	var iterable = {};
  2242  	var iterator = {
  2243  	  next: function() {
  2244  		return { value: true };
  2245  	  },
  2246  	  return: function() {
  2247  		returnCount += 1;
  2248  		throw new Error();
  2249  	  }
  2250  	};
  2251  	iterable[Symbol.iterator] = function() {
  2252  	  return iterator;
  2253  	};
  2254  
  2255  	try {
  2256  		for (var i of iterable) {
  2257  				break;
  2258  		}
  2259  	} catch (e) {};
  2260  	returnCount;
  2261  	`
  2262  	testScript(SCRIPT, valueInt(1), t)
  2263  }
  2264  
  2265  func TestDeclareGlobalFunc(t *testing.T) {
  2266  	const SCRIPT = `
  2267  	var initial;
  2268  
  2269  	Object.defineProperty(this, 'f', {
  2270  	  enumerable: true,
  2271  	  writable: true,
  2272  	  configurable: false
  2273  	});
  2274  
  2275  	(0,eval)('initial = f; function f() { return 2222; }');
  2276  	var desc = Object.getOwnPropertyDescriptor(this, "f");
  2277  	assert(desc.enumerable, "enumerable");
  2278  	assert(desc.writable, "writable");
  2279  	assert(!desc.configurable, "configurable");
  2280  	assert.sameValue(initial(), 2222);
  2281  	`
  2282  	testScriptWithTestLib(SCRIPT, _undefined, t)
  2283  }
  2284  
  2285  func TestStackOverflowError(t *testing.T) {
  2286  	vm := New()
  2287  	vm.SetMaxCallStackSize(3)
  2288  	_, err := vm.RunString(`
  2289  	function f() {
  2290  		f();
  2291  	}
  2292  	f();
  2293  	`)
  2294  	if _, ok := err.(*StackOverflowError); !ok {
  2295  		t.Fatal(err)
  2296  	}
  2297  }
  2298  
  2299  func TestStacktraceLocationThrowFromCatch(t *testing.T) {
  2300  	vm := New()
  2301  	_, err := vm.RunString(`
  2302  	function main(arg) {
  2303  		try {
  2304  			if (arg === 1) {
  2305  				return f1();
  2306  			}
  2307  			if (arg === 2) {
  2308  				return f2();
  2309  			}
  2310  			if (arg === 3) {
  2311  				return f3();
  2312  			}
  2313  		} catch (e) {
  2314  			throw e;
  2315  		}
  2316  	}
  2317  	function f1() {}
  2318  	function f2() {
  2319  		throw new Error();
  2320  	}
  2321  	function f3() {}
  2322  	main(2);
  2323  	`)
  2324  	if err == nil {
  2325  		t.Fatal("Expected error")
  2326  	}
  2327  	stack := err.(*Exception).stack
  2328  	if len(stack) != 2 {
  2329  		t.Fatalf("Unexpected stack len: %v", stack)
  2330  	}
  2331  	if frame := stack[0]; frame.funcName != "main" || frame.pc != 29 {
  2332  		t.Fatalf("Unexpected stack frame 0: %#v", frame)
  2333  	}
  2334  	if frame := stack[1]; frame.funcName != "" || frame.pc != 7 {
  2335  		t.Fatalf("Unexpected stack frame 1: %#v", frame)
  2336  	}
  2337  }
  2338  
  2339  func TestStacktraceLocationThrowFromGo(t *testing.T) {
  2340  	vm := New()
  2341  	f := func() {
  2342  		panic(vm.ToValue("Test"))
  2343  	}
  2344  	vm.Set("f", f)
  2345  	_, err := vm.RunString(`
  2346  	function main() {
  2347  		(function noop() {})();
  2348  		return callee();
  2349  	}
  2350  	function callee() {
  2351  		return f();
  2352  	}
  2353  	main();
  2354  	`)
  2355  	if err == nil {
  2356  		t.Fatal("Expected error")
  2357  	}
  2358  	stack := err.(*Exception).stack
  2359  	if len(stack) != 4 {
  2360  		t.Fatalf("Unexpected stack len: %v", stack)
  2361  	}
  2362  	if frame := stack[0]; !strings.HasSuffix(frame.funcName.String(), "TestStacktraceLocationThrowFromGo.func1") {
  2363  		t.Fatalf("Unexpected stack frame 0: %#v", frame)
  2364  	}
  2365  	if frame := stack[1]; frame.funcName != "callee" || frame.pc != 2 {
  2366  		t.Fatalf("Unexpected stack frame 1: %#v", frame)
  2367  	}
  2368  	if frame := stack[2]; frame.funcName != "main" || frame.pc != 6 {
  2369  		t.Fatalf("Unexpected stack frame 2: %#v", frame)
  2370  	}
  2371  	if frame := stack[3]; frame.funcName != "" || frame.pc != 4 {
  2372  		t.Fatalf("Unexpected stack frame 3: %#v", frame)
  2373  	}
  2374  }
  2375  
  2376  func TestStacktraceLocationThrowNativeInTheMiddle(t *testing.T) {
  2377  	vm := New()
  2378  	v, err := vm.RunString(`(function f1() {
  2379  		throw new Error("test")
  2380  	})`)
  2381  	if err != nil {
  2382  		t.Fatal(err)
  2383  	}
  2384  
  2385  	var f1 func()
  2386  	err = vm.ExportTo(v, &f1)
  2387  	if err != nil {
  2388  		t.Fatal(err)
  2389  	}
  2390  
  2391  	f := func() {
  2392  		f1()
  2393  	}
  2394  	vm.Set("f", f)
  2395  	_, err = vm.RunString(`
  2396  	function main() {
  2397  		(function noop() {})();
  2398  		return callee();
  2399  	}
  2400  	function callee() {
  2401  		return f();
  2402  	}
  2403  	main();
  2404  	`)
  2405  	if err == nil {
  2406  		t.Fatal("Expected error")
  2407  	}
  2408  	stack := err.(*Exception).stack
  2409  	if len(stack) != 5 {
  2410  		t.Fatalf("Unexpected stack len: %v", stack)
  2411  	}
  2412  	if frame := stack[0]; frame.funcName != "f1" || frame.pc != 7 {
  2413  		t.Fatalf("Unexpected stack frame 0: %#v", frame)
  2414  	}
  2415  	if frame := stack[1]; !strings.HasSuffix(frame.funcName.String(), "TestStacktraceLocationThrowNativeInTheMiddle.func1") {
  2416  		t.Fatalf("Unexpected stack frame 1: %#v", frame)
  2417  	}
  2418  	if frame := stack[2]; frame.funcName != "callee" || frame.pc != 2 {
  2419  		t.Fatalf("Unexpected stack frame 2: %#v", frame)
  2420  	}
  2421  	if frame := stack[3]; frame.funcName != "main" || frame.pc != 6 {
  2422  		t.Fatalf("Unexpected stack frame 3: %#v", frame)
  2423  	}
  2424  	if frame := stack[4]; frame.funcName != "" || frame.pc != 4 {
  2425  		t.Fatalf("Unexpected stack frame 4: %#v", frame)
  2426  	}
  2427  }
  2428  
  2429  func TestStrToInt64(t *testing.T) {
  2430  	if _, ok := strToInt64(""); ok {
  2431  		t.Fatal("<empty>")
  2432  	}
  2433  	if n, ok := strToInt64("0"); !ok || n != 0 {
  2434  		t.Fatal("0", n, ok)
  2435  	}
  2436  	if n, ok := strToInt64("-0"); ok {
  2437  		t.Fatal("-0", n, ok)
  2438  	}
  2439  	if n, ok := strToInt64("-1"); !ok || n != -1 {
  2440  		t.Fatal("-1", n, ok)
  2441  	}
  2442  	if n, ok := strToInt64("9223372036854775808"); ok {
  2443  		t.Fatal("max+1", n, ok)
  2444  	}
  2445  	if n, ok := strToInt64("9223372036854775817"); ok {
  2446  		t.Fatal("9223372036854775817", n, ok)
  2447  	}
  2448  	if n, ok := strToInt64("-9223372036854775818"); ok {
  2449  		t.Fatal("-9223372036854775818", n, ok)
  2450  	}
  2451  	if n, ok := strToInt64("9223372036854775807"); !ok || n != 9223372036854775807 {
  2452  		t.Fatal("max", n, ok)
  2453  	}
  2454  	if n, ok := strToInt64("-9223372036854775809"); ok {
  2455  		t.Fatal("min-1", n, ok)
  2456  	}
  2457  	if n, ok := strToInt64("-9223372036854775808"); !ok || n != -9223372036854775808 {
  2458  		t.Fatal("min", n, ok)
  2459  	}
  2460  	if n, ok := strToInt64("-00"); ok {
  2461  		t.Fatal("-00", n, ok)
  2462  	}
  2463  	if n, ok := strToInt64("-01"); ok {
  2464  		t.Fatal("-01", n, ok)
  2465  	}
  2466  }
  2467  
  2468  func TestStrToInt32(t *testing.T) {
  2469  	if _, ok := strToInt32(""); ok {
  2470  		t.Fatal("<empty>")
  2471  	}
  2472  	if n, ok := strToInt32("0"); !ok || n != 0 {
  2473  		t.Fatal("0", n, ok)
  2474  	}
  2475  	if n, ok := strToInt32("-0"); ok {
  2476  		t.Fatal("-0", n, ok)
  2477  	}
  2478  	if n, ok := strToInt32("-1"); !ok || n != -1 {
  2479  		t.Fatal("-1", n, ok)
  2480  	}
  2481  	if n, ok := strToInt32("2147483648"); ok {
  2482  		t.Fatal("max+1", n, ok)
  2483  	}
  2484  	if n, ok := strToInt32("2147483657"); ok {
  2485  		t.Fatal("2147483657", n, ok)
  2486  	}
  2487  	if n, ok := strToInt32("-2147483658"); ok {
  2488  		t.Fatal("-2147483658", n, ok)
  2489  	}
  2490  	if n, ok := strToInt32("2147483647"); !ok || n != 2147483647 {
  2491  		t.Fatal("max", n, ok)
  2492  	}
  2493  	if n, ok := strToInt32("-2147483649"); ok {
  2494  		t.Fatal("min-1", n, ok)
  2495  	}
  2496  	if n, ok := strToInt32("-2147483648"); !ok || n != -2147483648 {
  2497  		t.Fatal("min", n, ok)
  2498  	}
  2499  	if n, ok := strToInt32("-00"); ok {
  2500  		t.Fatal("-00", n, ok)
  2501  	}
  2502  	if n, ok := strToInt32("-01"); ok {
  2503  		t.Fatal("-01", n, ok)
  2504  	}
  2505  }
  2506  
  2507  func TestDestructSymbol(t *testing.T) {
  2508  	const SCRIPT = `
  2509  	var S = Symbol("S");
  2510  	var s, rest;
  2511  
  2512  	({[S]: s, ...rest} = {[S]: true, test: 1});
  2513  	assert.sameValue(s, true, "S");
  2514  	assert(deepEqual(rest, {test: 1}), "rest");
  2515  	`
  2516  	testScriptWithTestLibX(SCRIPT, _undefined, t)
  2517  }
  2518  
  2519  func TestAccessorFuncName(t *testing.T) {
  2520  	const SCRIPT = `
  2521  	const namedSym = Symbol('test262');
  2522  	const emptyStrSym = Symbol("");
  2523  	const anonSym = Symbol();
  2524  
  2525  	const o = {
  2526  	  get id() {},
  2527  	  get [anonSym]() {},
  2528  	  get [namedSym]() {},
  2529        get [emptyStrSym]() {},
  2530  	  set id(v) {},
  2531  	  set [anonSym](v) {},
  2532  	  set [namedSym](v) {},
  2533        set [emptyStrSym](v) {}
  2534  	};
  2535  
  2536  	let prop;
  2537  	prop = Object.getOwnPropertyDescriptor(o, 'id');
  2538  	assert.sameValue(prop.get.name, 'get id');
  2539  	assert.sameValue(prop.set.name, 'set id');
  2540  
  2541  	prop = Object.getOwnPropertyDescriptor(o, anonSym);
  2542  	assert.sameValue(prop.get.name, 'get ');
  2543  	assert.sameValue(prop.set.name, 'set ');
  2544  
  2545  	prop = Object.getOwnPropertyDescriptor(o, emptyStrSym);
  2546  	assert.sameValue(prop.get.name, 'get []');
  2547  	assert.sameValue(prop.set.name, 'set []');
  2548  
  2549  	prop = Object.getOwnPropertyDescriptor(o, namedSym);
  2550  	assert.sameValue(prop.get.name, 'get [test262]');
  2551  	assert.sameValue(prop.set.name, 'set [test262]');
  2552  	`
  2553  	testScriptWithTestLib(SCRIPT, _undefined, t)
  2554  }
  2555  
  2556  func TestCoverFuncName(t *testing.T) {
  2557  	const SCRIPT = `
  2558  	var namedSym = Symbol('');
  2559  	var anonSym = Symbol();
  2560  	var o;
  2561  
  2562  	o = {
  2563  	  xId: (0, function() {}),
  2564  	  id: (function() {}),
  2565        id1: function x() {},
  2566  	  [anonSym]: (function() {}),
  2567  	  [namedSym]: (function() {})
  2568  	};
  2569  
  2570  	assert(o.xId.name !== 'xId');
  2571  	assert.sameValue(o.id1.name, 'x'); 
  2572  	assert.sameValue(o.id.name, 'id', 'via IdentifierName');
  2573  	assert.sameValue(o[anonSym].name, '', 'via anonymous Symbol');
  2574  	assert.sameValue(o[namedSym].name, '[]', 'via Symbol');
  2575  	`
  2576  	testScriptWithTestLib(SCRIPT, _undefined, t)
  2577  }
  2578  
  2579  func TestAnonFuncName(t *testing.T) {
  2580  	const SCRIPT = `
  2581  	const d = Object.getOwnPropertyDescriptor((function() {}), 'name');
  2582  	d !== undefined && d.value === '';
  2583  	`
  2584  	testScript(SCRIPT, valueTrue, t)
  2585  }
  2586  
  2587  func TestStringToBytesConversion(t *testing.T) {
  2588  	vm := New()
  2589  	v := vm.ToValue("Test")
  2590  	var b []byte
  2591  	err := vm.ExportTo(v, &b)
  2592  	if err != nil {
  2593  		t.Fatal(err)
  2594  	}
  2595  	if string(b) != "Test" {
  2596  		t.Fatal(b)
  2597  	}
  2598  }
  2599  
  2600  func TestPromiseAll(t *testing.T) {
  2601  	const SCRIPT = `
  2602  var p1 = new Promise(function() {});
  2603  var p2 = new Promise(function() {});
  2604  var p3 = new Promise(function() {});
  2605  var callCount = 0;
  2606  var currentThis = p1;
  2607  var nextThis = p2;
  2608  var afterNextThis = p3;
  2609  
  2610  p1.then = p2.then = p3.then = function(a, b) {
  2611    assert.sameValue(typeof a, 'function', 'type of first argument');
  2612    assert.sameValue(
  2613      a.length,
  2614      1,
  2615      'ES6 25.4.1.3.2: The length property of a promise resolve function is 1.'
  2616    );
  2617    assert.sameValue(typeof b, 'function', 'type of second argument');
  2618    assert.sameValue(
  2619      b.length,
  2620      1,
  2621      'ES6 25.4.1.3.1: The length property of a promise reject function is 1.'
  2622    );
  2623    assert.sameValue(arguments.length, 2, '"then"" invoked with two arguments');
  2624    assert.sameValue(this, currentThis, '"this" value');
  2625  
  2626    currentThis = nextThis;
  2627    nextThis = afterNextThis;
  2628    afterNextThis = null;
  2629  
  2630    callCount += 1;
  2631  };
  2632  
  2633  Promise.all([p1, p2, p3]);
  2634  
  2635  assert.sameValue(callCount, 3, '"then"" invoked once for every iterated value');
  2636  	`
  2637  	testScriptWithTestLib(SCRIPT, _undefined, t)
  2638  }
  2639  
  2640  func TestPromiseExport(t *testing.T) {
  2641  	vm := New()
  2642  	p, _, _ := vm.NewPromise()
  2643  	pv := vm.ToValue(p)
  2644  	if actual := pv.ExportType(); actual != reflect.TypeOf((*Promise)(nil)) {
  2645  		t.Fatalf("Export type: %v", actual)
  2646  	}
  2647  
  2648  	if ev := pv.Export(); ev != p {
  2649  		t.Fatalf("Export value: %v", ev)
  2650  	}
  2651  }
  2652  
  2653  func TestErrorStack(t *testing.T) {
  2654  	const SCRIPT = `
  2655  	const err = new Error("test");
  2656  	if (!("stack" in err)) {
  2657  		throw new Error("in");
  2658  	}
  2659  	if (Reflect.ownKeys(err)[0] !== "stack") {
  2660  		throw new Error("property order");
  2661  	}
  2662  	const stack = err.stack;
  2663  	if (stack !== "Error: test\n\tat test.js:2:14(3)\n") {
  2664  		throw new Error(stack);
  2665  	}
  2666  	delete err.stack;
  2667  	if ("stack" in err) {
  2668  		throw new Error("stack still in err after delete");
  2669  	}
  2670  	`
  2671  	testScript(SCRIPT, _undefined, t)
  2672  }
  2673  
  2674  func TestErrorFormatSymbols(t *testing.T) {
  2675  	vm := New()
  2676  	vm.Set("a", func() (Value, error) { return nil, errors.New("something %s %f") })
  2677  	_, err := vm.RunString("a()")
  2678  	if !strings.Contains(err.Error(), "something %s %f") {
  2679  		t.Fatalf("Wrong value %q", err.Error())
  2680  	}
  2681  }
  2682  
  2683  func TestPanicPassthrough(t *testing.T) {
  2684  	const panicString = "Test panic"
  2685  	r := New()
  2686  	r.Set("f", func() {
  2687  		panic(panicString)
  2688  	})
  2689  	defer func() {
  2690  		if x := recover(); x != nil {
  2691  			if x != panicString {
  2692  				t.Fatalf("Wrong panic value: %v", x)
  2693  			}
  2694  			if len(r.vm.callStack) > 0 {
  2695  				t.Fatal("vm.callStack is not empty")
  2696  			}
  2697  		} else {
  2698  			t.Fatal("No panic")
  2699  		}
  2700  	}()
  2701  	_, _ = r.RunString("f()")
  2702  	t.Fatal("Should not reach here")
  2703  }
  2704  
  2705  func TestSuspendResumeRelStackLen(t *testing.T) {
  2706  	const SCRIPT = `
  2707  	async function f2() {
  2708  		throw new Error("test");
  2709  	}
  2710  
  2711  	async function f1() {
  2712  		let a = [1];
  2713  		for (let i of a) {
  2714  			try {
  2715  				await f2();
  2716  			} catch {
  2717  				return true;
  2718  			}
  2719  		}
  2720  	}
  2721  
  2722  	async function f() {
  2723  		let a = [1];
  2724  		for (let i of a) {
  2725  			return await f1();
  2726  		}
  2727  	}
  2728  	return f();
  2729  	`
  2730  	testAsyncFunc(SCRIPT, valueTrue, t)
  2731  }
  2732  
  2733  func TestSuspendResumeStacks(t *testing.T) {
  2734  	const SCRIPT = `
  2735  async function f1() {
  2736  	throw new Error();
  2737  }
  2738  async function f() {
  2739    try {
  2740  	await f1();
  2741    } catch {}
  2742  }
  2743  
  2744  result = await f();
  2745  	`
  2746  	testAsyncFunc(SCRIPT, _undefined, t)
  2747  }
  2748  
  2749  func TestNestedTopLevelConstructorCall(t *testing.T) {
  2750  	r := New()
  2751  	c := func(call ConstructorCall, rt *Runtime) *Object {
  2752  		if _, err := rt.RunString("(5)"); err != nil {
  2753  			panic(err)
  2754  		}
  2755  		return nil
  2756  	}
  2757  	if err := r.Set("C", c); err != nil {
  2758  		panic(err)
  2759  	}
  2760  	if _, err := r.RunString("new C()"); err != nil {
  2761  		panic(err)
  2762  	}
  2763  }
  2764  
  2765  func TestNestedTopLevelConstructorPanicAsync(t *testing.T) {
  2766  	r := New()
  2767  	c := func(call ConstructorCall, rt *Runtime) *Object {
  2768  		c, ok := AssertFunction(rt.ToValue(func() {}))
  2769  		if !ok {
  2770  			panic("wat")
  2771  		}
  2772  		if _, err := c(Undefined()); err != nil {
  2773  			panic(err)
  2774  		}
  2775  		return nil
  2776  	}
  2777  	if err := r.Set("C", c); err != nil {
  2778  		panic(err)
  2779  	}
  2780  	if _, err := r.RunString("new C()"); err != nil {
  2781  		panic(err)
  2782  	}
  2783  }
  2784  
  2785  func TestAsyncFuncThrow(t *testing.T) {
  2786  	const SCRIPT = `
  2787  	class TestError extends Error {
  2788  	}
  2789  
  2790  	async function f() {
  2791  		throw new TestError();
  2792  	}
  2793  
  2794  	async function f1() {
  2795  		try {
  2796  			await f();
  2797  		} catch (e) {
  2798  			assert.sameValue(e.constructor.name, TestError.name);
  2799  			return;
  2800  		}
  2801  		throw new Error("No exception was thrown");
  2802  	}
  2803  	await f1();
  2804  	return undefined;
  2805  	`
  2806  	testAsyncFuncWithTestLib(SCRIPT, _undefined, t)
  2807  }
  2808  
  2809  func TestAsyncStacktrace(t *testing.T) {
  2810  	// Do not reformat, assertions depend on the line and column numbers
  2811  	const SCRIPT = `
  2812  	let ex;
  2813  	async function foo(x) {
  2814  	  await bar(x);
  2815  	}
  2816  
  2817  	async function bar(x) {
  2818  	  await x;
  2819  	  throw new Error("Let's have a look...");
  2820  	}
  2821  
  2822  	try {
  2823  		await foo(1);
  2824  	} catch (e) {
  2825  		assertStack(e, [
  2826  			["test.js", "bar", 9, 10],
  2827  			["test.js", "foo", 4, 13],
  2828  			["test.js", "test", 13, 12],
  2829  		]);
  2830  	}
  2831  	`
  2832  	testAsyncFuncWithTestLibX(SCRIPT, _undefined, t)
  2833  }
  2834  
  2835  func TestPanicPropagation(t *testing.T) {
  2836  	r := New()
  2837  	r.Set("doPanic", func() {
  2838  		panic(true)
  2839  	})
  2840  	v, err := r.RunString(`(function() {
  2841  		doPanic();
  2842  	})`)
  2843  	if err != nil {
  2844  		t.Fatal(err)
  2845  	}
  2846  	f, ok := AssertFunction(v)
  2847  	if !ok {
  2848  		t.Fatal("not a function")
  2849  	}
  2850  	defer func() {
  2851  		if x := recover(); x != nil {
  2852  			if x != true {
  2853  				t.Fatal("Invalid panic value")
  2854  			}
  2855  		}
  2856  	}()
  2857  	_, _ = f(nil)
  2858  	t.Fatal("Expected panic")
  2859  }
  2860  
  2861  func TestAwaitInParameters(t *testing.T) {
  2862  	_, err := Compile("", `
  2863  	async function g() {
  2864  	    async function inner(a = 1 + await 1) {
  2865  	    }
  2866  	}
  2867  	`, false)
  2868  	if err == nil {
  2869  		t.Fatal("Expected error")
  2870  	}
  2871  }
  2872  
  2873  func ExampleRuntime_ForOf() {
  2874  	r := New()
  2875  	v, err := r.RunString(`
  2876  		new Map().set("a", 1).set("b", 2);
  2877  	`)
  2878  	if err != nil {
  2879  		panic(err)
  2880  	}
  2881  
  2882  	var sb strings.Builder
  2883  	ex := r.Try(func() {
  2884  		r.ForOf(v, func(v Value) bool {
  2885  			o := v.ToObject(r)
  2886  			key := o.Get("0")
  2887  			value := o.Get("1")
  2888  
  2889  			sb.WriteString(key.String())
  2890  			sb.WriteString("=")
  2891  			sb.WriteString(value.String())
  2892  			sb.WriteString(",")
  2893  
  2894  			return true
  2895  		})
  2896  	})
  2897  	if ex != nil {
  2898  		panic(ex)
  2899  	}
  2900  	fmt.Println(sb.String())
  2901  	// Output: a=1,b=2,
  2902  }
  2903  
  2904  /*
  2905  func TestArrayConcatSparse(t *testing.T) {
  2906  function foo(a,b,c)
  2907    {
  2908      arguments[0] = 1; arguments[1] = 'str'; arguments[2] = 2.1;
  2909      if(1 === a && 'str' === b && 2.1 === c)
  2910        return true;
  2911    }
  2912  
  2913  
  2914  	const SCRIPT = `
  2915  	var a1 = [];
  2916  	var a2 = [];
  2917  	a1[500000] = 1;
  2918  	a2[1000000] = 2;
  2919  	var a3 = a1.concat(a2);
  2920  	a3.length === 1500002 && a3[500000] === 1 && a3[1500001] == 2;
  2921  	`
  2922  
  2923  	testScript(SCRIPT, valueTrue, t)
  2924  }
  2925  */
  2926  
  2927  func BenchmarkCallReflect(b *testing.B) {
  2928  	vm := New()
  2929  	vm.Set("f", func(v Value) {
  2930  
  2931  	})
  2932  
  2933  	prg := MustCompile("test.js", "f(null)", true)
  2934  
  2935  	b.ResetTimer()
  2936  	for i := 0; i < b.N; i++ {
  2937  		vm.RunProgram(prg)
  2938  	}
  2939  }
  2940  
  2941  func BenchmarkCallNative(b *testing.B) {
  2942  	vm := New()
  2943  	vm.Set("f", func(call FunctionCall) (ret Value) {
  2944  		return
  2945  	})
  2946  
  2947  	prg := MustCompile("test.js", "f(null)", true)
  2948  
  2949  	b.ResetTimer()
  2950  	for i := 0; i < b.N; i++ {
  2951  		vm.RunProgram(prg)
  2952  	}
  2953  }
  2954  
  2955  func BenchmarkCallJS(b *testing.B) {
  2956  	vm := New()
  2957  	_, err := vm.RunString(`
  2958  	function f() {
  2959  		return 42;
  2960  	}
  2961  	`)
  2962  
  2963  	if err != nil {
  2964  		b.Fatal(err)
  2965  	}
  2966  
  2967  	prg := MustCompile("test.js", "f(null)", true)
  2968  
  2969  	b.ResetTimer()
  2970  	for i := 0; i < b.N; i++ {
  2971  		vm.RunProgram(prg)
  2972  	}
  2973  }
  2974  
  2975  func BenchmarkMainLoop(b *testing.B) {
  2976  	vm := New()
  2977  
  2978  	const SCRIPT = `
  2979  		for (var i=0; i<100000; i++) {
  2980  		}
  2981  	`
  2982  
  2983  	prg := MustCompile("test.js", SCRIPT, true)
  2984  
  2985  	b.ResetTimer()
  2986  	for i := 0; i < b.N; i++ {
  2987  		vm.RunProgram(prg)
  2988  	}
  2989  }
  2990  
  2991  func BenchmarkStringMapGet(b *testing.B) {
  2992  	m := make(map[string]Value)
  2993  	for i := 0; i < 100; i++ {
  2994  		m[strconv.Itoa(i)] = intToValue(int64(i))
  2995  	}
  2996  	b.ResetTimer()
  2997  	for i := 0; i < b.N; i++ {
  2998  		if m["50"] == nil {
  2999  			b.Fatal()
  3000  		}
  3001  	}
  3002  }
  3003  
  3004  func BenchmarkValueStringMapGet(b *testing.B) {
  3005  	m := make(map[String]Value)
  3006  	for i := 0; i < 100; i++ {
  3007  		m[asciiString(strconv.Itoa(i))] = intToValue(int64(i))
  3008  	}
  3009  	b.ResetTimer()
  3010  	var key String = asciiString("50")
  3011  	for i := 0; i < b.N; i++ {
  3012  		if m[key] == nil {
  3013  			b.Fatal()
  3014  		}
  3015  	}
  3016  }
  3017  
  3018  func BenchmarkAsciiStringMapGet(b *testing.B) {
  3019  	m := make(map[asciiString]Value)
  3020  	for i := 0; i < 100; i++ {
  3021  		m[asciiString(strconv.Itoa(i))] = intToValue(int64(i))
  3022  	}
  3023  	b.ResetTimer()
  3024  	var key = asciiString("50")
  3025  	for i := 0; i < b.N; i++ {
  3026  		if m[key] == nil {
  3027  			b.Fatal()
  3028  		}
  3029  	}
  3030  }