proxies.js revision 589d6979ff2ef66fca2d8fa51404c369ca5e9250
1// Copyright 2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28// Flags: --harmony-proxies
29
30
31// TODO(rossberg): for-in for proxies not implemented.
32// TODO(rossberg): inheritance from proxies not implemented.
33// TODO(rossberg): function proxies as constructors not implemented.
34
35
36// Helper.
37
38function TestWithProxies(test, handler) {
39  test(handler, Proxy.create)
40  test(handler, function(h) {return Proxy.createFunction(h, function() {})})
41}
42
43
44// Getters.
45
46function TestGet(handler) {
47  TestWithProxies(TestGet2, handler)
48}
49
50function TestGet2(handler, create) {
51  var p = create(handler)
52  assertEquals(42, p.a)
53  assertEquals(42, p["b"])
54
55  // TODO(rossberg): inheritance from proxies not yet implemented.
56  // var o = Object.create(p, {x: {value: 88}})
57  // assertEquals(42, o.a)
58  // assertEquals(42, o["b"])
59  // assertEquals(88, o.x)
60  // assertEquals(88, o["x"])
61}
62
63TestGet({
64  get: function(r, k) { return 42 }
65})
66
67TestGet({
68  get: function(r, k) { return this.get2(r, k) },
69  get2: function(r, k) { return 42 }
70})
71
72TestGet({
73  getPropertyDescriptor: function(k) { return {value: 42} }
74})
75
76TestGet({
77  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
78  getPropertyDescriptor2: function(k) { return {value: 42} }
79})
80
81TestGet({
82  getPropertyDescriptor: function(k) {
83    return {get value() { return 42 }}
84  }
85})
86
87TestGet({
88  get: undefined,
89  getPropertyDescriptor: function(k) { return {value: 42} }
90})
91
92TestGet(Proxy.create({
93  get: function(pr, pk) {
94    return function(r, k) { return 42 }
95  }
96}))
97
98
99function TestGetCall(handler) {
100  TestWithProxies(TestGetCall2, handler)
101}
102
103function TestGetCall2(handler, create) {
104  var p = create(handler)
105  assertEquals(55, p.f())
106  assertEquals(55, p.f("unused", "arguments"))
107  assertEquals(55, p.f.call(p))
108  assertEquals(55, p.withargs(45, 5))
109  assertEquals(55, p.withargs.call(p, 11, 22))
110  assertEquals("6655", "66" + p)  // calls p.toString
111}
112
113TestGetCall({
114  get: function(r, k) { return function() { return 55 } }
115})
116
117TestGetCall({
118  get: function(r, k) { return this.get2(r, k) },
119  get2: function(r, k) { return function() { return 55 } }
120})
121
122TestGetCall({
123  getPropertyDescriptor: function(k) {
124    return {value: function() { return 55 }}
125  }
126})
127
128TestGetCall({
129  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
130  getPropertyDescriptor2: function(k) {
131    return {value: function() { return 55 }}
132  }
133})
134
135TestGetCall({
136  getPropertyDescriptor: function(k) {
137    return {get value() { return function() { return 55 } }}
138  }
139})
140
141TestGetCall({
142  get: undefined,
143  getPropertyDescriptor: function(k) {
144    return {value: function() { return 55 }}
145  }
146})
147
148TestGetCall({
149  get: function(r, k) {
150    if (k == "gg") {
151      return function() { return 55 }
152    } else if (k == "withargs") {
153      return function(n, m) { return n + m * 2 }
154    } else {
155      return function() { return this.gg() }
156    }
157  }
158})
159
160TestGetCall(Proxy.create({
161  get: function(pr, pk) {
162    return function(r, k) { return function() { return 55 } }
163  }
164}))
165
166
167function TestGetThrow(handler) {
168  TestWithProxies(TestGetThrow2, handler)
169}
170
171function TestGetThrow2(handler, create) {
172  var p = create(handler)
173  assertThrows(function(){ p.a }, "myexn")
174  assertThrows(function(){ p["b"] }, "myexn")
175}
176
177TestGetThrow({
178  get: function(r, k) { throw "myexn" }
179})
180
181TestGetThrow({
182  get: function(r, k) { return this.get2(r, k) },
183  get2: function(r, k) { throw "myexn" }
184})
185
186TestGetThrow({
187  getPropertyDescriptor: function(k) { throw "myexn" }
188})
189
190TestGetThrow({
191  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
192  getPropertyDescriptor2: function(k) { throw "myexn" }
193})
194
195TestGetThrow({
196  getPropertyDescriptor: function(k) {
197    return {get value() { throw "myexn" }}
198  }
199})
200
201TestGetThrow({
202  get: undefined,
203  getPropertyDescriptor: function(k) { throw "myexn" }
204})
205
206TestGetThrow(Proxy.create({
207  get: function(pr, pk) { throw "myexn" }
208}))
209
210TestGetThrow(Proxy.create({
211  get: function(pr, pk) {
212    return function(r, k) { throw "myexn" }
213  }
214}))
215
216
217
218// Setters.
219
220var key
221var val
222
223function TestSet(handler, create) {
224  TestWithProxies(TestSet2, handler)
225}
226
227function TestSet2(handler, create) {
228  var p = create(handler)
229  assertEquals(42, p.a = 42)
230  assertEquals("a", key)
231  assertEquals(42, val)
232  assertEquals(43, p["b"] = 43)
233  assertEquals("b", key)
234  assertEquals(43, val)
235}
236
237TestSet({
238  set: function(r, k, v) { key = k; val = v; return true }
239})
240
241TestSet({
242  set: function(r, k, v) { return this.set2(r, k, v) },
243  set2: function(r, k, v) { key = k; val = v; return true }
244})
245
246TestSet({
247  getOwnPropertyDescriptor: function(k) { return {writable: true} },
248  defineProperty: function(k, desc) { key = k; val = desc.value }
249})
250
251TestSet({
252  getOwnPropertyDescriptor: function(k) {
253    return this.getOwnPropertyDescriptor2(k)
254  },
255  getOwnPropertyDescriptor2: function(k) { return {writable: true} },
256  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
257  defineProperty2: function(k, desc) { key = k; val = desc.value }
258})
259
260TestSet({
261  getOwnPropertyDescriptor: function(k) {
262    return {get writable() { return true }}
263  },
264  defineProperty: function(k, desc) { key = k; val = desc.value }
265})
266
267TestSet({
268  getOwnPropertyDescriptor: function(k) {
269    return {set: function(v) { key = k; val = v }}
270  }
271})
272
273TestSet({
274  getOwnPropertyDescriptor: function(k) { return null },
275  getPropertyDescriptor: function(k) { return {writable: true} },
276  defineProperty: function(k, desc) { key = k; val = desc.value }
277})
278
279TestSet({
280  getOwnPropertyDescriptor: function(k) { return null },
281  getPropertyDescriptor: function(k) {
282    return {get writable() { return true }}
283  },
284  defineProperty: function(k, desc) { key = k; val = desc.value }
285})
286
287TestSet({
288  getOwnPropertyDescriptor: function(k) { return null },
289  getPropertyDescriptor: function(k) {
290    return {set: function(v) { key = k; val = v }}
291  }
292})
293
294TestSet({
295  getOwnPropertyDescriptor: function(k) { return null },
296  getPropertyDescriptor: function(k) { return null },
297  defineProperty: function(k, desc) { key = k, val = desc.value }
298})
299
300TestSet(Proxy.create({
301  get: function(pr, pk) {
302    return function(r, k, v) { key = k; val = v; return true }
303  }
304}))
305
306
307
308function TestSetThrow(handler, create) {
309  TestWithProxies(TestSetThrow2, handler)
310}
311
312function TestSetThrow2(handler, create) {
313  var p = create(handler)
314  assertThrows(function(){ p.a = 42 }, "myexn")
315  assertThrows(function(){ p["b"] = 42 }, "myexn")
316}
317
318TestSetThrow({
319  set: function(r, k, v) { throw "myexn" }
320})
321
322TestSetThrow({
323  set: function(r, k, v) { return this.set2(r, k, v) },
324  set2: function(r, k, v) { throw "myexn" }
325})
326
327TestSetThrow({
328  getOwnPropertyDescriptor: function(k) { throw "myexn" },
329  defineProperty: function(k, desc) { key = k; val = desc.value }
330})
331
332TestSetThrow({
333  getOwnPropertyDescriptor: function(k) { return {writable: true} },
334  defineProperty: function(k, desc) { throw "myexn" }
335})
336
337TestSetThrow({
338  getOwnPropertyDescriptor: function(k) {
339    return this.getOwnPropertyDescriptor2(k)
340  },
341  getOwnPropertyDescriptor2: function(k) { throw "myexn" },
342  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
343  defineProperty2: function(k, desc) { key = k; val = desc.value }
344})
345
346TestSetThrow({
347  getOwnPropertyDescriptor: function(k) {
348    return this.getOwnPropertyDescriptor2(k)
349  },
350  getOwnPropertyDescriptor2: function(k) { return {writable: true} },
351  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
352  defineProperty2: function(k, desc) { throw "myexn" }
353})
354
355TestSetThrow({
356  getOwnPropertyDescriptor: function(k) { throw "myexn" },
357  defineProperty: function(k, desc) { key = k; val = desc.value }
358})
359
360TestSetThrow({
361  getOwnPropertyDescriptor: function(k) {
362    return {get writable() { return true }}
363  },
364  defineProperty: function(k, desc) { throw "myexn" }
365})
366
367TestSetThrow({
368  getOwnPropertyDescriptor: function(k) { throw "myexn" }
369})
370
371TestSetThrow({
372  getOwnPropertyDescriptor: function(k) {
373    return {set: function(v) { throw "myexn" }}
374  }
375})
376
377TestSetThrow({
378  getOwnPropertyDescriptor: function(k) { throw "myexn" },
379  getPropertyDescriptor: function(k) { return {writable: true} },
380  defineProperty: function(k, desc) { key = k; val = desc.value }
381})
382
383TestSetThrow({
384  getOwnPropertyDescriptor: function(k) { return null },
385  getPropertyDescriptor: function(k) { throw "myexn" },
386  defineProperty: function(k, desc) { key = k; val = desc.value }
387})
388
389TestSetThrow({
390  getOwnPropertyDescriptor: function(k) { return null },
391  getPropertyDescriptor: function(k) { return {writable: true} },
392  defineProperty: function(k, desc) { throw "myexn" }
393})
394
395TestSetThrow({
396  getOwnPropertyDescriptor: function(k) { return null },
397  getPropertyDescriptor: function(k) {
398    return {get writable() { throw "myexn" }}
399  },
400  defineProperty: function(k, desc) { key = k; val = desc.value }
401})
402
403TestSetThrow({
404  getOwnPropertyDescriptor: function(k) { return null },
405  getPropertyDescriptor: function(k) {
406    return {set: function(v) { throw "myexn" }}
407  }
408})
409
410TestSetThrow({
411  getOwnPropertyDescriptor: function(k) { return null },
412  getPropertyDescriptor: function(k) { return null },
413  defineProperty: function(k, desc) { throw "myexn" }
414})
415
416TestSetThrow(Proxy.create({
417  get: function(pr, pk) { throw "myexn" }
418}))
419
420TestSetThrow(Proxy.create({
421  get: function(pr, pk) {
422    return function(r, k, v) { throw "myexn" }
423  }
424}))
425
426
427
428// Property definition (Object.defineProperty and Object.defineProperties).
429
430var key
431var desc
432
433function TestDefine(handler) {
434  TestWithProxies(TestDefine2, handler)
435}
436
437function TestDefine2(handler, create) {
438  var p = create(handler)
439  assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
440  assertEquals("a", key)
441  assertEquals(1, Object.getOwnPropertyNames(desc).length)
442  assertEquals(44, desc.value)
443
444  assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
445  assertEquals("b", key)
446  assertEquals(2, Object.getOwnPropertyNames(desc).length)
447  assertEquals(45, desc.value)
448  assertEquals(false, desc.writable)
449
450  assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
451  assertEquals("c", key)
452  assertEquals(2, Object.getOwnPropertyNames(desc).length)
453  assertEquals(46, desc.value)
454  assertEquals(false, desc.enumerable)
455
456  var attributes = {configurable: true, mine: 66, minetoo: 23}
457  assertEquals(p, Object.defineProperty(p, "d", attributes))
458  assertEquals("d", key)
459  // Modifying the attributes object after the fact should have no effect.
460  attributes.configurable = false
461  attributes.mine = 77
462  delete attributes.minetoo
463  assertEquals(3, Object.getOwnPropertyNames(desc).length)
464  assertEquals(true, desc.configurable)
465  assertEquals(66, desc.mine)
466  assertEquals(23, desc.minetoo)
467
468  assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
469  assertEquals("e", key)
470  assertEquals(1, Object.getOwnPropertyNames(desc).length)
471  assertEquals(5, desc.get())
472
473  assertEquals(p, Object.defineProperty(p, "zzz", {}))
474  assertEquals("zzz", key)
475  assertEquals(0, Object.getOwnPropertyNames(desc).length)
476
477// TODO(rossberg): This test requires for-in on proxies.
478//  var d = create({
479//    get: function(r, k) { return (k === "value") ? 77 : void 0 },
480//    getOwnPropertyNames: function() { return ["value"] }
481//  })
482//  assertEquals(1, Object.getOwnPropertyNames(d).length)
483//  assertEquals(77, d.value)
484//  assertEquals(p, Object.defineProperty(p, "p", d))
485//  assertEquals("p", key)
486//  assertEquals(1, Object.getOwnPropertyNames(desc).length)
487//  assertEquals(77, desc.value)
488
489  var props = {
490    'bla': {},
491    blub: {get: function() { return true }},
492    '': {get value() { return 20 }},
493    last: {value: 21, configurable: true, mine: "eyes"}
494  }
495  Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
496  assertEquals(p, Object.defineProperties(p, props))
497  assertEquals("last", key)
498  assertEquals(2, Object.getOwnPropertyNames(desc).length)
499  assertEquals(21, desc.value)
500  assertEquals(true, desc.configurable)
501  assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
502
503  var props = {bla: {get value() { throw "myexn" }}}
504  assertThrows(function(){ Object.defineProperties(p, props) }, "myexn")
505}
506
507TestDefine({
508  defineProperty: function(k, d) { key = k; desc = d; return true }
509})
510
511TestDefine({
512  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
513  defineProperty2: function(k, d) { key = k; desc = d; return true }
514})
515
516TestDefine(Proxy.create({
517  get: function(pr, pk) {
518    return function(k, d) { key = k; desc = d; return true }
519  }
520}))
521
522
523function TestDefineThrow(handler) {
524  TestWithProxies(TestDefineThrow2, handler)
525}
526
527function TestDefineThrow2(handler, create) {
528  var p = create(handler)
529  assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
530
531// TODO(rossberg): These tests require for-in on proxies.
532//  var d1 = create({
533//    get: function(r, k) { throw "myexn" },
534//    getOwnPropertyNames: function() { return ["value"] }
535//  })
536//  assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
537//  var d2 = create({
538//    get: function(r, k) { return 77 },
539//    getOwnPropertyNames: function() { throw "myexn" }
540//  })
541//  assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
542
543  var props = {bla: {get value() { throw "otherexn" }}}
544  assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
545}
546
547TestDefineThrow({
548  defineProperty: function(k, d) { throw "myexn" }
549})
550
551TestDefineThrow({
552  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
553  defineProperty2: function(k, d) { throw "myexn" }
554})
555
556TestDefineThrow(Proxy.create({
557  get: function(pr, pk) { throw "myexn" }
558}))
559
560TestDefineThrow(Proxy.create({
561  get: function(pr, pk) {
562    return function(k, d) { throw "myexn" }
563  }
564}))
565
566
567
568// Property deletion (delete).
569
570var key
571
572function TestDelete(handler) {
573  TestWithProxies(TestDelete2, handler)
574}
575
576function TestDelete2(handler, create) {
577  var p = create(handler)
578  assertEquals(true, delete p.a)
579  assertEquals("a", key)
580  assertEquals(true, delete p["b"])
581  assertEquals("b", key)
582
583  assertEquals(false, delete p.z1)
584  assertEquals("z1", key)
585  assertEquals(false, delete p["z2"])
586  assertEquals("z2", key);
587
588  (function() {
589    "use strict"
590    assertEquals(true, delete p.c)
591    assertEquals("c", key)
592    assertEquals(true, delete p["d"])
593    assertEquals("d", key)
594
595    assertThrows(function(){ delete p.z3 }, TypeError)
596    assertEquals("z3", key)
597    assertThrows(function(){ delete p["z4"] }, TypeError)
598    assertEquals("z4", key)
599  })()
600}
601
602TestDelete({
603  delete: function(k) { key = k; return k < "z" }
604})
605
606TestDelete({
607  delete: function(k) { return this.delete2(k) },
608  delete2: function(k) { key = k; return k < "z" }
609})
610
611TestDelete(Proxy.create({
612  get: function(pr, pk) {
613    return function(k) { key = k; return k < "z" }
614  }
615}))
616
617
618function TestDeleteThrow(handler) {
619  TestWithProxies(TestDeleteThrow2, handler)
620}
621
622function TestDeleteThrow2(handler, create) {
623  var p = create(handler)
624  assertThrows(function(){ delete p.a }, "myexn")
625  assertThrows(function(){ delete p["b"] }, "myexn");
626
627  (function() {
628    "use strict"
629    assertThrows(function(){ delete p.c }, "myexn")
630    assertThrows(function(){ delete p["d"] }, "myexn")
631  })()
632}
633
634TestDeleteThrow({
635  delete: function(k) { throw "myexn" }
636})
637
638TestDeleteThrow({
639  delete: function(k) { return this.delete2(k) },
640  delete2: function(k) { throw "myexn" }
641})
642
643TestDeleteThrow(Proxy.create({
644  get: function(pr, pk) { throw "myexn" }
645}))
646
647TestDeleteThrow(Proxy.create({
648  get: function(pr, pk) {
649    return function(k) { throw "myexn" }
650  }
651}))
652
653
654
655// Property descriptors (Object.getOwnPropertyDescriptor).
656
657function TestDescriptor(handler) {
658  TestWithProxies(TestDescriptor2, handler)
659}
660
661function TestDescriptor2(handler, create) {
662  var p = create(handler)
663  var descs = [
664    {configurable: true},
665    {value: 34, enumerable: true, configurable: true},
666    {value: 3, writable: false, mine: "eyes", configurable: true},
667    {get value() { return 20 }, get configurable() { return true }},
668    {get: function() { "get" }, set: function() { "set" }, configurable: true}
669  ]
670  for (var i = 0; i < descs.length; ++i) {
671    assertEquals(p, Object.defineProperty(p, i, descs[i]))
672    var desc = Object.getOwnPropertyDescriptor(p, i)
673    for (prop in descs[i]) {
674      // TODO(rossberg): Ignore user attributes as long as the spec isn't
675      // fixed suitably.
676      if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
677    }
678    assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
679  }
680}
681
682TestDescriptor({
683  defineProperty: function(k, d) { this["__" + k] = d; return true },
684  getOwnPropertyDescriptor: function(k) { return this["__" + k] }
685})
686
687TestDescriptor({
688  defineProperty: function(k, d) { this["__" + k] = d; return true },
689  getOwnPropertyDescriptor: function(k) {
690    return this.getOwnPropertyDescriptor2(k)
691  },
692  getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
693})
694
695
696function TestDescriptorThrow(handler) {
697  TestWithProxies(TestDescriptorThrow2, handler)
698}
699
700function TestDescriptorThrow2(handler, create) {
701  var p = create(handler)
702  assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
703}
704
705TestDescriptorThrow({
706  getOwnPropertyDescriptor: function(k) { throw "myexn" }
707})
708
709TestDescriptorThrow({
710  getOwnPropertyDescriptor: function(k) {
711    return this.getOwnPropertyDescriptor2(k)
712  },
713  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
714})
715
716
717
718// Comparison.
719
720function TestComparison(eq) {
721  TestWithProxies(TestComparison2, eq)
722}
723
724function TestComparison2(eq, create) {
725  var p1 = create({})
726  var p2 = create({})
727
728  assertTrue(eq(p1, p1))
729  assertTrue(eq(p2, p2))
730  assertTrue(!eq(p1, p2))
731  assertTrue(!eq(p1, {}))
732  assertTrue(!eq({}, p2))
733  assertTrue(!eq({}, {}))
734}
735
736TestComparison(function(o1, o2) { return o1 == o2 })
737TestComparison(function(o1, o2) { return o1 === o2 })
738TestComparison(function(o1, o2) { return !(o1 != o2) })
739TestComparison(function(o1, o2) { return !(o1 !== o2) })
740
741
742
743// Type (typeof).
744
745function TestTypeof() {
746  assertEquals("object", typeof Proxy.create({}))
747  assertTrue(typeof Proxy.create({}) == "object")
748  assertTrue("object" == typeof Proxy.create({}))
749
750  assertEquals("function", typeof Proxy.createFunction({}, function() {}))
751  assertTrue(typeof Proxy.createFunction({}, function() {}) == "function")
752  assertTrue("function" == typeof Proxy.createFunction({}, function() {}))
753}
754
755TestTypeof()
756
757
758
759// Membership test (in).
760
761var key
762
763function TestIn(handler) {
764  TestWithProxies(TestIn2, handler)
765}
766
767function TestIn2(handler, create) {
768  var p = create(handler)
769  assertTrue("a" in p)
770  assertEquals("a", key)
771  assertTrue(99 in p)
772  assertEquals("99", key)
773  assertFalse("z" in p)
774  assertEquals("z", key)
775
776  assertEquals(2, ("a" in p) ? 2 : 0)
777  assertEquals(0, !("a" in p) ? 2 : 0)
778  assertEquals(0, ("zzz" in p) ? 2 : 0)
779  assertEquals(2, !("zzz" in p) ? 2 : 0)
780
781  if ("b" in p) {
782  } else {
783    assertTrue(false)
784  }
785  assertEquals("b", key)
786
787  if ("zz" in p) {
788    assertTrue(false)
789  }
790  assertEquals("zz", key)
791
792  if (!("c" in p)) {
793    assertTrue(false)
794  }
795  assertEquals("c", key)
796
797  if (!("zzz" in p)) {
798  } else {
799    assertTrue(false)
800  }
801  assertEquals("zzz", key)
802}
803
804TestIn({
805  has: function(k) { key = k; return k < "z" }
806})
807
808TestIn({
809  has: function(k) { return this.has2(k) },
810  has2: function(k) { key = k; return k < "z" }
811})
812
813TestIn({
814  getPropertyDescriptor: function(k) {
815    key = k; return k < "z" ? {value: 42} : void 0
816  }
817})
818
819TestIn({
820  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
821  getPropertyDescriptor2: function(k) {
822    key = k; return k < "z" ? {value: 42} : void 0
823  }
824})
825
826TestIn({
827  getPropertyDescriptor: function(k) {
828    key = k; return k < "z" ? {get value() { return 42 }} : void 0
829  }
830})
831
832TestIn({
833  get: undefined,
834  getPropertyDescriptor: function(k) {
835    key = k; return k < "z" ? {value: 42} : void 0
836  }
837})
838
839TestIn(Proxy.create({
840  get: function(pr, pk) {
841    return function(k) { key = k; return k < "z" }
842  }
843}))
844
845
846function TestInThrow(handler) {
847  TestWithProxies(TestInThrow2, handler)
848}
849
850function TestInThrow2(handler, create) {
851  var p = create(handler)
852  assertThrows(function(){ return "a" in o }, "myexn")
853  assertThrows(function(){ return !("a" in o) }, "myexn")
854  assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn")
855  assertThrows(function(){ if ("b" in o) {} }, "myexn")
856  assertThrows(function(){ if (!("b" in o)) {} }, "myexn")
857  assertThrows(function(){ if ("zzz" in o) {} }, "myexn")
858}
859
860TestInThrow({
861  has: function(k) { throw "myexn" }
862})
863
864TestInThrow({
865  has: function(k) { return this.has2(k) },
866  has2: function(k) { throw "myexn" }
867})
868
869TestInThrow({
870  getPropertyDescriptor: function(k) { throw "myexn" }
871})
872
873TestInThrow({
874  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
875  getPropertyDescriptor2: function(k) { throw "myexn" }
876})
877
878TestInThrow({
879  get: undefined,
880  getPropertyDescriptor: function(k) { throw "myexn" }
881})
882
883TestInThrow(Proxy.create({
884  get: function(pr, pk) { throw "myexn" }
885}))
886
887TestInThrow(Proxy.create({
888  get: function(pr, pk) {
889    return function(k) { throw "myexn" }
890  }
891}))
892
893
894
895// Own Properties (Object.prototype.hasOwnProperty).
896
897var key
898
899function TestHasOwn(handler) {
900  TestWithProxies(TestHasOwn2, handler)
901}
902
903function TestHasOwn2(handler, create) {
904  var p = create(handler)
905  assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
906  assertEquals("a", key)
907  assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
908  assertEquals("99", key)
909  assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
910  assertEquals("z", key)
911}
912
913TestHasOwn({
914  hasOwn: function(k) { key = k; return k < "z" }
915})
916
917TestHasOwn({
918  hasOwn: function(k) { return this.hasOwn2(k) },
919  hasOwn2: function(k) { key = k; return k < "z" }
920})
921
922TestHasOwn({
923  getOwnPropertyDescriptor: function(k) {
924    key = k; return k < "z" ? {value: 42} : void 0
925  }
926})
927
928TestHasOwn({
929  getOwnPropertyDescriptor: function(k) {
930    return this.getOwnPropertyDescriptor2(k)
931  },
932  getOwnPropertyDescriptor2: function(k) {
933    key = k; return k < "z" ? {value: 42} : void 0
934  }
935})
936
937TestHasOwn({
938  getOwnPropertyDescriptor: function(k) {
939    key = k; return k < "z" ? {get value() { return 42 }} : void 0
940  }
941})
942
943TestHasOwn({
944  hasOwn: undefined,
945  getOwnPropertyDescriptor: function(k) {
946    key = k; return k < "z" ? {value: 42} : void 0
947  }
948})
949
950TestHasOwn(Proxy.create({
951  get: function(pr, pk) {
952    return function(k) { key = k; return k < "z" }
953  }
954}))
955
956
957function TestHasOwnThrow(handler) {
958  TestWithProxies(TestHasOwnThrow2, handler)
959}
960
961function TestHasOwnThrow2(handler, create) {
962  var p = create(handler)
963  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
964    "myexn")
965  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
966    "myexn")
967}
968
969TestHasOwnThrow({
970  hasOwn: function(k) { throw "myexn" }
971})
972
973TestHasOwnThrow({
974  hasOwn: function(k) { return this.hasOwn2(k) },
975  hasOwn2: function(k) { throw "myexn" }
976})
977
978TestHasOwnThrow({
979  getOwnPropertyDescriptor: function(k) { throw "myexn" }
980})
981
982TestHasOwnThrow({
983  getOwnPropertyDescriptor: function(k) {
984    return this.getOwnPropertyDescriptor2(k)
985  },
986  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
987})
988
989TestHasOwnThrow({
990  hasOwn: undefined,
991  getOwnPropertyDescriptor: function(k) { throw "myexn" }
992})
993
994TestHasOwnThrow(Proxy.create({
995  get: function(pr, pk) { throw "myexn" }
996}))
997
998TestHasOwnThrow(Proxy.create({
999  get: function(pr, pk) {
1000    return function(k) { throw "myexn" }
1001  }
1002}))
1003
1004
1005
1006// Instanceof (instanceof)
1007
1008function TestInstanceof() {
1009  var o = {}
1010  var p1 = Proxy.create({})
1011  var p2 = Proxy.create({}, o)
1012  var p3 = Proxy.create({}, p2)
1013
1014  var f0 = function() {}
1015  f0.prototype = o
1016  var f1 = function() {}
1017  f1.prototype = p1
1018  var f2 = function() {}
1019  f2.prototype = p2
1020
1021  assertTrue(o instanceof Object)
1022  assertFalse(o instanceof f0)
1023  assertFalse(o instanceof f1)
1024  assertFalse(o instanceof f2)
1025  assertFalse(p1 instanceof Object)
1026  assertFalse(p1 instanceof f0)
1027  assertFalse(p1 instanceof f1)
1028  assertFalse(p1 instanceof f2)
1029  assertTrue(p2 instanceof Object)
1030  assertTrue(p2 instanceof f0)
1031  assertFalse(p2 instanceof f1)
1032  assertFalse(p2 instanceof f2)
1033  assertTrue(p3 instanceof Object)
1034  assertTrue(p3 instanceof f0)
1035  assertFalse(p3 instanceof f1)
1036  assertTrue(p3 instanceof f2)
1037
1038  var f = Proxy.createFunction({}, function() {})
1039  assertTrue(f instanceof Function)
1040}
1041
1042TestInstanceof()
1043
1044
1045
1046// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
1047
1048function TestPrototype() {
1049  var o = {}
1050  var p1 = Proxy.create({})
1051  var p2 = Proxy.create({}, o)
1052  var p3 = Proxy.create({}, p2)
1053  var p4 = Proxy.create({}, 666)
1054
1055  assertSame(Object.getPrototypeOf(o), Object.prototype)
1056  assertSame(Object.getPrototypeOf(p1), null)
1057  assertSame(Object.getPrototypeOf(p2), o)
1058  assertSame(Object.getPrototypeOf(p3), p2)
1059  assertSame(Object.getPrototypeOf(p4), null)
1060
1061  assertTrue(Object.prototype.isPrototypeOf(o))
1062  assertFalse(Object.prototype.isPrototypeOf(p1))
1063  assertTrue(Object.prototype.isPrototypeOf(p2))
1064  assertTrue(Object.prototype.isPrototypeOf(p3))
1065  assertFalse(Object.prototype.isPrototypeOf(p4))
1066  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o))
1067  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
1068  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
1069  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
1070  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4))
1071  assertFalse(Object.prototype.isPrototypeOf.call(o, o))
1072  assertFalse(Object.prototype.isPrototypeOf.call(o, p1))
1073  assertTrue(Object.prototype.isPrototypeOf.call(o, p2))
1074  assertTrue(Object.prototype.isPrototypeOf.call(o, p3))
1075  assertFalse(Object.prototype.isPrototypeOf.call(o, p4))
1076  assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
1077  assertFalse(Object.prototype.isPrototypeOf.call(p1, o))
1078  assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
1079  assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
1080  assertFalse(Object.prototype.isPrototypeOf.call(p1, p4))
1081  assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
1082  assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
1083  assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
1084  assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
1085  assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
1086
1087  var f = Proxy.createFunction({}, function() {})
1088  assertSame(Object.getPrototypeOf(f), Function.prototype)
1089  assertTrue(Object.prototype.isPrototypeOf(f))
1090  assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
1091}
1092
1093TestPrototype()
1094
1095
1096
1097// Property names (Object.getOwnPropertyNames, Object.keys).
1098
1099function TestPropertyNames(names, handler) {
1100  TestWithProxies(TestPropertyNames2, [names, handler])
1101}
1102
1103function TestPropertyNames2(names_handler, create) {
1104  var p = create(names_handler[1])
1105  assertArrayEquals(names_handler[0], Object.getOwnPropertyNames(p))
1106}
1107
1108TestPropertyNames([], {
1109  getOwnPropertyNames: function() { return [] }
1110})
1111
1112TestPropertyNames(["a", "zz", " ", "0"], {
1113  getOwnPropertyNames: function() { return ["a", "zz", " ", 0] }
1114})
1115
1116TestPropertyNames(["throw", "function "], {
1117  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1118  getOwnPropertyNames2: function() { return ["throw", "function "] }
1119})
1120
1121TestPropertyNames(["[object Object]"], {
1122  get getOwnPropertyNames() {
1123    return function() { return [{}] }
1124  }
1125})
1126
1127
1128function TestPropertyNamesThrow(handler) {
1129  TestWithProxies(TestPropertyNamesThrow2, handler)
1130}
1131
1132function TestPropertyNamesThrow2(handler, create) {
1133  var p = create(handler)
1134  assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn")
1135}
1136
1137TestPropertyNamesThrow({
1138  getOwnPropertyNames: function() { throw "myexn" }
1139})
1140
1141TestPropertyNamesThrow({
1142  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1143  getOwnPropertyNames2: function() { throw "myexn" }
1144})
1145
1146
1147function TestKeys(names, handler) {
1148  TestWithProxies(TestKeys2, [names, handler])
1149}
1150
1151function TestKeys2(names_handler, create) {
1152  var p = create(names_handler[1])
1153  assertArrayEquals(names_handler[0], Object.keys(p))
1154}
1155
1156TestKeys([], {
1157  keys: function() { return [] }
1158})
1159
1160TestKeys(["a", "zz", " ", "0"], {
1161  keys: function() { return ["a", "zz", " ", 0] }
1162})
1163
1164TestKeys(["throw", "function "], {
1165  keys: function() { return this.keys2() },
1166  keys2: function() { return ["throw", "function "] }
1167})
1168
1169TestKeys(["[object Object]"], {
1170  get keys() {
1171    return function() { return [{}] }
1172  }
1173})
1174
1175TestKeys(["a", "0"], {
1176  getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
1177  getOwnPropertyDescriptor: function(k) { return {enumerable: k.length == 1} }
1178})
1179
1180TestKeys(["23", "zz", ""], {
1181  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1182  getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] },
1183  getOwnPropertyDescriptor: function(k) {
1184    return this.getOwnPropertyDescriptor2(k)
1185  },
1186  getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} }
1187})
1188
1189TestKeys(["a", "b", "c", "5"], {
1190  get getOwnPropertyNames() {
1191    return function() { return ["0", 4, "a", "b", "c", 5] }
1192  },
1193  get getOwnPropertyDescriptor() {
1194    return function(k) { return {enumerable: k >= "44"} }
1195  }
1196})
1197
1198TestKeys([], {
1199  get getOwnPropertyNames() {
1200    return function() { return ["a", "b", "c"] }
1201  },
1202  getOwnPropertyDescriptor: function(k) { return {} }
1203})
1204
1205
1206function TestKeysThrow(handler) {
1207  TestWithProxies(TestKeysThrow2, handler)
1208}
1209
1210function TestKeysThrow2(handler, create) {
1211  var p = create(handler)
1212  assertThrows(function(){ Object.keys(p) }, "myexn")
1213}
1214
1215TestKeysThrow({
1216  keys: function() { throw "myexn" }
1217})
1218
1219TestKeysThrow({
1220  keys: function() { return this.keys2() },
1221  keys2: function() { throw "myexn" }
1222})
1223
1224TestKeysThrow({
1225  getOwnPropertyNames: function() { throw "myexn" },
1226  getOwnPropertyDescriptor: function(k) { return true }
1227})
1228
1229TestKeysThrow({
1230  getOwnPropertyNames: function() { return [1, 2] },
1231  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1232})
1233
1234TestKeysThrow({
1235  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1236  getOwnPropertyNames2: function() { throw "myexn" },
1237})
1238
1239TestKeysThrow({
1240  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1241  getOwnPropertyNames2: function() { return [1, 2] },
1242  getOwnPropertyDescriptor: function(k) {
1243    return this.getOwnPropertyDescriptor2(k)
1244  },
1245  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1246})
1247
1248TestKeysThrow({
1249  get getOwnPropertyNames() { throw "myexn" }
1250})
1251
1252TestKeysThrow({
1253  get getOwnPropertyNames() {
1254    return function() { throw "myexn" }
1255  },
1256})
1257
1258TestKeysThrow([], {
1259  get getOwnPropertyNames() {
1260    return function() { return [1, 2] }
1261  },
1262  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1263})
1264
1265
1266
1267// Fixing (Object.freeze, Object.seal, Object.preventExtensions,
1268//         Object.isFrozen, Object.isSealed, Object.isExtensible)
1269
1270// TODO(rossberg): use TestWithProxies to include funciton proxies
1271function TestFix(names, handler) {
1272  var proto = {p: 77}
1273  var assertFixing = function(o, s, f, e) {
1274    assertEquals(s, Object.isSealed(o))
1275    assertEquals(f, Object.isFrozen(o))
1276    assertEquals(e, Object.isExtensible(o))
1277  }
1278
1279  var p1 = Proxy.create(handler, proto)
1280  assertFixing(p1, false, false, true)
1281  Object.seal(p1)
1282  assertFixing(p1, true, names.length === 0, false)
1283  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort())
1284  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1285                    Object.keys(p1).sort())
1286  assertEquals(proto, Object.getPrototypeOf(p1))
1287  assertEquals(77, p1.p)
1288  for (var n in p1) {
1289    var desc = Object.getOwnPropertyDescriptor(p1, n)
1290    if (desc !== undefined) assertFalse(desc.configurable)
1291  }
1292
1293  var p2 = Proxy.create(handler, proto)
1294  assertFixing(p2, false, false, true)
1295  Object.freeze(p2)
1296  assertFixing(p2, true, true, false)
1297  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort())
1298  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1299                    Object.keys(p2).sort())
1300  assertEquals(proto, Object.getPrototypeOf(p2))
1301  assertEquals(77, p2.p)
1302  for (var n in p2) {
1303    var desc = Object.getOwnPropertyDescriptor(p2, n)
1304    if (desc !== undefined) assertFalse(desc.writable)
1305    if (desc !== undefined) assertFalse(desc.configurable)
1306  }
1307
1308  var p3 = Proxy.create(handler, proto)
1309  assertFixing(p3, false, false, true)
1310  Object.preventExtensions(p3)
1311  assertFixing(p3, names.length === 0, names.length === 0, false)
1312  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort())
1313  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1314                    Object.keys(p3).sort())
1315  assertEquals(proto, Object.getPrototypeOf(p3))
1316  assertEquals(77, p3.p)
1317}
1318
1319TestFix([], {
1320  fix: function() { return {} }
1321})
1322
1323TestFix(["a", "b", "c", "d", "zz"], {
1324  fix: function() {
1325    return {
1326      a: {value: "a", writable: true, configurable: false, enumerable: true},
1327      b: {value: 33, writable: false, configurable: false, enumerable: true},
1328      c: {value: 0, writable: true, configurable: true, enumerable: true},
1329      d: {value: true, writable: false, configurable: true, enumerable: true},
1330      zz: {value: 0, enumerable: false}
1331    }
1332  }
1333})
1334
1335TestFix(["a"], {
1336  fix: function() { return this.fix2() },
1337  fix2: function() {
1338    return {a: {value: 4, writable: true, configurable: true, enumerable: true}}
1339  }
1340})
1341
1342TestFix(["b"], {
1343  get fix() {
1344    return function() {
1345      return {b: {configurable: true, writable: true, enumerable: true}}
1346    }
1347  }
1348})
1349
1350
1351function TestFixFunction(fix) {
1352  var f1 = Proxy.createFunction({
1353    fix: function() { return {} }
1354  }, function() {})
1355  fix(f1)
1356  assertEquals(0, f1.length)
1357
1358  var f2 = Proxy.createFunction({
1359    fix: function() { return {length: {value: 3}} }
1360  }, function() {})
1361  fix(f2)
1362  assertEquals(3, f2.length)
1363
1364  var f3 = Proxy.createFunction({
1365    fix: function() { return {length: {value: "huh"}} }
1366  }, function() {})
1367  fix(f3)
1368  assertEquals(0, f1.length)
1369}
1370
1371TestFixFunction(Object.seal)
1372TestFixFunction(Object.freeze)
1373TestFixFunction(Object.preventExtensions)
1374
1375
1376function TestFixThrow(handler) {
1377  TestWithProxies(TestFixThrow2, handler)
1378}
1379
1380function TestFixThrow2(handler) {
1381  var p = Proxy.create(handler, {})
1382  assertThrows(function(){ Object.seal(p) }, "myexn")
1383  assertThrows(function(){ Object.freeze(p) }, "myexn")
1384  assertThrows(function(){ Object.preventExtensions(p) }, "myexn")
1385}
1386
1387TestFixThrow({
1388  fix: function() { throw "myexn" }
1389})
1390
1391TestFixThrow({
1392  fix: function() { return this.fix2() },
1393  fix2: function() { throw "myexn" }
1394})
1395
1396TestFixThrow({
1397  get fix() { throw "myexn" }
1398})
1399
1400TestFixThrow({
1401  get fix() {
1402    return function() { throw "myexn" }
1403  }
1404})
1405
1406
1407
1408// String conversion (Object.prototype.toString,
1409//                    Object.prototype.toLocaleString,
1410//                    Function.prototype.toString)
1411
1412var key
1413
1414function TestToString(handler) {
1415  var p = Proxy.create(handler)
1416  key = ""
1417  assertEquals("[object Object]", Object.prototype.toString.call(p))
1418  assertEquals("", key)
1419  assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
1420  assertEquals("toString", key)
1421
1422  var f = Proxy.createFunction(handler, function() {})
1423  key = ""
1424  assertEquals("[object Function]", Object.prototype.toString.call(f))
1425  assertEquals("", key)
1426  assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
1427  assertEquals("toString", key)
1428  assertDoesNotThrow(function(){ Function.prototype.toString.call(f) })
1429}
1430
1431TestToString({
1432  get: function(r, k) { key = k; return function() { return "my_proxy" } }
1433})
1434
1435TestToString({
1436  get: function(r, k) { return this.get2(r, k) },
1437  get2: function(r, k) { key = k; return function() { return "my_proxy" } }
1438})
1439
1440TestToString(Proxy.create({
1441  get: function(pr, pk) {
1442    return function(r, k) { key = k; return function() { return "my_proxy" } }
1443  }
1444}))
1445
1446
1447function TestToStringThrow(handler) {
1448  var p = Proxy.create(handler)
1449  assertEquals("[object Object]", Object.prototype.toString.call(p))
1450  assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn")
1451
1452  var f = Proxy.createFunction(handler, function() {})
1453  assertEquals("[object Function]", Object.prototype.toString.call(f))
1454  assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn")
1455}
1456
1457TestToStringThrow({
1458  get: function(r, k) { throw "myexn" }
1459})
1460
1461TestToStringThrow({
1462  get: function(r, k) { return function() { throw "myexn" } }
1463})
1464
1465TestToStringThrow({
1466  get: function(r, k) { return this.get2(r, k) },
1467  get2: function(r, k) { throw "myexn" }
1468})
1469
1470TestToStringThrow(Proxy.create({
1471  get: function(pr, pk) { throw "myexn" }
1472}))
1473
1474TestToStringThrow(Proxy.create({
1475  get: function(pr, pk) {
1476    return function(r, k) { throw "myexn" }
1477  }
1478}))
1479
1480
1481
1482// Value conversion (Object.prototype.toValue)
1483
1484function TestValueOf(handler) {
1485  TestWithProxies(TestValueOf2, handler)
1486}
1487
1488function TestValueOf2(handler, create) {
1489  var p = create(handler)
1490  assertSame(p, Object.prototype.valueOf.call(p))
1491}
1492
1493TestValueOf({})
1494
1495
1496
1497// Enumerability (Object.prototype.propertyIsEnumerable)
1498
1499var key
1500
1501function TestIsEnumerable(handler) {
1502  TestWithProxies(TestIsEnumerable2, handler)
1503}
1504
1505function TestIsEnumerable2(handler, create) {
1506  var p = create(handler)
1507  assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
1508  assertEquals("a", key)
1509  assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
1510  assertEquals("2", key)
1511  assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
1512  assertEquals("z", key)
1513}
1514
1515TestIsEnumerable({
1516  getOwnPropertyDescriptor: function(k) {
1517    key = k; return {enumerable: k < "z", configurable: true}
1518  },
1519})
1520
1521TestIsEnumerable({
1522  getOwnPropertyDescriptor: function(k) {
1523    return this.getOwnPropertyDescriptor2(k)
1524  },
1525  getOwnPropertyDescriptor2: function(k) {
1526    key = k; return {enumerable: k < "z", configurable: true}
1527  },
1528})
1529
1530TestIsEnumerable({
1531  getOwnPropertyDescriptor: function(k) {
1532    key = k; return {get enumerable() { return k < "z" }, configurable: true}
1533  },
1534})
1535
1536TestIsEnumerable(Proxy.create({
1537  get: function(pr, pk) {
1538    return function(k) {
1539      key = k; return {enumerable: k < "z", configurable: true}
1540    }
1541  }
1542}))
1543
1544
1545function TestIsEnumerableThrow(handler) {
1546  TestWithProxies(TestIsEnumerableThrow2, handler)
1547}
1548
1549function TestIsEnumerableThrow2(handler, create) {
1550  var p = create(handler)
1551  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") },
1552    "myexn")
1553  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) },
1554    "myexn")
1555}
1556
1557TestIsEnumerableThrow({
1558  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1559})
1560
1561TestIsEnumerableThrow({
1562  getOwnPropertyDescriptor: function(k) {
1563    return this.getOwnPropertyDescriptor2(k)
1564  },
1565  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1566})
1567
1568TestIsEnumerableThrow({
1569  getOwnPropertyDescriptor: function(k) {
1570    return {get enumerable() { throw "myexn" }, configurable: true}
1571  },
1572})
1573
1574TestIsEnumerableThrow(Proxy.create({
1575  get: function(pr, pk) { throw "myexn" }
1576}))
1577
1578TestIsEnumerableThrow(Proxy.create({
1579  get: function(pr, pk) {
1580    return function(k) { throw "myexn" }
1581  }
1582}))
1583
1584
1585
1586// Calling (call, Function.prototype.call, Function.prototype.apply,
1587//          Function.prototype.bind).
1588
1589var global = this
1590var receiver
1591
1592function TestCall(isStrict, callTrap) {
1593  assertEquals(42, callTrap(5, 37))
1594// TODO(rossberg): unrelated bug: this does not succeed for optimized code.
1595// assertEquals(isStrict ? undefined : global, receiver)
1596
1597  var f = Proxy.createFunction({fix: function() { return {} }}, callTrap)
1598  receiver = 333
1599  assertEquals(42, f(11, 31))
1600  assertEquals(isStrict ? undefined : global, receiver)
1601  var o = {}
1602  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
1603  assertEquals(o, receiver)
1604  assertEquals(43, Function.prototype.call.call(f, null, 20, 23))
1605  assertEquals(isStrict ? null : global, receiver)
1606  assertEquals(44, Function.prototype.call.call(f, 2, 21, 23))
1607  assertEquals(2, receiver.valueOf())
1608  receiver = 333
1609  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
1610  assertEquals(o, receiver)
1611  var ff = Function.prototype.bind.call(f, o, 12)
1612  receiver = 333
1613  assertEquals(42, ff(30))
1614  assertEquals(o, receiver)
1615  receiver = 333
1616  assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
1617  assertEquals(o, receiver)
1618
1619  Object.freeze(f)
1620  receiver = 333
1621  assertEquals(42, f(11, 31))
1622// TODO(rossberg): unrelated bug: this does not succeed for optimized code.
1623// assertEquals(isStrict ? undefined : global, receiver)
1624  receiver = 333
1625  assertEquals(42, Function.prototype.call.call(f, o, 20, 22))
1626  assertEquals(o, receiver)
1627  receiver = 333
1628  assertEquals(32, Function.prototype.apply.call(f, o, [17, 15]))
1629  assertEquals(o, receiver)
1630  receiver = 333
1631  assertEquals(42, ff(30))
1632  assertEquals(o, receiver)
1633  receiver = 333
1634  assertEquals(32, Function.prototype.apply.call(ff, {}, [20]))
1635  assertEquals(o, receiver)
1636}
1637
1638TestCall(false, function(x, y) {
1639  receiver = this; return x + y
1640})
1641
1642TestCall(true, function(x, y) {
1643  "use strict";
1644  receiver = this; return x + y
1645})
1646
1647TestCall(false, Proxy.createFunction({}, function(x, y) {
1648  receiver = this; return x + y
1649}))
1650
1651TestCall(true, Proxy.createFunction({}, function(x, y) {
1652  "use strict";
1653  receiver = this; return x + y
1654}))
1655
1656var p = Proxy.createFunction({fix: function() {return {}}}, function(x, y) {
1657  receiver = this; return x + y
1658})
1659TestCall(false, p)
1660Object.freeze(p)
1661TestCall(false, p)
1662
1663
1664function TestCallThrow(callTrap) {
1665  var f = Proxy.createFunction({fix: function() {return {}}}, callTrap)
1666  assertThrows(function(){ f(11) }, "myexn")
1667  assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
1668  assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
1669
1670  Object.freeze(f)
1671  assertThrows(function(){ f(11) }, "myexn")
1672  assertThrows(function(){ Function.prototype.call.call(f, {}, 2) }, "myexn")
1673  assertThrows(function(){ Function.prototype.apply.call(f, {}, [1]) }, "myexn")
1674}
1675
1676TestCallThrow(function() { throw "myexn" })
1677TestCallThrow(Proxy.createFunction({}, function() { throw "myexn" }))
1678
1679var p = Proxy.createFunction(
1680  {fix: function() {return {}}}, function() { throw "myexn" })
1681Object.freeze(p)
1682TestCallThrow(p)
1683