github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_proxy_test.go (about) 1 package goja 2 3 import ( 4 "strconv" 5 "testing" 6 ) 7 8 func TestProxy_Object_target_getPrototypeOf(t *testing.T) { 9 const SCRIPT = ` 10 var proto = {}; 11 var obj = Object.create(proto); 12 var proxy = new Proxy(obj, {}); 13 var p = Object.getPrototypeOf(proxy); 14 assert.sameValue(proto, p); 15 ` 16 17 testScriptWithTestLib(SCRIPT, _undefined, t) 18 } 19 20 func TestProxy_Object_proxy_getPrototypeOf(t *testing.T) { 21 const SCRIPT = ` 22 var proto = {}; 23 var proto2 = {}; 24 var obj = Object.create(proto); 25 var proxy = new Proxy(obj, { 26 getPrototypeOf: function(target) { 27 return proto2; 28 } 29 }); 30 var p = Object.getPrototypeOf(proxy); 31 assert.sameValue(proto2, p); 32 ` 33 34 testScriptWithTestLib(SCRIPT, _undefined, t) 35 } 36 37 func TestProxy_Object_native_proxy_getPrototypeOf(t *testing.T) { 38 const SCRIPT = ` 39 var p = Object.getPrototypeOf(proxy); 40 assert.sameValue(proto, p); 41 ` 42 43 runtime := New() 44 45 prototype := runtime.NewObject() 46 runtime.Set("proto", prototype) 47 48 target := runtime.NewObject() 49 proxy := runtime.NewProxy(target, &ProxyTrapConfig{ 50 GetPrototypeOf: func(target *Object) *Object { 51 return prototype 52 }, 53 }) 54 runtime.Set("proxy", proxy) 55 56 runtime.testScriptWithTestLib(SCRIPT, _undefined, t) 57 } 58 59 func TestProxy_Object_target_setPrototypeOf(t *testing.T) { 60 const SCRIPT = ` 61 var proto = {}; 62 var obj = {}; 63 Object.setPrototypeOf(obj, proto); 64 var proxy = new Proxy(obj, {}); 65 var p = Object.getPrototypeOf(proxy); 66 assert.sameValue(proto, p); 67 ` 68 69 testScriptWithTestLib(SCRIPT, _undefined, t) 70 } 71 72 func TestProxy_Object_proxy_setPrototypeOf(t *testing.T) { 73 const SCRIPT = ` 74 var proto = {}; 75 var proto2 = {}; 76 var obj = {}; 77 Object.setPrototypeOf(obj, proto); 78 var proxy = new Proxy(obj, { 79 setPrototypeOf: function(target, prototype) { 80 return Object.setPrototypeOf(target, proto2); 81 } 82 }); 83 Object.setPrototypeOf(proxy, null); 84 var p = Object.getPrototypeOf(proxy); 85 assert.sameValue(proto2, p); 86 ` 87 88 testScriptWithTestLib(SCRIPT, _undefined, t) 89 } 90 91 func TestProxy_Object_target_isExtensible(t *testing.T) { 92 const SCRIPT = ` 93 var obj = {}; 94 Object.seal(obj); 95 var proxy = new Proxy(obj, {}); 96 Object.isExtensible(proxy); 97 ` 98 99 testScript(SCRIPT, valueFalse, t) 100 } 101 102 func TestProxy_proxy_isExtensible(t *testing.T) { 103 const SCRIPT = ` 104 var obj = {}; 105 Object.seal(obj); 106 var proxy = new Proxy(obj, { 107 isExtensible: function(target) { 108 return false; 109 } 110 }); 111 Object.isExtensible(proxy); 112 ` 113 114 testScript(SCRIPT, valueFalse, t) 115 } 116 117 func TestProxy_native_proxy_isExtensible(t *testing.T) { 118 const SCRIPT = ` 119 (function() { 120 Object.preventExtensions(target); 121 return Object.isExtensible(proxy); 122 })(); 123 ` 124 125 runtime := New() 126 127 target := runtime.NewObject() 128 runtime.Set("target", target) 129 130 proxy := runtime.NewProxy(target, &ProxyTrapConfig{ 131 IsExtensible: func(target *Object) (success bool) { 132 return false 133 }, 134 }) 135 runtime.Set("proxy", proxy) 136 137 val, err := runtime.RunString(SCRIPT) 138 if err != nil { 139 t.Fatal(err) 140 } 141 if val.ToBoolean() { 142 t.Fatal() 143 } 144 } 145 146 func TestProxy_Object_target_preventExtensions(t *testing.T) { 147 const SCRIPT = ` 148 var obj = { 149 canEvolve: true 150 }; 151 var proxy = new Proxy(obj, {}); 152 Object.preventExtensions(proxy); 153 proxy.canEvolve 154 ` 155 156 testScript(SCRIPT, valueTrue, t) 157 } 158 159 func TestProxy_proxy_preventExtensions(t *testing.T) { 160 const SCRIPT = ` 161 var obj = { 162 canEvolve: true 163 }; 164 var proxy = new Proxy(obj, { 165 preventExtensions: function(target) { 166 target.canEvolve = false; 167 Object.preventExtensions(obj); 168 return true; 169 } 170 }); 171 Object.preventExtensions(proxy); 172 proxy.canEvolve; 173 ` 174 175 testScript(SCRIPT, valueFalse, t) 176 } 177 178 func TestProxy_native_proxy_preventExtensions(t *testing.T) { 179 const SCRIPT = ` 180 (function() { 181 Object.preventExtensions(proxy); 182 return proxy.canEvolve; 183 })(); 184 ` 185 186 runtime := New() 187 188 target := runtime.NewObject() 189 target.Set("canEvolve", true) 190 runtime.Set("target", target) 191 192 proxy := runtime.NewProxy(target, &ProxyTrapConfig{ 193 PreventExtensions: func(target *Object) (success bool) { 194 target.Set("canEvolve", false) 195 _, err := runtime.RunString("Object.preventExtensions(target)") 196 if err != nil { 197 panic(err) 198 } 199 return true 200 }, 201 }) 202 runtime.Set("proxy", proxy) 203 204 val, err := runtime.RunString(SCRIPT) 205 if err != nil { 206 t.Fatal(err) 207 } 208 if val.ToBoolean() { 209 t.Fatal() 210 } 211 } 212 213 func TestProxy_Object_target_getOwnPropertyDescriptor(t *testing.T) { 214 const SCRIPT = ` 215 var desc = { 216 configurable: false, 217 enumerable: false, 218 value: 42, 219 writable: false 220 }; 221 222 var obj = {}; 223 Object.defineProperty(obj, "foo", desc); 224 225 var proxy = new Proxy(obj, {}); 226 227 var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo"); 228 desc2.value 229 ` 230 231 testScript(SCRIPT, valueInt(42), t) 232 } 233 234 func TestProxy_proxy_getOwnPropertyDescriptor(t *testing.T) { 235 const SCRIPT = ` 236 var desc = { 237 configurable: false, 238 enumerable: false, 239 value: 42, 240 writable: false 241 }; 242 var proxy_desc = { 243 configurable: false, 244 enumerable: false, 245 value: 24, 246 writable: false 247 }; 248 249 var obj = {}; 250 Object.defineProperty(obj, "foo", desc); 251 252 var proxy = new Proxy(obj, { 253 getOwnPropertyDescriptor: function(target, property) { 254 return proxy_desc; 255 } 256 }); 257 258 assert.throws(TypeError, function() { 259 Object.getOwnPropertyDescriptor(proxy, "foo"); 260 }); 261 undefined; 262 ` 263 264 testScriptWithTestLib(SCRIPT, _undefined, t) 265 } 266 267 func TestProxy_native_proxy_getOwnPropertyDescriptor(t *testing.T) { 268 const SCRIPT = ` 269 (function() { 270 var desc = { 271 configurable: true, 272 enumerable: false, 273 value: 42, 274 writable: false 275 }; 276 var proxy_desc = { 277 configurable: true, 278 enumerable: false, 279 value: 24, 280 writable: false 281 }; 282 283 var obj = {}; 284 Object.defineProperty(obj, "foo", desc); 285 286 return function(constructor) { 287 var proxy = constructor(obj, proxy_desc); 288 289 var desc2 = Object.getOwnPropertyDescriptor(proxy, "foo"); 290 return desc2.value 291 } 292 })(); 293 ` 294 295 runtime := New() 296 297 constructor := func(call FunctionCall) Value { 298 target := call.Argument(0).(*Object) 299 proxyDesc := call.Argument(1).(*Object) 300 301 return runtime.NewProxy(target, &ProxyTrapConfig{ 302 GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { 303 return runtime.toPropertyDescriptor(proxyDesc) 304 }, 305 }).proxy.val 306 } 307 308 val, err := runtime.RunString(SCRIPT) 309 if err != nil { 310 t.Fatal(err) 311 } 312 313 if c, ok := val.(*Object).self.assertCallable(); ok { 314 val := c(FunctionCall{ 315 This: val, 316 Arguments: []Value{runtime.ToValue(constructor)}, 317 }) 318 if i := val.ToInteger(); i != 24 { 319 t.Fatalf("val: %d", i) 320 } 321 } else { 322 t.Fatal("not a function") 323 } 324 } 325 326 func TestProxy_native_proxy_getOwnPropertyDescriptorIdx(t *testing.T) { 327 vm := New() 328 a := vm.NewArray() 329 proxy1 := vm.NewProxy(a, &ProxyTrapConfig{ 330 GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { 331 panic(vm.NewTypeError("GetOwnPropertyDescriptor was called for %q", prop)) 332 }, 333 GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor { 334 if prop >= -1 && prop <= 1 { 335 return PropertyDescriptor{ 336 Value: vm.ToValue(prop), 337 Configurable: FLAG_TRUE, 338 } 339 } 340 return PropertyDescriptor{} 341 }, 342 }) 343 344 proxy2 := vm.NewProxy(a, &ProxyTrapConfig{ 345 GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { 346 switch prop { 347 case "-1", "0", "1": 348 return PropertyDescriptor{ 349 Value: vm.ToValue(prop), 350 Configurable: FLAG_TRUE, 351 } 352 } 353 return PropertyDescriptor{} 354 }, 355 }) 356 357 proxy3 := vm.NewProxy(a, &ProxyTrapConfig{ 358 GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { 359 return PropertyDescriptor{ 360 Value: vm.ToValue(prop), 361 Configurable: FLAG_TRUE, 362 } 363 }, 364 GetOwnPropertyDescriptorIdx: func(target *Object, prop int) PropertyDescriptor { 365 panic(vm.NewTypeError("GetOwnPropertyDescriptorIdx was called for %d", prop)) 366 }, 367 }) 368 369 vm.Set("proxy1", proxy1) 370 vm.Set("proxy2", proxy2) 371 vm.Set("proxy3", proxy3) 372 vm.testScriptWithTestLibX(` 373 var desc; 374 for (var i = -1; i <= 1; i++) { 375 desc = Object.getOwnPropertyDescriptor(proxy1, i); 376 assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. int "+i); 377 378 desc = Object.getOwnPropertyDescriptor(proxy1, ""+i); 379 assert(deepEqual(desc, {value: i, writable: false, enumerable: false, configurable: true}), "1. str "+i); 380 381 desc = Object.getOwnPropertyDescriptor(proxy2, i); 382 assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. int "+i); 383 384 desc = Object.getOwnPropertyDescriptor(proxy2, ""+i); 385 assert(deepEqual(desc, {value: ""+i, writable: false, enumerable: false, configurable: true}), "2. str "+i); 386 } 387 388 for (const prop of ["00", " 0", "-0", "01"]) { 389 desc = Object.getOwnPropertyDescriptor(proxy3, prop); 390 assert(deepEqual(desc, {value: prop, writable: false, enumerable: false, configurable: true}), "3. "+prop); 391 } 392 `, _undefined, t) 393 } 394 395 func TestProxy_native_proxy_getOwnPropertyDescriptorSym(t *testing.T) { 396 vm := New() 397 o := vm.NewObject() 398 sym := NewSymbol("42") 399 vm.Set("sym", sym) 400 proxy := vm.NewProxy(o, &ProxyTrapConfig{ 401 GetOwnPropertyDescriptorSym: func(target *Object, s *Symbol) PropertyDescriptor { 402 if target != o { 403 panic(vm.NewTypeError("Invalid target")) 404 } 405 if s == sym { 406 return PropertyDescriptor{ 407 Value: vm.ToValue("passed"), 408 Writable: FLAG_TRUE, 409 Configurable: FLAG_TRUE, 410 } 411 } 412 return PropertyDescriptor{} 413 }, 414 }) 415 416 vm.Set("proxy", proxy) 417 vm.testScriptWithTestLibX(` 418 var desc = Object.getOwnPropertyDescriptor(proxy, sym); 419 assert(deepEqual(desc, {value: "passed", writable: true, enumerable: false, configurable: true})); 420 assert.sameValue(Object.getOwnPropertyDescriptor(proxy, Symbol.iterator), undefined); 421 `, _undefined, t) 422 } 423 424 func TestProxy_native_proxy_getOwnPropertyDescriptor_non_existing(t *testing.T) { 425 vm := New() 426 proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{ 427 GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) { 428 return // empty PropertyDescriptor 429 }, 430 }) 431 vm.Set("proxy", proxy) 432 res, err := vm.RunString(`Object.getOwnPropertyDescriptor(proxy, "foo") === undefined`) 433 if err != nil { 434 t.Fatal(err) 435 } 436 if res != valueTrue { 437 t.Fatal(res) 438 } 439 } 440 441 func TestProxy_Object_target_defineProperty(t *testing.T) { 442 const SCRIPT = ` 443 var obj = {}; 444 var proxy = new Proxy(obj, {}); 445 Object.defineProperty(proxy, "foo", { 446 value: "test123" 447 }); 448 proxy.foo; 449 ` 450 451 testScript(SCRIPT, asciiString("test123"), t) 452 } 453 454 func TestProxy_proxy_defineProperty(t *testing.T) { 455 const SCRIPT = ` 456 var obj = {}; 457 var proxy = new Proxy(obj, { 458 defineProperty: function(target, prop, descriptor) { 459 target.foo = "321tset"; 460 return true; 461 } 462 }); 463 Object.defineProperty(proxy, "foo", { 464 value: "test123" 465 }); 466 proxy.foo; 467 ` 468 469 testScript(SCRIPT, asciiString("321tset"), t) 470 } 471 472 func TestProxy_native_proxy_defineProperty(t *testing.T) { 473 const SCRIPT = ` 474 Object.defineProperty(proxy, "foo", { 475 value: "teststr" 476 }); 477 Object.defineProperty(proxy, "0", { 478 value: "testidx" 479 }); 480 Object.defineProperty(proxy, Symbol.toStringTag, { 481 value: "testsym" 482 }); 483 assert.sameValue(proxy.foo, "teststr-passed-str"); 484 assert.sameValue(proxy[0], "testidx-passed-idx"); 485 assert.sameValue(proxy[Symbol.toStringTag], "testsym-passed-sym"); 486 ` 487 488 runtime := New() 489 490 target := runtime.NewObject() 491 492 proxy := runtime.NewProxy(target, &ProxyTrapConfig{ 493 DefineProperty: func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool) { 494 target.Set(key, propertyDescriptor.Value.String()+"-passed-str") 495 return true 496 }, 497 DefinePropertyIdx: func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool) { 498 target.Set(strconv.Itoa(key), propertyDescriptor.Value.String()+"-passed-idx") 499 return true 500 }, 501 DefinePropertySym: func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool) { 502 target.SetSymbol(key, propertyDescriptor.Value.String()+"-passed-sym") 503 return true 504 }, 505 }) 506 runtime.Set("proxy", proxy) 507 508 runtime.testScriptWithTestLib(SCRIPT, _undefined, t) 509 } 510 511 func TestProxy_target_has_in(t *testing.T) { 512 const SCRIPT = ` 513 var obj = { 514 secret: true 515 }; 516 var proxy = new Proxy(obj, {}); 517 518 "secret" in proxy 519 ` 520 521 testScript(SCRIPT, valueTrue, t) 522 } 523 524 func TestProxy_proxy_has_in(t *testing.T) { 525 const SCRIPT = ` 526 var obj = { 527 secret: true 528 }; 529 var proxy = new Proxy(obj, { 530 has: function(target, key) { 531 return key !== "secret"; 532 } 533 }); 534 535 "secret" in proxy 536 ` 537 538 testScript(SCRIPT, valueFalse, t) 539 } 540 541 func TestProxy_target_has_with(t *testing.T) { 542 const SCRIPT = ` 543 var obj = { 544 secret: true 545 }; 546 var proxy = new Proxy(obj, {}); 547 548 with(proxy) { 549 (secret); 550 } 551 ` 552 553 testScript(SCRIPT, valueTrue, t) 554 } 555 556 func TestProxy_proxy_has_with(t *testing.T) { 557 const SCRIPT = ` 558 var obj = { 559 secret: true 560 }; 561 var proxy = new Proxy(obj, { 562 has: function(target, key) { 563 return key !== "secret"; 564 } 565 }); 566 567 var thrown = false; 568 try { 569 with(proxy) { 570 (secret); 571 } 572 } catch (e) { 573 if (e instanceof ReferenceError) { 574 thrown = true; 575 } else { 576 throw e; 577 } 578 } 579 thrown; 580 ` 581 582 testScript(SCRIPT, valueTrue, t) 583 } 584 585 func TestProxy_target_get(t *testing.T) { 586 const SCRIPT = ` 587 var obj = {}; 588 var proxy = new Proxy(obj, {}); 589 Object.defineProperty(proxy, "foo", { 590 value: "test123" 591 }); 592 proxy.foo; 593 ` 594 595 testScript(SCRIPT, asciiString("test123"), t) 596 } 597 598 func TestProxy_proxy_get(t *testing.T) { 599 const SCRIPT = ` 600 var obj = {}; 601 var proxy = new Proxy(obj, { 602 get: function(target, prop, receiver) { 603 return "321tset" 604 } 605 }); 606 Object.defineProperty(proxy, "foo", { 607 value: "test123", 608 configurable: true, 609 }); 610 proxy.foo; 611 ` 612 613 testScript(SCRIPT, asciiString("321tset"), t) 614 } 615 616 func TestProxy_proxy_get_json_stringify(t *testing.T) { 617 const SCRIPT = ` 618 var obj = {}; 619 var propValue = "321tset"; 620 var _handler, _target, _prop, _receiver; 621 var proxy = new Proxy(obj, { 622 ownKeys: function() { 623 return ["foo"]; 624 }, 625 getOwnPropertyDescriptor: function(target, prop) { 626 if (prop === "foo") { 627 return { 628 value: propValue, 629 enumerable: true, 630 configurable: true 631 } 632 } 633 }, 634 get: function(target, prop, receiver) { 635 if (prop === "foo") { 636 _prop = prop; 637 _receiver = receiver; 638 return propValue; 639 } 640 return obj[prop]; 641 } 642 }); 643 var res = JSON.stringify(proxy); 644 assert.sameValue(res, '{"foo":"321tset"}'); 645 assert.sameValue(_prop, "foo"); 646 assert.sameValue(_receiver, proxy); 647 ` 648 649 testScriptWithTestLib(SCRIPT, _undefined, t) 650 } 651 652 func TestProxy_native_proxy_get(t *testing.T) { 653 vm := New() 654 propValueStr := vm.ToValue("321tset") 655 propValueIdx := vm.ToValue("idx") 656 propValueSym := vm.ToValue("sym") 657 sym := NewSymbol("test") 658 obj := vm.NewObject() 659 proxy := vm.NewProxy(obj, &ProxyTrapConfig{ 660 OwnKeys: func(*Object) *Object { 661 return vm.NewArray("0", "foo") 662 }, 663 GetOwnPropertyDescriptor: func(target *Object, prop string) (propertyDescriptor PropertyDescriptor) { 664 if prop == "foo" { 665 return PropertyDescriptor{ 666 Value: propValueStr, 667 Enumerable: FLAG_TRUE, 668 Configurable: FLAG_TRUE, 669 } 670 } 671 if prop == "0" { 672 panic(vm.NewTypeError("GetOwnPropertyDescriptor(0) was called")) 673 } 674 return 675 }, 676 GetOwnPropertyDescriptorIdx: func(target *Object, prop int) (propertyDescriptor PropertyDescriptor) { 677 if prop == 0 { 678 return PropertyDescriptor{ 679 Value: propValueIdx, 680 Enumerable: FLAG_TRUE, 681 Configurable: FLAG_TRUE, 682 } 683 } 684 return 685 }, 686 Get: func(target *Object, property string, receiver Value) (value Value) { 687 if property == "foo" { 688 return propValueStr 689 } 690 if property == "0" { 691 panic(vm.NewTypeError("Get(0) was called")) 692 } 693 return obj.Get(property) 694 }, 695 GetIdx: func(target *Object, property int, receiver Value) (value Value) { 696 if property == 0 { 697 return propValueIdx 698 } 699 return obj.Get(strconv.Itoa(property)) 700 }, 701 GetSym: func(target *Object, property *Symbol, receiver Value) (value Value) { 702 if property == sym { 703 return propValueSym 704 } 705 return obj.GetSymbol(property) 706 }, 707 }) 708 vm.Set("proxy", proxy) 709 res, err := vm.RunString(`JSON.stringify(proxy)`) 710 if err != nil { 711 t.Fatal(err) 712 } 713 if !res.SameAs(asciiString(`{"0":"idx","foo":"321tset"}`)) { 714 t.Fatalf("res: %v", res) 715 } 716 res, err = vm.RunString(`proxy[Symbol.toPrimitive]`) 717 if err != nil { 718 t.Fatal(err) 719 } 720 if !IsUndefined(res) { 721 t.Fatalf("res: %v", res) 722 } 723 724 res, err = vm.RunString(`proxy.hasOwnProperty(Symbol.toPrimitive)`) 725 if err != nil { 726 t.Fatal(err) 727 } 728 if !res.SameAs(valueFalse) { 729 t.Fatalf("res: %v", res) 730 } 731 732 if val := vm.ToValue(proxy).(*Object).GetSymbol(sym); val == nil || !val.SameAs(propValueSym) { 733 t.Fatalf("Get(symbol): %v", val) 734 } 735 736 res, err = vm.RunString(`proxy.toString()`) 737 if err != nil { 738 t.Fatal(err) 739 } 740 if !res.SameAs(asciiString(`[object Object]`)) { 741 t.Fatalf("res: %v", res) 742 } 743 } 744 745 func TestProxy_native_proxy_set(t *testing.T) { 746 vm := New() 747 propValueStr := vm.ToValue("321tset") 748 propValueIdx := vm.ToValue("idx") 749 propValueSym := vm.ToValue("sym") 750 sym := NewSymbol("test") 751 obj := vm.NewObject() 752 proxy := vm.NewProxy(obj, &ProxyTrapConfig{ 753 Set: func(target *Object, property string, value Value, receiver Value) (success bool) { 754 if property == "str" { 755 obj.Set(property, propValueStr) 756 return true 757 } 758 panic(vm.NewTypeError("Setter for unexpected property: %q", property)) 759 }, 760 SetIdx: func(target *Object, property int, value Value, receiver Value) (success bool) { 761 if property == 0 { 762 obj.Set(strconv.Itoa(property), propValueIdx) 763 return true 764 } 765 panic(vm.NewTypeError("Setter for unexpected idx property: %d", property)) 766 }, 767 SetSym: func(target *Object, property *Symbol, value Value, receiver Value) (success bool) { 768 if property == sym { 769 obj.SetSymbol(property, propValueSym) 770 return true 771 } 772 panic(vm.NewTypeError("Setter for unexpected sym property: %q", property.String())) 773 }, 774 }) 775 proxyObj := vm.ToValue(proxy).ToObject(vm) 776 err := proxyObj.Set("str", "") 777 if err != nil { 778 t.Fatal(err) 779 } 780 err = proxyObj.Set("0", "") 781 if err != nil { 782 t.Fatal(err) 783 } 784 err = proxyObj.SetSymbol(sym, "") 785 if err != nil { 786 t.Fatal(err) 787 } 788 if v := obj.Get("str"); !propValueStr.SameAs(v) { 789 t.Fatal(v) 790 } 791 if v := obj.Get("0"); !propValueIdx.SameAs(v) { 792 t.Fatal(v) 793 } 794 if v := obj.GetSymbol(sym); !propValueSym.SameAs(v) { 795 t.Fatal(v) 796 } 797 } 798 799 func TestProxy_target_set_prop(t *testing.T) { 800 const SCRIPT = ` 801 var obj = {}; 802 var proxy = new Proxy(obj, {}); 803 proxy.foo = "test123"; 804 proxy.foo; 805 ` 806 807 testScript(SCRIPT, asciiString("test123"), t) 808 } 809 810 func TestProxy_proxy_set_prop(t *testing.T) { 811 const SCRIPT = ` 812 var obj = {}; 813 var proxy = new Proxy(obj, { 814 set: function(target, prop, receiver) { 815 target.foo = "321tset"; 816 return true; 817 } 818 }); 819 proxy.foo = "test123"; 820 proxy.foo; 821 ` 822 823 testScript(SCRIPT, asciiString("321tset"), t) 824 } 825 func TestProxy_target_set_associative(t *testing.T) { 826 const SCRIPT = ` 827 var obj = {}; 828 var proxy = new Proxy(obj, {}); 829 proxy["foo"] = "test123"; 830 proxy.foo; 831 ` 832 833 testScript(SCRIPT, asciiString("test123"), t) 834 } 835 836 func TestProxy_proxy_set_associative(t *testing.T) { 837 const SCRIPT = ` 838 var obj = {}; 839 var proxy = new Proxy(obj, { 840 set: function(target, property, value, receiver) { 841 target["foo"] = "321tset"; 842 return true; 843 } 844 }); 845 proxy["foo"] = "test123"; 846 proxy.foo; 847 ` 848 849 testScript(SCRIPT, asciiString("321tset"), t) 850 } 851 852 func TestProxy_target_delete(t *testing.T) { 853 const SCRIPT = ` 854 var obj = { 855 foo: "test" 856 }; 857 var proxy = new Proxy(obj, {}); 858 delete proxy.foo; 859 860 proxy.foo; 861 ` 862 863 testScript(SCRIPT, _undefined, t) 864 } 865 866 func TestProxy_proxy_delete(t *testing.T) { 867 const SCRIPT = ` 868 var obj = { 869 foo: "test" 870 }; 871 var proxy = new Proxy(obj, { 872 deleteProperty: function(target, prop) { 873 return true; 874 } 875 }); 876 delete proxy.foo; 877 878 proxy.foo; 879 ` 880 881 testScript(SCRIPT, asciiString("test"), t) 882 } 883 884 func TestProxy_native_delete(t *testing.T) { 885 vm := New() 886 sym := NewSymbol("test") 887 obj := vm.NewObject() 888 var strCalled, idxCalled, symCalled, strNegCalled, idxNegCalled, symNegCalled bool 889 proxy := vm.NewProxy(obj, &ProxyTrapConfig{ 890 DeleteProperty: func(target *Object, property string) (success bool) { 891 if property == "str" { 892 strCalled = true 893 return true 894 } 895 if property == "strNeg" { 896 strNegCalled = true 897 return false 898 } 899 panic(vm.NewTypeError("DeleteProperty for unexpected property: %q", property)) 900 }, 901 DeletePropertyIdx: func(target *Object, property int) (success bool) { 902 if property == 0 { 903 idxCalled = true 904 return true 905 } 906 if property == 1 { 907 idxNegCalled = true 908 return false 909 } 910 panic(vm.NewTypeError("DeletePropertyIdx for unexpected idx property: %d", property)) 911 }, 912 DeletePropertySym: func(target *Object, property *Symbol) (success bool) { 913 if property == sym { 914 symCalled = true 915 return true 916 } 917 if property == SymIterator { 918 symNegCalled = true 919 return false 920 } 921 panic(vm.NewTypeError("DeletePropertySym for unexpected sym property: %q", property.String())) 922 }, 923 }) 924 proxyObj := vm.ToValue(proxy).ToObject(vm) 925 err := proxyObj.Delete("str") 926 if err != nil { 927 t.Fatal(err) 928 } 929 err = proxyObj.Delete("0") 930 if err != nil { 931 t.Fatal(err) 932 } 933 err = proxyObj.DeleteSymbol(sym) 934 if err != nil { 935 t.Fatal(err) 936 } 937 if !strCalled { 938 t.Fatal("str") 939 } 940 if !idxCalled { 941 t.Fatal("idx") 942 } 943 if !symCalled { 944 t.Fatal("sym") 945 } 946 vm.Set("proxy", proxy) 947 _, err = vm.RunString(` 948 if (delete proxy.strNeg) { 949 throw new Error("strNeg"); 950 } 951 if (delete proxy[1]) { 952 throw new Error("idxNeg"); 953 } 954 if (delete proxy[Symbol.iterator]) { 955 throw new Error("symNeg"); 956 } 957 `) 958 if err != nil { 959 t.Fatal(err) 960 } 961 if !strNegCalled { 962 t.Fatal("strNeg") 963 } 964 if !idxNegCalled { 965 t.Fatal("idxNeg") 966 } 967 if !symNegCalled { 968 t.Fatal("symNeg") 969 } 970 } 971 972 func TestProxy_target_keys(t *testing.T) { 973 const SCRIPT = ` 974 var obj = { 975 foo: "test" 976 }; 977 var proxy = new Proxy(obj, {}); 978 979 var keys = Object.keys(proxy); 980 if (keys.length != 1) { 981 throw new Error("assertion error"); 982 } 983 ` 984 985 testScript(SCRIPT, _undefined, t) 986 } 987 988 func TestProxy_proxy_keys(t *testing.T) { 989 const SCRIPT = ` 990 var obj = { 991 foo: "test" 992 }; 993 var proxy = new Proxy(obj, { 994 ownKeys: function(target) { 995 return ["foo", "bar"]; 996 } 997 }); 998 999 var keys = Object.keys(proxy); 1000 if (keys.length !== 1) { 1001 throw new Error("length is "+keys.length); 1002 } 1003 if (keys[0] !== "foo") { 1004 throw new Error("keys[0] is "+keys[0]); 1005 } 1006 ` 1007 1008 testScript(SCRIPT, _undefined, t) 1009 } 1010 1011 func TestProxy_target_call(t *testing.T) { 1012 const SCRIPT = ` 1013 var obj = function() { 1014 return "test" 1015 } 1016 1017 var proxy = new Proxy(obj, {}); 1018 1019 proxy(); 1020 ` 1021 1022 testScript(SCRIPT, asciiString("test"), t) 1023 } 1024 1025 func TestProxy_proxy_call(t *testing.T) { 1026 const SCRIPT = ` 1027 var obj = function() { 1028 return "test" 1029 } 1030 1031 var proxy = new Proxy(obj, { 1032 apply: function(target, thisArg, args) { 1033 return "tset" 1034 } 1035 }); 1036 1037 proxy(); 1038 ` 1039 1040 testScript(SCRIPT, asciiString("tset"), t) 1041 } 1042 1043 func TestProxy_target_func_apply(t *testing.T) { 1044 const SCRIPT = ` 1045 var obj = function() { 1046 return "test" 1047 } 1048 1049 var proxy = new Proxy(obj, {}); 1050 1051 proxy.apply(); 1052 ` 1053 1054 testScript(SCRIPT, asciiString("test"), t) 1055 } 1056 1057 func TestProxy_proxy_func_apply(t *testing.T) { 1058 const SCRIPT = ` 1059 var obj = function() { 1060 return "test" 1061 } 1062 1063 var proxy = new Proxy(obj, { 1064 apply: function(target, thisArg, args) { 1065 return "tset" 1066 } 1067 }); 1068 1069 proxy.apply(); 1070 ` 1071 1072 testScript(SCRIPT, asciiString("tset"), t) 1073 } 1074 1075 func TestProxy_target_func_call(t *testing.T) { 1076 const SCRIPT = ` 1077 var obj = function() { 1078 return "test" 1079 } 1080 1081 var proxy = new Proxy(obj, {}); 1082 1083 proxy.call(); 1084 ` 1085 1086 testScript(SCRIPT, asciiString("test"), t) 1087 } 1088 1089 func TestProxy_proxy_func_call(t *testing.T) { 1090 const SCRIPT = ` 1091 var obj = function() { 1092 return "test" 1093 } 1094 1095 var proxy = new Proxy(obj, { 1096 apply: function(target, thisArg, args) { 1097 return "tset" 1098 } 1099 }); 1100 1101 proxy.call(); 1102 ` 1103 1104 testScript(SCRIPT, asciiString("tset"), t) 1105 } 1106 1107 func TestProxy_target_new(t *testing.T) { 1108 const SCRIPT = ` 1109 var obj = function(word) { 1110 this.foo = function() { 1111 return word; 1112 } 1113 } 1114 1115 var proxy = new Proxy(obj, {}); 1116 1117 var instance = new proxy("test"); 1118 instance.foo(); 1119 ` 1120 1121 testScript(SCRIPT, asciiString("test"), t) 1122 } 1123 1124 func TestProxy_proxy_new(t *testing.T) { 1125 const SCRIPT = ` 1126 var obj = function(word) { 1127 this.foo = function() { 1128 return word; 1129 } 1130 } 1131 1132 var proxy = new Proxy(obj, { 1133 construct: function(target, args, newTarget) { 1134 var word = args[0]; 1135 return { 1136 foo: function() { 1137 return "caught-" + word 1138 } 1139 } 1140 } 1141 }); 1142 1143 var instance = new proxy("test"); 1144 instance.foo(); 1145 ` 1146 1147 testScript(SCRIPT, asciiString("caught-test"), t) 1148 } 1149 1150 func TestProxy_Object_native_proxy_ownKeys(t *testing.T) { 1151 headers := map[string][]string{ 1152 "k0": {}, 1153 } 1154 vm := New() 1155 proxy := vm.NewProxy(vm.NewObject(), &ProxyTrapConfig{ 1156 OwnKeys: func(target *Object) (object *Object) { 1157 keys := make([]interface{}, 0, len(headers)) 1158 for k := range headers { 1159 keys = append(keys, k) 1160 } 1161 return vm.ToValue(keys).ToObject(vm) 1162 }, 1163 GetOwnPropertyDescriptor: func(target *Object, prop string) PropertyDescriptor { 1164 v, exists := headers[prop] 1165 if exists { 1166 return PropertyDescriptor{ 1167 Value: vm.ToValue(v), 1168 Enumerable: FLAG_TRUE, 1169 Configurable: FLAG_TRUE, 1170 } 1171 } 1172 return PropertyDescriptor{} 1173 }, 1174 }) 1175 vm.Set("headers", proxy) 1176 v, err := vm.RunString(` 1177 var keys = Object.keys(headers); 1178 keys.length === 1 && keys[0] === "k0"; 1179 `) 1180 if err != nil { 1181 t.Fatal(err) 1182 } 1183 if v != valueTrue { 1184 t.Fatal("not true", v) 1185 } 1186 } 1187 1188 func TestProxy_proxy_forIn(t *testing.T) { 1189 const SCRIPT = ` 1190 var proto = { 1191 a: 2, 1192 protoProp: 1 1193 } 1194 Object.defineProperty(proto, "protoNonEnum", { 1195 value: 2, 1196 writable: true, 1197 configurable: true 1198 }); 1199 var target = Object.create(proto); 1200 var proxy = new Proxy(target, { 1201 ownKeys: function() { 1202 return ["a", "b"]; 1203 }, 1204 getOwnPropertyDescriptor: function(target, p) { 1205 switch (p) { 1206 case "a": 1207 case "b": 1208 return { 1209 value: 42, 1210 enumerable: true, 1211 configurable: true 1212 } 1213 } 1214 }, 1215 }); 1216 1217 var forInResult = []; 1218 for (var key in proxy) { 1219 if (forInResult.indexOf(key) !== -1) { 1220 throw new Error("Duplicate property "+key); 1221 } 1222 forInResult.push(key); 1223 } 1224 forInResult.length === 3 && forInResult[0] === "a" && forInResult[1] === "b" && forInResult[2] === "protoProp"; 1225 ` 1226 1227 testScript(SCRIPT, valueTrue, t) 1228 } 1229 1230 func TestProxyExport(t *testing.T) { 1231 vm := New() 1232 v, err := vm.RunString(` 1233 new Proxy({}, {}); 1234 `) 1235 if err != nil { 1236 t.Fatal(err) 1237 } 1238 v1 := v.Export() 1239 if _, ok := v1.(Proxy); !ok { 1240 t.Fatalf("Export returned unexpected type: %T", v1) 1241 } 1242 } 1243 1244 func TestProxy_proxy_createTargetNotCallable(t *testing.T) { 1245 // from https://github.com/tc39/test262/blob/main/test/built-ins/Proxy/create-target-is-not-callable.js 1246 const SCRIPT = ` 1247 var p = new Proxy({}, {}); 1248 1249 assert.throws(TypeError, function() { 1250 p(); 1251 }); 1252 ` 1253 1254 testScriptWithTestLib(SCRIPT, _undefined, t) 1255 } 1256 1257 func TestProxyEnumerableSymbols(t *testing.T) { 1258 const SCRIPT = ` 1259 var getOwnKeys = []; 1260 var ownKeysResult = [Symbol(), "foo", "0"]; 1261 var proxy = new Proxy({}, { 1262 getOwnPropertyDescriptor: function(_target, key) { 1263 getOwnKeys.push(key); 1264 }, 1265 ownKeys: function() { 1266 return ownKeysResult; 1267 }, 1268 }); 1269 1270 let {...$} = proxy; 1271 compareArray(getOwnKeys, ownKeysResult); 1272 ` 1273 1274 testScriptWithTestLib(SCRIPT, valueTrue, t) 1275 }