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 }