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