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
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
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 }
1276
View as plain text