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