proxies.js revision 5d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0b
1// Copyright 2011 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// Helper.
32
33function TestWithProxies(test, x, y, z) {
34  test(Proxy.create, x, y, z)
35  test(function(h) {return Proxy.createFunction(h, function() {})}, x, y, z)
36}
37
38
39
40// Getting property descriptors (Object.getOwnPropertyDescriptor).
41
42var key
43
44function TestGetOwnProperty(handler) {
45  TestWithProxies(TestGetOwnProperty2, handler)
46}
47
48function TestGetOwnProperty2(create, handler) {
49  var p = create(handler)
50  assertEquals(42, Object.getOwnPropertyDescriptor(p, "a").value)
51  assertEquals("a", key)
52  assertEquals(42, Object.getOwnPropertyDescriptor(p, 99).value)
53  assertEquals("99", key)
54}
55
56TestGetOwnProperty({
57  getOwnPropertyDescriptor: function(k) {
58    key = k
59    return {value: 42, configurable: true}
60  }
61})
62
63TestGetOwnProperty({
64  getOwnPropertyDescriptor: function(k) {
65    return this.getOwnPropertyDescriptor2(k)
66  },
67  getOwnPropertyDescriptor2: function(k) {
68    key = k
69    return {value: 42, configurable: true}
70  }
71})
72
73TestGetOwnProperty({
74  getOwnPropertyDescriptor: function(k) {
75    key = k
76    return {get value() { return 42 }, get configurable() { return true }}
77  }
78})
79
80TestGetOwnProperty(Proxy.create({
81  get: function(pr, pk) {
82    return function(k) { key = k; return {value: 42, configurable: true} }
83  }
84}))
85
86
87function TestGetOwnPropertyThrow(handler) {
88  TestWithProxies(TestGetOwnPropertyThrow2, handler)
89}
90
91function TestGetOwnPropertyThrow2(create, handler) {
92  var p = create(handler)
93  assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
94  assertThrows(function(){ Object.getOwnPropertyDescriptor(p, 77) }, "myexn")
95}
96
97TestGetOwnPropertyThrow({
98  getOwnPropertyDescriptor: function(k) { throw "myexn" }
99})
100
101TestGetOwnPropertyThrow({
102  getOwnPropertyDescriptor: function(k) {
103    return this.getPropertyDescriptor2(k)
104  },
105  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
106})
107
108TestGetOwnPropertyThrow({
109  getOwnPropertyDescriptor: function(k) {
110    return {get value() { throw "myexn" }}
111  }
112})
113
114TestGetOwnPropertyThrow(Proxy.create({
115  get: function(pr, pk) {
116    return function(k) { throw "myexn" }
117  }
118}))
119
120
121
122// Getters (dot, brackets).
123
124var key
125
126function TestGet(handler) {
127  TestWithProxies(TestGet2, handler)
128}
129
130function TestGet2(create, handler) {
131  var p = create(handler)
132  assertEquals(42, p.a)
133  assertEquals("a", key)
134  assertEquals(42, p["b"])
135  assertEquals("b", key)
136  assertEquals(42, p[99])
137  assertEquals("99", key)
138  assertEquals(42, (function(n) { return p[n] })("c"))
139  assertEquals("c", key)
140  assertEquals(42, (function(n) { return p[n] })(101))
141  assertEquals("101", key)
142
143  var o = Object.create(p, {x: {value: 88}})
144  assertEquals(42, o.a)
145  assertEquals("a", key)
146  assertEquals(42, o["b"])
147  assertEquals("b", key)
148  assertEquals(42, o[99])
149  assertEquals("99", key)
150  assertEquals(88, o.x)
151  assertEquals(88, o["x"])
152  assertEquals(42, (function(n) { return o[n] })("c"))
153  assertEquals("c", key)
154  assertEquals(42, (function(n) { return o[n] })(101))
155  assertEquals("101", key)
156  assertEquals(88, (function(n) { return o[n] })("x"))
157}
158
159TestGet({
160  get: function(r, k) { key = k; return 42 }
161})
162
163TestGet({
164  get: function(r, k) { return this.get2(r, k) },
165  get2: function(r, k) { key = k; return 42 }
166})
167
168TestGet({
169  getPropertyDescriptor: function(k) { key = k; return {value: 42} }
170})
171
172TestGet({
173  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
174  getPropertyDescriptor2: function(k) { key = k; return {value: 42} }
175})
176
177TestGet({
178  getPropertyDescriptor: function(k) {
179    key = k;
180    return {get value() { return 42 }}
181  }
182})
183
184TestGet({
185  get: undefined,
186  getPropertyDescriptor: function(k) { key = k; return {value: 42} }
187})
188
189TestGet(Proxy.create({
190  get: function(pr, pk) {
191    return function(r, k) { key = k; return 42 }
192  }
193}))
194
195
196function TestGetCall(handler) {
197  TestWithProxies(TestGetCall2, handler)
198}
199
200function TestGetCall2(create, handler) {
201  var p = create(handler)
202  assertEquals(55, p.f())
203  assertEquals(55, p["f"]())
204  assertEquals(55, p.f("unused", "arguments"))
205  assertEquals(55, p.f.call(p))
206  assertEquals(55, p["f"].call(p))
207  assertEquals(55, p[101].call(p))
208  assertEquals(55, p.withargs(45, 5))
209  assertEquals(55, p.withargs.call(p, 11, 22))
210  assertEquals(55, (function(n) { return p[n]() })("f"))
211  assertEquals(55, (function(n) { return p[n].call(p) })("f"))
212  assertEquals(55, (function(n) { return p[n](15, 20) })("withargs"))
213  assertEquals(55, (function(n) { return p[n].call(p, 13, 21) })("withargs"))
214  assertEquals("6655", "66" + p)  // calls p.toString
215
216  var o = Object.create(p, {g: {value: function(x) { return x + 88 }}})
217  assertEquals(55, o.f())
218  assertEquals(55, o["f"]())
219  assertEquals(55, o.f("unused", "arguments"))
220  assertEquals(55, o.f.call(o))
221  assertEquals(55, o.f.call(p))
222  assertEquals(55, o["f"].call(p))
223  assertEquals(55, o[101].call(p))
224  assertEquals(55, o.withargs(45, 5))
225  assertEquals(55, o.withargs.call(p, 11, 22))
226  assertEquals(90, o.g(2))
227  assertEquals(91, o.g.call(o, 3))
228  assertEquals(92, o.g.call(p, 4))
229  assertEquals(55, (function(n) { return o[n]() })("f"))
230  assertEquals(55, (function(n) { return o[n].call(o) })("f"))
231  assertEquals(55, (function(n) { return o[n](15, 20) })("withargs"))
232  assertEquals(55, (function(n) { return o[n].call(o, 13, 21) })("withargs"))
233  assertEquals(93, (function(n) { return o[n](5) })("g"))
234  assertEquals(94, (function(n) { return o[n].call(o, 6) })("g"))
235  assertEquals(95, (function(n) { return o[n].call(p, 7) })("g"))
236  assertEquals("6655", "66" + o)  // calls o.toString
237}
238
239TestGetCall({
240  get: function(r, k) { return function() { return 55 } }
241})
242
243TestGetCall({
244  get: function(r, k) { return this.get2(r, k) },
245  get2: function(r, k) { return function() { return 55 } }
246})
247
248TestGetCall({
249  getPropertyDescriptor: function(k) {
250    return {value: function() { return 55 }}
251  }
252})
253
254TestGetCall({
255  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
256  getPropertyDescriptor2: function(k) {
257    return {value: function() { return 55 }}
258  }
259})
260
261TestGetCall({
262  getPropertyDescriptor: function(k) {
263    return {get value() { return function() { return 55 } }}
264  }
265})
266
267TestGetCall({
268  get: undefined,
269  getPropertyDescriptor: function(k) {
270    return {value: function() { return 55 }}
271  }
272})
273
274TestGetCall({
275  get: function(r, k) {
276    if (k == "gg") {
277      return function() { return 55 }
278    } else if (k == "withargs") {
279      return function(n, m) { return n + m * 2 }
280    } else {
281      return function() { return this.gg() }
282    }
283  }
284})
285
286TestGetCall(Proxy.create({
287  get: function(pr, pk) {
288    return function(r, k) { return function() { return 55 } }
289  }
290}))
291
292
293function TestGetThrow(handler) {
294  TestWithProxies(TestGetThrow2, handler)
295}
296
297function TestGetThrow2(create, handler) {
298  var p = create(handler)
299  assertThrows(function(){ p.a }, "myexn")
300  assertThrows(function(){ p["b"] }, "myexn")
301  assertThrows(function(){ p[3] }, "myexn")
302  assertThrows(function(){ (function(n) { p[n] })("c") }, "myexn")
303  assertThrows(function(){ (function(n) { p[n] })(99) }, "myexn")
304
305  var o = Object.create(p, {x: {value: 88}, '4': {value: 89}})
306  assertThrows(function(){ o.a }, "myexn")
307  assertThrows(function(){ o["b"] }, "myexn")
308  assertThrows(function(){ o[3] }, "myexn")
309  assertThrows(function(){ (function(n) { o[n] })("c") }, "myexn")
310  assertThrows(function(){ (function(n) { o[n] })(99) }, "myexn")
311}
312
313TestGetThrow({
314  get: function(r, k) { throw "myexn" }
315})
316
317TestGetThrow({
318  get: function(r, k) { return this.get2(r, k) },
319  get2: function(r, k) { throw "myexn" }
320})
321
322TestGetThrow({
323  getPropertyDescriptor: function(k) { throw "myexn" }
324})
325
326TestGetThrow({
327  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
328  getPropertyDescriptor2: function(k) { throw "myexn" }
329})
330
331TestGetThrow({
332  getPropertyDescriptor: function(k) {
333    return {get value() { throw "myexn" }}
334  }
335})
336
337TestGetThrow({
338  get: undefined,
339  getPropertyDescriptor: function(k) { throw "myexn" }
340})
341
342TestGetThrow(Proxy.create({
343  get: function(pr, pk) { throw "myexn" }
344}))
345
346TestGetThrow(Proxy.create({
347  get: function(pr, pk) {
348    return function(r, k) { throw "myexn" }
349  }
350}))
351
352
353
354// Setters.
355
356var key
357var val
358
359function TestSet(handler) {
360  TestWithProxies(TestSet2, handler)
361}
362
363function TestSet2(create, handler) {
364  var p = create(handler)
365  assertEquals(42, p.a = 42)
366  assertEquals("a", key)
367  assertEquals(42, val)
368  assertEquals(43, p["b"] = 43)
369  assertEquals("b", key)
370  assertEquals(43, val)
371  assertEquals(44, p[77] = 44)
372  assertEquals("77", key)
373  assertEquals(44, val)
374
375  assertEquals(45, (function(n) { return p[n] = 45 })("c"))
376  assertEquals("c", key)
377  assertEquals(45, val)
378  assertEquals(46, (function(n) { return p[n] = 46 })(99))
379  assertEquals("99", key)
380  assertEquals(46, val)
381}
382
383TestSet({
384  set: function(r, k, v) { key = k; val = v; return true }
385})
386
387TestSet({
388  set: function(r, k, v) { return this.set2(r, k, v) },
389  set2: function(r, k, v) { key = k; val = v; return true }
390})
391
392TestSet({
393  getOwnPropertyDescriptor: function(k) { return {writable: true} },
394  defineProperty: function(k, desc) { key = k; val = desc.value }
395})
396
397TestSet({
398  getOwnPropertyDescriptor: function(k) {
399    return this.getOwnPropertyDescriptor2(k)
400  },
401  getOwnPropertyDescriptor2: function(k) { return {writable: true} },
402  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
403  defineProperty2: function(k, desc) { key = k; val = desc.value }
404})
405
406TestSet({
407  getOwnPropertyDescriptor: function(k) {
408    return {get writable() { return true }}
409  },
410  defineProperty: function(k, desc) { key = k; val = desc.value }
411})
412
413TestSet({
414  getOwnPropertyDescriptor: function(k) {
415    return {set: function(v) { key = k; val = v }}
416  }
417})
418
419TestSet({
420  getOwnPropertyDescriptor: function(k) { return null },
421  getPropertyDescriptor: function(k) { return {writable: true} },
422  defineProperty: function(k, desc) { key = k; val = desc.value }
423})
424
425TestSet({
426  getOwnPropertyDescriptor: function(k) { return null },
427  getPropertyDescriptor: function(k) {
428    return {get writable() { return true }}
429  },
430  defineProperty: function(k, desc) { key = k; val = desc.value }
431})
432
433TestSet({
434  getOwnPropertyDescriptor: function(k) { return null },
435  getPropertyDescriptor: function(k) {
436    return {set: function(v) { key = k; val = v }}
437  }
438})
439
440TestSet({
441  getOwnPropertyDescriptor: function(k) { return null },
442  getPropertyDescriptor: function(k) { return null },
443  defineProperty: function(k, desc) { key = k, val = desc.value }
444})
445
446TestSet(Proxy.create({
447  get: function(pr, pk) {
448    return function(r, k, v) { key = k; val = v; return true }
449  }
450}))
451
452
453function TestSetThrow(handler) {
454  TestWithProxies(TestSetThrow2, handler)
455}
456
457function TestSetThrow2(create, handler) {
458  var p = create(handler)
459  assertThrows(function(){ p.a = 42 }, "myexn")
460  assertThrows(function(){ p["b"] = 42 }, "myexn")
461  assertThrows(function(){ p[22] = 42 }, "myexn")
462  assertThrows(function(){ (function(n) { p[n] = 45 })("c") }, "myexn")
463  assertThrows(function(){ (function(n) { p[n] = 46 })(99) }, "myexn")
464}
465
466TestSetThrow({
467  set: function(r, k, v) { throw "myexn" }
468})
469
470TestSetThrow({
471  set: function(r, k, v) { return this.set2(r, k, v) },
472  set2: function(r, k, v) { throw "myexn" }
473})
474
475TestSetThrow({
476  getOwnPropertyDescriptor: function(k) { throw "myexn" },
477  defineProperty: function(k, desc) { key = k; val = desc.value }
478})
479
480TestSetThrow({
481  getOwnPropertyDescriptor: function(k) { return {writable: true} },
482  defineProperty: function(k, desc) { throw "myexn" }
483})
484
485TestSetThrow({
486  getOwnPropertyDescriptor: function(k) {
487    return this.getOwnPropertyDescriptor2(k)
488  },
489  getOwnPropertyDescriptor2: function(k) { throw "myexn" },
490  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
491  defineProperty2: function(k, desc) { key = k; val = desc.value }
492})
493
494TestSetThrow({
495  getOwnPropertyDescriptor: function(k) {
496    return this.getOwnPropertyDescriptor2(k)
497  },
498  getOwnPropertyDescriptor2: function(k) { return {writable: true} },
499  defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
500  defineProperty2: function(k, desc) { throw "myexn" }
501})
502
503TestSetThrow({
504  getOwnPropertyDescriptor: function(k) { throw "myexn" },
505  defineProperty: function(k, desc) { key = k; val = desc.value }
506})
507
508TestSetThrow({
509  getOwnPropertyDescriptor: function(k) {
510    return {get writable() { return true }}
511  },
512  defineProperty: function(k, desc) { throw "myexn" }
513})
514
515TestSetThrow({
516  getOwnPropertyDescriptor: function(k) { throw "myexn" }
517})
518
519TestSetThrow({
520  getOwnPropertyDescriptor: function(k) {
521    return {set: function(v) { throw "myexn" }}
522  }
523})
524
525TestSetThrow({
526  getOwnPropertyDescriptor: function(k) { throw "myexn" },
527  getPropertyDescriptor: function(k) { return {writable: true} },
528  defineProperty: function(k, desc) { key = k; val = desc.value }
529})
530
531TestSetThrow({
532  getOwnPropertyDescriptor: function(k) { return null },
533  getPropertyDescriptor: function(k) { throw "myexn" },
534  defineProperty: function(k, desc) { key = k; val = desc.value }
535})
536
537TestSetThrow({
538  getOwnPropertyDescriptor: function(k) { return null },
539  getPropertyDescriptor: function(k) { return {writable: true} },
540  defineProperty: function(k, desc) { throw "myexn" }
541})
542
543TestSetThrow({
544  getOwnPropertyDescriptor: function(k) { return null },
545  getPropertyDescriptor: function(k) {
546    return {get writable() { throw "myexn" }}
547  },
548  defineProperty: function(k, desc) { key = k; val = desc.value }
549})
550
551TestSetThrow({
552  getOwnPropertyDescriptor: function(k) { return null },
553  getPropertyDescriptor: function(k) {
554    return {set: function(v) { throw "myexn" }}
555  }
556})
557
558TestSetThrow({
559  getOwnPropertyDescriptor: function(k) { return null },
560  getPropertyDescriptor: function(k) { return null },
561  defineProperty: function(k, desc) { throw "myexn" }
562})
563
564TestSetThrow(Proxy.create({
565  get: function(pr, pk) { throw "myexn" }
566}))
567
568TestSetThrow(Proxy.create({
569  get: function(pr, pk) {
570    return function(r, k, v) { throw "myexn" }
571  }
572}))
573
574
575var key
576var val
577
578function TestSetForDerived(handler) {
579  TestWithProxies(TestSetForDerived2, handler)
580}
581
582function TestSetForDerived2(create, handler) {
583  var p = create(handler)
584  var o = Object.create(p, {x: {value: 88, writable: true},
585                            '1': {value: 89, writable: true}})
586
587  key = ""
588  assertEquals(48, o.x = 48)
589  assertEquals("", key)  // trap not invoked
590  assertEquals(48, o.x)
591
592  assertEquals(47, o[1] = 47)
593  assertEquals("", key)  // trap not invoked
594  assertEquals(47, o[1])
595
596  assertEquals(49, o.y = 49)
597  assertEquals("y", key)
598  assertEquals(49, o.y)
599
600  assertEquals(50, o[2] = 50)
601  assertEquals("2", key)
602  assertEquals(50, o[2])
603
604  assertEquals(44, o.p_writable = 44)
605  assertEquals("p_writable", key)
606  assertEquals(44, o.p_writable)
607
608  assertEquals(45, o.p_nonwritable = 45)
609  assertEquals("p_nonwritable", key)
610  assertEquals(45, o.p_nonwritable)
611
612  assertEquals(46, o.p_setter = 46)
613  assertEquals("p_setter", key)
614  assertEquals(46, val)  // written to parent
615  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter"))
616
617  val = ""
618  assertEquals(47, o.p_nosetter = 47)
619  assertEquals("p_nosetter", key)
620  assertEquals("", val)  // not written at all
621  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter"));
622
623  key = ""
624  assertThrows(function(){ "use strict"; o.p_nosetter = 50 }, TypeError)
625  assertEquals("p_nosetter", key)
626  assertEquals("", val)  // not written at all
627
628  assertThrows(function(){ o.p_nonconf = 53 }, TypeError)
629  assertEquals("p_nonconf", key)
630
631  assertThrows(function(){ o.p_throw = 51 }, "myexn")
632  assertEquals("p_throw", key)
633
634  assertThrows(function(){ o.p_setterthrow = 52 }, "myexn")
635  assertEquals("p_setterthrow", key)
636}
637
638TestSetForDerived({
639  getPropertyDescriptor: function(k) {
640    key = k;
641    switch (k) {
642      case "p_writable": return {writable: true, configurable: true}
643      case "p_nonwritable": return {writable: false, configurable: true}
644      case "p_setter":return {set: function(x) { val = x }, configurable: true}
645      case "p_nosetter": return {get: function() { return 1 }, configurable: true}
646      case "p_nonconf":return {}
647      case "p_throw": throw "myexn"
648      case "p_setterthrow": return {set: function(x) { throw "myexn" }}
649      default: return undefined
650    }
651  }
652})
653
654
655// Evil proxy-induced side-effects shouldn't crash.
656// TODO(rossberg): proper behaviour isn't really spec'ed yet, so ignore results.
657
658TestWithProxies(function(create) {
659  var calls = 0
660  var handler = {
661    getPropertyDescriptor: function() {
662      ++calls
663      return (calls % 2 == 1)
664        ? {get: function() { return 5 }, configurable: true}
665        : {set: function() { return false }, configurable: true}
666    }
667  }
668  var p = create(handler)
669  var o = Object.create(p)
670  // Make proxy prototype property read-only after CanPut check.
671  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
672})
673
674TestWithProxies(function(create) {
675  var handler = {
676    getPropertyDescriptor: function() {
677      Object.defineProperty(o, "x", {get: function() { return 5 }});
678      return {set: function() {}}
679    }
680  }
681  var p = create(handler)
682  var o = Object.create(p)
683  // Make object property read-only after CanPut check.
684  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
685})
686
687
688
689// TODO(rossberg): TestSetReject, returning false
690// TODO(rossberg): TestGetProperty, TestSetProperty
691
692
693
694// Property definition (Object.defineProperty and Object.defineProperties).
695
696var key
697var desc
698
699function TestDefine(handler) {
700  TestWithProxies(TestDefine2, handler)
701}
702
703function TestDefine2(create, handler) {
704  var p = create(handler)
705  assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
706  assertEquals("a", key)
707  assertEquals(1, Object.getOwnPropertyNames(desc).length)
708  assertEquals(44, desc.value)
709
710  assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
711  assertEquals("b", key)
712  assertEquals(2, Object.getOwnPropertyNames(desc).length)
713  assertEquals(45, desc.value)
714  assertEquals(false, desc.writable)
715
716  assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
717  assertEquals("c", key)
718  assertEquals(2, Object.getOwnPropertyNames(desc).length)
719  assertEquals(46, desc.value)
720  assertEquals(false, desc.enumerable)
721
722  assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
723  assertEquals("101", key)
724  assertEquals(2, Object.getOwnPropertyNames(desc).length)
725  assertEquals(47, desc.value)
726  assertEquals(false, desc.enumerable)
727
728  var attributes = {configurable: true, mine: 66, minetoo: 23}
729  assertEquals(p, Object.defineProperty(p, "d", attributes))
730  assertEquals("d", key)
731  // Modifying the attributes object after the fact should have no effect.
732  attributes.configurable = false
733  attributes.mine = 77
734  delete attributes.minetoo
735  assertEquals(3, Object.getOwnPropertyNames(desc).length)
736  assertEquals(true, desc.configurable)
737  assertEquals(66, desc.mine)
738  assertEquals(23, desc.minetoo)
739
740  assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
741  assertEquals("e", key)
742  assertEquals(1, Object.getOwnPropertyNames(desc).length)
743  assertEquals(5, desc.get())
744
745  assertEquals(p, Object.defineProperty(p, "zzz", {}))
746  assertEquals("zzz", key)
747  assertEquals(0, Object.getOwnPropertyNames(desc).length)
748
749  var d = create({
750    get: function(r, k) { return (k === "value") ? 77 : void 0 },
751    getOwnPropertyNames: function() { return ["value"] },
752    enumerate: function() { return ["value"] }
753  })
754  assertEquals(1, Object.getOwnPropertyNames(d).length)
755  assertEquals(77, d.value)
756  assertEquals(p, Object.defineProperty(p, "p", d))
757  assertEquals("p", key)
758  assertEquals(1, Object.getOwnPropertyNames(desc).length)
759  assertEquals(77, desc.value)
760
761  var props = {
762    '11': {},
763    blub: {get: function() { return true }},
764    '': {get value() { return 20 }},
765    last: {value: 21, configurable: true, mine: "eyes"}
766  }
767  Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
768  assertEquals(p, Object.defineProperties(p, props))
769  assertEquals("last", key)
770  assertEquals(2, Object.getOwnPropertyNames(desc).length)
771  assertEquals(21, desc.value)
772  assertEquals(true, desc.configurable)
773  assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
774
775  var props = {bla: {get value() { throw "myexn" }}}
776  assertThrows(function(){ Object.defineProperties(p, props) }, "myexn")
777}
778
779TestDefine({
780  defineProperty: function(k, d) { key = k; desc = d; return true }
781})
782
783TestDefine({
784  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
785  defineProperty2: function(k, d) { key = k; desc = d; return true }
786})
787
788TestDefine(Proxy.create({
789  get: function(pr, pk) {
790    return function(k, d) { key = k; desc = d; return true }
791  }
792}))
793
794
795function TestDefineThrow(handler) {
796  TestWithProxies(TestDefineThrow2, handler)
797}
798
799function TestDefineThrow2(create, handler) {
800  var p = create(handler)
801  assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
802  assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn")
803
804  var d1 = create({
805    get: function(r, k) { throw "myexn" },
806    getOwnPropertyNames: function() { return ["value"] }
807  })
808  assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
809  var d2 = create({
810    get: function(r, k) { return 77 },
811    getOwnPropertyNames: function() { throw "myexn" }
812  })
813  assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
814
815  var props = {bla: {get value() { throw "otherexn" }}}
816  assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
817}
818
819TestDefineThrow({
820  defineProperty: function(k, d) { throw "myexn" }
821})
822
823TestDefineThrow({
824  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
825  defineProperty2: function(k, d) { throw "myexn" }
826})
827
828TestDefineThrow(Proxy.create({
829  get: function(pr, pk) { throw "myexn" }
830}))
831
832TestDefineThrow(Proxy.create({
833  get: function(pr, pk) {
834    return function(k, d) { throw "myexn" }
835  }
836}))
837
838
839
840// Property deletion (delete).
841
842var key
843
844function TestDelete(handler) {
845  TestWithProxies(TestDelete2, handler)
846}
847
848function TestDelete2(create, handler) {
849  var p = create(handler)
850  assertEquals(true, delete p.a)
851  assertEquals("a", key)
852  assertEquals(true, delete p["b"])
853  assertEquals("b", key)
854  assertEquals(true, delete p[1])
855  assertEquals("1", key)
856
857  assertEquals(false, delete p.z1)
858  assertEquals("z1", key)
859  assertEquals(false, delete p["z2"])
860  assertEquals("z2", key);
861
862  (function() {
863    "use strict"
864    assertEquals(true, delete p.c)
865    assertEquals("c", key)
866    assertEquals(true, delete p["d"])
867    assertEquals("d", key)
868    assertEquals(true, delete p[2])
869    assertEquals("2", key)
870
871    assertThrows(function(){ delete p.z3 }, TypeError)
872    assertEquals("z3", key)
873    assertThrows(function(){ delete p["z4"] }, TypeError)
874    assertEquals("z4", key)
875  })()
876}
877
878TestDelete({
879  delete: function(k) { key = k; return k < "z" }
880})
881
882TestDelete({
883  delete: function(k) { return this.delete2(k) },
884  delete2: function(k) { key = k; return k < "z" }
885})
886
887TestDelete(Proxy.create({
888  get: function(pr, pk) {
889    return function(k) { key = k; return k < "z" }
890  }
891}))
892
893
894function TestDeleteThrow(handler) {
895  TestWithProxies(TestDeleteThrow2, handler)
896}
897
898function TestDeleteThrow2(create, handler) {
899  var p = create(handler)
900  assertThrows(function(){ delete p.a }, "myexn")
901  assertThrows(function(){ delete p["b"] }, "myexn");
902  assertThrows(function(){ delete p[3] }, "myexn");
903
904  (function() {
905    "use strict"
906    assertThrows(function(){ delete p.c }, "myexn")
907    assertThrows(function(){ delete p["d"] }, "myexn")
908    assertThrows(function(){ delete p[4] }, "myexn");
909  })()
910}
911
912TestDeleteThrow({
913  delete: function(k) { throw "myexn" }
914})
915
916TestDeleteThrow({
917  delete: function(k) { return this.delete2(k) },
918  delete2: function(k) { throw "myexn" }
919})
920
921TestDeleteThrow(Proxy.create({
922  get: function(pr, pk) { throw "myexn" }
923}))
924
925TestDeleteThrow(Proxy.create({
926  get: function(pr, pk) {
927    return function(k) { throw "myexn" }
928  }
929}))
930
931
932
933// Property descriptors (Object.getOwnPropertyDescriptor).
934
935function TestDescriptor(handler) {
936  TestWithProxies(TestDescriptor2, handler)
937}
938
939function TestDescriptor2(create, handler) {
940  var p = create(handler)
941  var descs = [
942    {configurable: true},
943    {value: 34, enumerable: true, configurable: true},
944    {value: 3, writable: false, mine: "eyes", configurable: true},
945    {get value() { return 20 }, get configurable() { return true }},
946    {get: function() { "get" }, set: function() { "set" }, configurable: true}
947  ]
948  for (var i = 0; i < descs.length; ++i) {
949    assertEquals(p, Object.defineProperty(p, i, descs[i]))
950    var desc = Object.getOwnPropertyDescriptor(p, i)
951    for (prop in descs[i]) {
952      // TODO(rossberg): Ignore user attributes as long as the spec isn't
953      // fixed suitably.
954      if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
955    }
956    assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
957  }
958}
959
960TestDescriptor({
961  defineProperty: function(k, d) { this["__" + k] = d; return true },
962  getOwnPropertyDescriptor: function(k) { return this["__" + k] }
963})
964
965TestDescriptor({
966  defineProperty: function(k, d) { this["__" + k] = d; return true },
967  getOwnPropertyDescriptor: function(k) {
968    return this.getOwnPropertyDescriptor2(k)
969  },
970  getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
971})
972
973
974function TestDescriptorThrow(handler) {
975  TestWithProxies(TestDescriptorThrow2, handler)
976}
977
978function TestDescriptorThrow2(create, handler) {
979  var p = create(handler)
980  assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
981}
982
983TestDescriptorThrow({
984  getOwnPropertyDescriptor: function(k) { throw "myexn" }
985})
986
987TestDescriptorThrow({
988  getOwnPropertyDescriptor: function(k) {
989    return this.getOwnPropertyDescriptor2(k)
990  },
991  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
992})
993
994
995
996// Comparison.
997
998function TestComparison(eq) {
999  TestWithProxies(TestComparison2, eq)
1000}
1001
1002function TestComparison2(create, eq) {
1003  var p1 = create({})
1004  var p2 = create({})
1005
1006  assertTrue(eq(p1, p1))
1007  assertTrue(eq(p2, p2))
1008  assertTrue(!eq(p1, p2))
1009  assertTrue(!eq(p1, {}))
1010  assertTrue(!eq({}, p2))
1011  assertTrue(!eq({}, {}))
1012}
1013
1014TestComparison(function(o1, o2) { return o1 == o2 })
1015TestComparison(function(o1, o2) { return o1 === o2 })
1016TestComparison(function(o1, o2) { return !(o1 != o2) })
1017TestComparison(function(o1, o2) { return !(o1 !== o2) })
1018
1019
1020
1021// Type (typeof).
1022
1023function TestTypeof() {
1024  assertEquals("object", typeof Proxy.create({}))
1025  assertTrue(typeof Proxy.create({}) == "object")
1026  assertTrue("object" == typeof Proxy.create({}))
1027
1028  assertEquals("function", typeof Proxy.createFunction({}, function() {}))
1029  assertTrue(typeof Proxy.createFunction({}, function() {}) == "function")
1030  assertTrue("function" == typeof Proxy.createFunction({}, function() {}))
1031}
1032
1033TestTypeof()
1034
1035
1036
1037// Membership test (in).
1038
1039var key
1040
1041function TestIn(handler) {
1042  TestWithProxies(TestIn2, handler)
1043}
1044
1045function TestIn2(create, handler) {
1046  var p = create(handler)
1047  assertTrue("a" in p)
1048  assertEquals("a", key)
1049  assertTrue(99 in p)
1050  assertEquals("99", key)
1051  assertFalse("z" in p)
1052  assertEquals("z", key)
1053
1054  assertEquals(2, ("a" in p) ? 2 : 0)
1055  assertEquals(0, !("a" in p) ? 2 : 0)
1056  assertEquals(0, ("zzz" in p) ? 2 : 0)
1057  assertEquals(2, !("zzz" in p) ? 2 : 0)
1058
1059  // Test compilation in conditionals.
1060  if ("b" in p) {
1061  } else {
1062    assertTrue(false)
1063  }
1064  assertEquals("b", key)
1065
1066  if ("zz" in p) {
1067    assertTrue(false)
1068  }
1069  assertEquals("zz", key)
1070
1071  if (!("c" in p)) {
1072    assertTrue(false)
1073  }
1074  assertEquals("c", key)
1075
1076  if (!("zzz" in p)) {
1077  } else {
1078    assertTrue(false)
1079  }
1080  assertEquals("zzz", key)
1081}
1082
1083TestIn({
1084  has: function(k) { key = k; return k < "z" }
1085})
1086
1087TestIn({
1088  has: function(k) { return this.has2(k) },
1089  has2: function(k) { key = k; return k < "z" }
1090})
1091
1092TestIn({
1093  getPropertyDescriptor: function(k) {
1094    key = k; return k < "z" ? {value: 42} : void 0
1095  }
1096})
1097
1098TestIn({
1099  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1100  getPropertyDescriptor2: function(k) {
1101    key = k; return k < "z" ? {value: 42} : void 0
1102  }
1103})
1104
1105TestIn({
1106  getPropertyDescriptor: function(k) {
1107    key = k; return k < "z" ? {get value() { return 42 }} : void 0
1108  }
1109})
1110
1111TestIn({
1112  has: undefined,
1113  getPropertyDescriptor: function(k) {
1114    key = k; return k < "z" ? {value: 42} : void 0
1115  }
1116})
1117
1118TestIn(Proxy.create({
1119  get: function(pr, pk) {
1120    return function(k) { key = k; return k < "z" }
1121  }
1122}))
1123
1124
1125function TestInThrow(handler) {
1126  TestWithProxies(TestInThrow2, handler)
1127}
1128
1129function TestInThrow2(create, handler) {
1130  var p = create(handler)
1131  assertThrows(function(){ return "a" in o }, "myexn")
1132  assertThrows(function(){ return 99 in o }, "myexn")
1133  assertThrows(function(){ return !("a" in o) }, "myexn")
1134  assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn")
1135  assertThrows(function(){ if ("b" in o) {} }, "myexn")
1136  assertThrows(function(){ if (!("b" in o)) {} }, "myexn")
1137  assertThrows(function(){ if ("zzz" in o) {} }, "myexn")
1138}
1139
1140TestInThrow({
1141  has: function(k) { throw "myexn" }
1142})
1143
1144TestInThrow({
1145  has: function(k) { return this.has2(k) },
1146  has2: function(k) { throw "myexn" }
1147})
1148
1149TestInThrow({
1150  getPropertyDescriptor: function(k) { throw "myexn" }
1151})
1152
1153TestInThrow({
1154  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1155  getPropertyDescriptor2: function(k) { throw "myexn" }
1156})
1157
1158TestInThrow({
1159  has: undefined,
1160  getPropertyDescriptor: function(k) { throw "myexn" }
1161})
1162
1163TestInThrow(Proxy.create({
1164  get: function(pr, pk) { throw "myexn" }
1165}))
1166
1167TestInThrow(Proxy.create({
1168  get: function(pr, pk) {
1169    return function(k) { throw "myexn" }
1170  }
1171}))
1172
1173
1174function TestInForDerived(handler) {
1175  TestWithProxies(TestInForDerived2, handler)
1176}
1177
1178function TestInForDerived2(create, handler) {
1179  var p = create(handler)
1180  var o = Object.create(p)
1181
1182  assertTrue("a" in o)
1183  assertEquals("a", key)
1184  assertTrue(99 in o)
1185  assertEquals("99", key)
1186  assertFalse("z" in o)
1187  assertEquals("z", key)
1188
1189  assertEquals(2, ("a" in o) ? 2 : 0)
1190  assertEquals(0, !("a" in o) ? 2 : 0)
1191  assertEquals(0, ("zzz" in o) ? 2 : 0)
1192  assertEquals(2, !("zzz" in o) ? 2 : 0)
1193
1194  if ("b" in o) {
1195  } else {
1196    assertTrue(false)
1197  }
1198  assertEquals("b", key)
1199
1200  if ("zz" in o) {
1201    assertTrue(false)
1202  }
1203  assertEquals("zz", key)
1204
1205  if (!("c" in o)) {
1206    assertTrue(false)
1207  }
1208  assertEquals("c", key)
1209
1210  if (!("zzz" in o)) {
1211  } else {
1212    assertTrue(false)
1213  }
1214  assertEquals("zzz", key)
1215}
1216
1217TestInForDerived({
1218  getPropertyDescriptor: function(k) {
1219    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1220  }
1221})
1222
1223TestInForDerived({
1224  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1225  getPropertyDescriptor2: function(k) {
1226    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1227  }
1228})
1229
1230TestInForDerived({
1231  getPropertyDescriptor: function(k) {
1232    key = k;
1233    return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
1234  }
1235})
1236
1237/* TODO(rossberg): this will work once we implement the newest proposal
1238 * regarding default traps for getPropertyDescriptor.
1239TestInForDerived({
1240  getOwnPropertyDescriptor: function(k) {
1241    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1242  }
1243})
1244
1245TestInForDerived({
1246  getOwnPropertyDescriptor: function(k) {
1247    return this.getOwnPropertyDescriptor2(k)
1248  },
1249  getOwnPropertyDescriptor2: function(k) {
1250    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1251  }
1252})
1253
1254TestInForDerived({
1255  getOwnPropertyDescriptor: function(k) {
1256    key = k;
1257    return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
1258  }
1259})
1260*/
1261
1262TestInForDerived(Proxy.create({
1263  get: function(pr, pk) {
1264    return function(k) {
1265      key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1266    }
1267  }
1268}))
1269
1270
1271
1272// Property descriptor conversion.
1273
1274var descget
1275
1276function TestDescriptorGetOrder(handler) {
1277  var p = Proxy.create(handler)
1278  var o = Object.create(p, {b: {value: 0}})
1279  TestDescriptorGetOrder2(function(n) { return p[n] }, "vV")
1280  TestDescriptorGetOrder2(function(n) { return n in p }, "")
1281  TestDescriptorGetOrder2(function(n) { return o[n] }, "vV")
1282  TestDescriptorGetOrder2(function(n) { return n in o }, "eEcCvVwWgs")
1283}
1284
1285function TestDescriptorGetOrder2(f, access) {
1286  descget = ""
1287  assertTrue(f("a"))
1288  assertEquals(access, descget)
1289  descget = ""
1290  assertTrue(f(99))
1291  assertEquals(access, descget)
1292  descget = ""
1293  assertFalse(!!f("z"))
1294  assertEquals("", descget)
1295}
1296
1297TestDescriptorGetOrder({
1298  getPropertyDescriptor: function(k) {
1299    if (k >= "z") return void 0
1300    // Return a proxy as property descriptor, so that we can log accesses.
1301    return Proxy.create({
1302      get: function(r, attr) {
1303        descget += attr[0].toUpperCase()
1304        return true
1305      },
1306      has: function(attr) {
1307        descget += attr[0]
1308        switch (attr) {
1309          case "writable":
1310          case "enumerable":
1311          case "configurable":
1312          case "value":
1313            return true
1314          case "get":
1315          case "set":
1316            return false
1317          default:
1318            assertUnreachable()
1319        }
1320      }
1321    })
1322  }
1323})
1324
1325
1326
1327// Own Properties (Object.prototype.hasOwnProperty).
1328
1329var key
1330
1331function TestHasOwn(handler) {
1332  TestWithProxies(TestHasOwn2, handler)
1333}
1334
1335function TestHasOwn2(create, handler) {
1336  var p = create(handler)
1337  assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
1338  assertEquals("a", key)
1339  assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
1340  assertEquals("99", key)
1341  assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
1342  assertEquals("z", key)
1343}
1344
1345TestHasOwn({
1346  hasOwn: function(k) { key = k; return k < "z" }
1347})
1348
1349TestHasOwn({
1350  hasOwn: function(k) { return this.hasOwn2(k) },
1351  hasOwn2: function(k) { key = k; return k < "z" }
1352})
1353
1354TestHasOwn({
1355  getOwnPropertyDescriptor: function(k) {
1356    key = k; return k < "z" ? {value: 42} : void 0
1357  }
1358})
1359
1360TestHasOwn({
1361  getOwnPropertyDescriptor: function(k) {
1362    return this.getOwnPropertyDescriptor2(k)
1363  },
1364  getOwnPropertyDescriptor2: function(k) {
1365    key = k; return k < "z" ? {value: 42} : void 0
1366  }
1367})
1368
1369TestHasOwn({
1370  getOwnPropertyDescriptor: function(k) {
1371    key = k; return k < "z" ? {get value() { return 42 }} : void 0
1372  }
1373})
1374
1375TestHasOwn({
1376  hasOwn: undefined,
1377  getOwnPropertyDescriptor: function(k) {
1378    key = k; return k < "z" ? {value: 42} : void 0
1379  }
1380})
1381
1382TestHasOwn(Proxy.create({
1383  get: function(pr, pk) {
1384    return function(k) { key = k; return k < "z" }
1385  }
1386}))
1387
1388
1389function TestHasOwnThrow(handler) {
1390  TestWithProxies(TestHasOwnThrow2, handler)
1391}
1392
1393function TestHasOwnThrow2(create, handler) {
1394  var p = create(handler)
1395  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
1396    "myexn")
1397  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
1398    "myexn")
1399}
1400
1401TestHasOwnThrow({
1402  hasOwn: function(k) { throw "myexn" }
1403})
1404
1405TestHasOwnThrow({
1406  hasOwn: function(k) { return this.hasOwn2(k) },
1407  hasOwn2: function(k) { throw "myexn" }
1408})
1409
1410TestHasOwnThrow({
1411  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1412})
1413
1414TestHasOwnThrow({
1415  getOwnPropertyDescriptor: function(k) {
1416    return this.getOwnPropertyDescriptor2(k)
1417  },
1418  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1419})
1420
1421TestHasOwnThrow({
1422  hasOwn: undefined,
1423  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1424})
1425
1426TestHasOwnThrow(Proxy.create({
1427  get: function(pr, pk) { throw "myexn" }
1428}))
1429
1430TestHasOwnThrow(Proxy.create({
1431  get: function(pr, pk) {
1432    return function(k) { throw "myexn" }
1433  }
1434}))
1435
1436
1437
1438// Instanceof (instanceof)
1439
1440function TestProxyInstanceof() {
1441  var o1 = {}
1442  var p1 = Proxy.create({})
1443  var p2 = Proxy.create({}, o1)
1444  var p3 = Proxy.create({}, p2)
1445  var o2 = Object.create(p2)
1446
1447  var f0 = function() {}
1448  f0.prototype = o1
1449  var f1 = function() {}
1450  f1.prototype = p1
1451  var f2 = function() {}
1452  f2.prototype = p2
1453  var f3 = function() {}
1454  f3.prototype = o2
1455
1456  assertTrue(o1 instanceof Object)
1457  assertFalse(o1 instanceof f0)
1458  assertFalse(o1 instanceof f1)
1459  assertFalse(o1 instanceof f2)
1460  assertFalse(o1 instanceof f3)
1461  assertFalse(p1 instanceof Object)
1462  assertFalse(p1 instanceof f0)
1463  assertFalse(p1 instanceof f1)
1464  assertFalse(p1 instanceof f2)
1465  assertFalse(p1 instanceof f3)
1466  assertTrue(p2 instanceof Object)
1467  assertTrue(p2 instanceof f0)
1468  assertFalse(p2 instanceof f1)
1469  assertFalse(p2 instanceof f2)
1470  assertFalse(p2 instanceof f3)
1471  assertTrue(p3 instanceof Object)
1472  assertTrue(p3 instanceof f0)
1473  assertFalse(p3 instanceof f1)
1474  assertTrue(p3 instanceof f2)
1475  assertFalse(p3 instanceof f3)
1476  assertTrue(o2 instanceof Object)
1477  assertTrue(o2 instanceof f0)
1478  assertFalse(o2 instanceof f1)
1479  assertTrue(o2 instanceof f2)
1480  assertFalse(o2 instanceof f3)
1481
1482  var f = Proxy.createFunction({}, function() {})
1483  assertTrue(f instanceof Function)
1484}
1485
1486TestProxyInstanceof()
1487
1488
1489function TestInstanceofProxy() {
1490  var o0 = Object.create(null)
1491  var o1 = {}
1492  var o2 = Object.create(o0)
1493  var o3 = Object.create(o1)
1494  var o4 = Object.create(o2)
1495  var o5 = Object.create(o3)
1496
1497  function handler(o) { return {get: function() { return o } } }
1498  var f0 = Proxy.createFunction(handler(o0), function() {})
1499  var f1 = Proxy.createFunction(handler(o1), function() {})
1500  var f2 = Proxy.createFunction(handler(o2), function() {})
1501  var f3 = Proxy.createFunction(handler(o3), function() {})
1502  var f4 = Proxy.createFunction(handler(o4), function() {})
1503  var f5 = Proxy.createFunction(handler(o4), function() {})
1504
1505  assertFalse(null instanceof f0)
1506  assertFalse(o0 instanceof f0)
1507  assertFalse(o0 instanceof f1)
1508  assertFalse(o0 instanceof f2)
1509  assertFalse(o0 instanceof f3)
1510  assertFalse(o0 instanceof f4)
1511  assertFalse(o0 instanceof f5)
1512  assertFalse(o1 instanceof f0)
1513  assertFalse(o1 instanceof f1)
1514  assertFalse(o1 instanceof f2)
1515  assertFalse(o1 instanceof f3)
1516  assertFalse(o1 instanceof f4)
1517  assertFalse(o1 instanceof f5)
1518  assertTrue(o2 instanceof f0)
1519  assertFalse(o2 instanceof f1)
1520  assertFalse(o2 instanceof f2)
1521  assertFalse(o2 instanceof f3)
1522  assertFalse(o2 instanceof f4)
1523  assertFalse(o2 instanceof f5)
1524  assertFalse(o3 instanceof f0)
1525  assertTrue(o3 instanceof f1)
1526  assertFalse(o3 instanceof f2)
1527  assertFalse(o3 instanceof f3)
1528  assertFalse(o3 instanceof f4)
1529  assertFalse(o3 instanceof f5)
1530  assertTrue(o4 instanceof f0)
1531  assertFalse(o4 instanceof f1)
1532  assertTrue(o4 instanceof f2)
1533  assertFalse(o4 instanceof f3)
1534  assertFalse(o4 instanceof f4)
1535  assertFalse(o4 instanceof f5)
1536  assertFalse(o5 instanceof f0)
1537  assertTrue(o5 instanceof f1)
1538  assertFalse(o5 instanceof f2)
1539  assertTrue(o5 instanceof f3)
1540  assertFalse(o5 instanceof f4)
1541  assertFalse(o5 instanceof f5)
1542
1543  var f = Proxy.createFunction({}, function() {})
1544  var ff = Proxy.createFunction(handler(Function), function() {})
1545  assertTrue(f instanceof Function)
1546  assertFalse(f instanceof ff)
1547}
1548
1549TestInstanceofProxy()
1550
1551
1552
1553// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
1554
1555function TestPrototype() {
1556  var o1 = {}
1557  var p1 = Proxy.create({})
1558  var p2 = Proxy.create({}, o1)
1559  var p3 = Proxy.create({}, p2)
1560  var p4 = Proxy.create({}, null)
1561  var o2 = Object.create(p3)
1562
1563  assertSame(Object.getPrototypeOf(o1), Object.prototype)
1564  assertSame(Object.getPrototypeOf(p1), null)
1565  assertSame(Object.getPrototypeOf(p2), o1)
1566  assertSame(Object.getPrototypeOf(p3), p2)
1567  assertSame(Object.getPrototypeOf(p4), null)
1568  assertSame(Object.getPrototypeOf(o2), p3)
1569
1570  assertTrue(Object.prototype.isPrototypeOf(o1))
1571  assertFalse(Object.prototype.isPrototypeOf(p1))
1572  assertTrue(Object.prototype.isPrototypeOf(p2))
1573  assertTrue(Object.prototype.isPrototypeOf(p3))
1574  assertFalse(Object.prototype.isPrototypeOf(p4))
1575  assertTrue(Object.prototype.isPrototypeOf(o2))
1576  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
1577  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
1578  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
1579  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
1580  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4))
1581  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
1582  assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
1583  assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
1584  assertTrue(Object.prototype.isPrototypeOf.call(o1, p2))
1585  assertTrue(Object.prototype.isPrototypeOf.call(o1, p3))
1586  assertFalse(Object.prototype.isPrototypeOf.call(o1, p4))
1587  assertTrue(Object.prototype.isPrototypeOf.call(o1, o2))
1588  assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
1589  assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
1590  assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
1591  assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
1592  assertFalse(Object.prototype.isPrototypeOf.call(p1, p4))
1593  assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
1594  assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
1595  assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
1596  assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
1597  assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
1598  assertTrue(Object.prototype.isPrototypeOf.call(p2, o2))
1599  assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
1600  assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
1601  assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
1602  assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
1603  assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
1604  assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
1605  assertFalse(Object.prototype.isPrototypeOf.call(o2, p4))
1606  assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
1607
1608  var f = Proxy.createFunction({}, function() {})
1609  assertSame(Object.getPrototypeOf(f), Function.prototype)
1610  assertTrue(Object.prototype.isPrototypeOf(f))
1611  assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
1612}
1613
1614TestPrototype()
1615
1616
1617
1618// Property names (Object.getOwnPropertyNames, Object.keys).
1619
1620function TestPropertyNames(names, handler) {
1621  TestWithProxies(TestPropertyNames2, handler, names)
1622}
1623
1624function TestPropertyNames2(create, handler, names) {
1625  var p = create(handler)
1626  assertArrayEquals(names, Object.getOwnPropertyNames(p))
1627}
1628
1629TestPropertyNames([], {
1630  getOwnPropertyNames: function() { return [] }
1631})
1632
1633TestPropertyNames(["a", "zz", " ", "0"], {
1634  getOwnPropertyNames: function() { return ["a", "zz", " ", 0] }
1635})
1636
1637TestPropertyNames(["throw", "function "], {
1638  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1639  getOwnPropertyNames2: function() { return ["throw", "function "] }
1640})
1641
1642TestPropertyNames(["[object Object]"], {
1643  get getOwnPropertyNames() {
1644    return function() { return [{}] }
1645  }
1646})
1647
1648
1649function TestPropertyNamesThrow(handler) {
1650  TestWithProxies(TestPropertyNamesThrow2, handler)
1651}
1652
1653function TestPropertyNamesThrow2(create, handler) {
1654  var p = create(handler)
1655  assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn")
1656}
1657
1658TestPropertyNamesThrow({
1659  getOwnPropertyNames: function() { throw "myexn" }
1660})
1661
1662TestPropertyNamesThrow({
1663  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1664  getOwnPropertyNames2: function() { throw "myexn" }
1665})
1666
1667
1668function TestKeys(names, handler) {
1669  TestWithProxies(TestKeys2, handler, names)
1670}
1671
1672function TestKeys2(create, handler, names) {
1673  var p = create(handler)
1674  assertArrayEquals(names, Object.keys(p))
1675}
1676
1677TestKeys([], {
1678  keys: function() { return [] }
1679})
1680
1681TestKeys(["a", "zz", " ", "0"], {
1682  keys: function() { return ["a", "zz", " ", 0] }
1683})
1684
1685TestKeys(["throw", "function "], {
1686  keys: function() { return this.keys2() },
1687  keys2: function() { return ["throw", "function "] }
1688})
1689
1690TestKeys(["[object Object]"], {
1691  get keys() {
1692    return function() { return [{}] }
1693  }
1694})
1695
1696TestKeys(["a", "0"], {
1697  getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
1698  getOwnPropertyDescriptor: function(k) {
1699    return k == "" ? undefined : {enumerable: k.length == 1}
1700  }
1701})
1702
1703TestKeys(["23", "zz", ""], {
1704  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1705  getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] },
1706  getOwnPropertyDescriptor: function(k) {
1707    return this.getOwnPropertyDescriptor2(k)
1708  },
1709  getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} }
1710})
1711
1712TestKeys(["a", "b", "c", "5"], {
1713  get getOwnPropertyNames() {
1714    return function() { return ["0", 4, "a", "b", "c", 5, "ety"] }
1715  },
1716  get getOwnPropertyDescriptor() {
1717    return function(k) {
1718      return k == "ety" ? undefined : {enumerable: k >= "44"}
1719    }
1720  }
1721})
1722
1723TestKeys([], {
1724  get getOwnPropertyNames() {
1725    return function() { return ["a", "b", "c"] }
1726  },
1727  getOwnPropertyDescriptor: function(k) { return {} }
1728})
1729
1730
1731function TestKeysThrow(handler) {
1732  TestWithProxies(TestKeysThrow2, handler)
1733}
1734
1735function TestKeysThrow2(create, handler) {
1736  var p = create(handler)
1737  assertThrows(function(){ Object.keys(p) }, "myexn")
1738}
1739
1740TestKeysThrow({
1741  keys: function() { throw "myexn" }
1742})
1743
1744TestKeysThrow({
1745  keys: function() { return this.keys2() },
1746  keys2: function() { throw "myexn" }
1747})
1748
1749TestKeysThrow({
1750  getOwnPropertyNames: function() { throw "myexn" },
1751  getOwnPropertyDescriptor: function(k) { return true }
1752})
1753
1754TestKeysThrow({
1755  getOwnPropertyNames: function() { return [1, 2] },
1756  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1757})
1758
1759TestKeysThrow({
1760  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1761  getOwnPropertyNames2: function() { throw "myexn" },
1762})
1763
1764TestKeysThrow({
1765  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1766  getOwnPropertyNames2: function() { return [1, 2] },
1767  getOwnPropertyDescriptor: function(k) {
1768    return this.getOwnPropertyDescriptor2(k)
1769  },
1770  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1771})
1772
1773TestKeysThrow({
1774  get getOwnPropertyNames() { throw "myexn" }
1775})
1776
1777TestKeysThrow({
1778  get getOwnPropertyNames() {
1779    return function() { throw "myexn" }
1780  },
1781})
1782
1783TestKeysThrow([], {
1784  get getOwnPropertyNames() {
1785    return function() { return [1, 2] }
1786  },
1787  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1788})
1789
1790
1791
1792// Fixing (Object.freeze, Object.seal, Object.preventExtensions,
1793//         Object.isFrozen, Object.isSealed, Object.isExtensible)
1794
1795function TestFix(names, handler) {
1796  var proto = {p: 77}
1797  var assertFixing = function(o, s, f, e) {
1798    assertEquals(s, Object.isSealed(o))
1799    assertEquals(f, Object.isFrozen(o))
1800    assertEquals(e, Object.isExtensible(o))
1801  }
1802
1803  var p1 = Proxy.create(handler, proto)
1804  assertFixing(p1, false, false, true)
1805  Object.seal(p1)
1806  assertFixing(p1, true, names.length === 0, false)
1807  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort())
1808  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1809                    Object.keys(p1).sort())
1810  assertEquals(proto, Object.getPrototypeOf(p1))
1811  assertEquals(77, p1.p)
1812  for (var n in p1) {
1813    var desc = Object.getOwnPropertyDescriptor(p1, n)
1814    if (desc !== undefined) assertFalse(desc.configurable)
1815  }
1816
1817  var p2 = Proxy.create(handler, proto)
1818  assertFixing(p2, false, false, true)
1819  Object.freeze(p2)
1820  assertFixing(p2, true, true, false)
1821  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort())
1822  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1823                    Object.keys(p2).sort())
1824  assertEquals(proto, Object.getPrototypeOf(p2))
1825  assertEquals(77, p2.p)
1826  for (var n in p2) {
1827    var desc = Object.getOwnPropertyDescriptor(p2, n)
1828    if (desc !== undefined) assertFalse(desc.writable)
1829    if (desc !== undefined) assertFalse(desc.configurable)
1830  }
1831
1832  var p3 = Proxy.create(handler, proto)
1833  assertFixing(p3, false, false, true)
1834  Object.preventExtensions(p3)
1835  assertFixing(p3, names.length === 0, names.length === 0, false)
1836  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort())
1837  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1838                    Object.keys(p3).sort())
1839  assertEquals(proto, Object.getPrototypeOf(p3))
1840  assertEquals(77, p3.p)
1841
1842  var p = Proxy.create(handler, proto)
1843  var o = Object.create(p)
1844  assertFixing(p, false, false, true)
1845  assertFixing(o, false, false, true)
1846  Object.freeze(o)
1847  assertFixing(p, false, false, true)
1848  assertFixing(o, true, true, false)
1849}
1850
1851TestFix([], {
1852  fix: function() { return {} }
1853})
1854
1855TestFix(["a", "b", "c", "3", "zz"], {
1856  fix: function() {
1857    return {
1858      a: {value: "a", writable: true, configurable: false, enumerable: true},
1859      b: {value: 33, writable: false, configurable: false, enumerable: true},
1860      c: {value: 0, writable: true, configurable: true, enumerable: true},
1861      '3': {value: true, writable: false, configurable: true, enumerable: true},
1862      zz: {value: 0, enumerable: false}
1863    }
1864  }
1865})
1866
1867TestFix(["a"], {
1868  fix: function() { return this.fix2() },
1869  fix2: function() {
1870    return {a: {value: 4, writable: true, configurable: true, enumerable: true}}
1871  }
1872})
1873
1874TestFix(["b"], {
1875  get fix() {
1876    return function() {
1877      return {b: {configurable: true, writable: true, enumerable: true}}
1878    }
1879  }
1880})
1881
1882
1883function TestFixFunction(fix) {
1884  var f1 = Proxy.createFunction({
1885    fix: function() { return {} }
1886  }, function() {})
1887  fix(f1)
1888  assertEquals(0, f1.length)
1889
1890  var f2 = Proxy.createFunction({
1891    fix: function() { return {length: {value: 3}} }
1892  }, function() {})
1893  fix(f2)
1894  assertEquals(3, f2.length)
1895
1896  var f3 = Proxy.createFunction({
1897    fix: function() { return {length: {value: "huh"}} }
1898  }, function() {})
1899  fix(f3)
1900  assertEquals(0, f1.length)
1901}
1902
1903TestFixFunction(Object.seal)
1904TestFixFunction(Object.freeze)
1905TestFixFunction(Object.preventExtensions)
1906
1907
1908function TestFixThrow(handler) {
1909  TestWithProxies(TestFixThrow2, handler)
1910}
1911
1912function TestFixThrow2(create, handler) {
1913  var p = create(handler, {})
1914  assertThrows(function(){ Object.seal(p) }, "myexn")
1915  assertThrows(function(){ Object.freeze(p) }, "myexn")
1916  assertThrows(function(){ Object.preventExtensions(p) }, "myexn")
1917}
1918
1919TestFixThrow({
1920  fix: function() { throw "myexn" }
1921})
1922
1923TestFixThrow({
1924  fix: function() { return this.fix2() },
1925  fix2: function() { throw "myexn" }
1926})
1927
1928TestFixThrow({
1929  get fix() { throw "myexn" }
1930})
1931
1932TestFixThrow({
1933  get fix() {
1934    return function() { throw "myexn" }
1935  }
1936})
1937
1938
1939// Freeze a proxy in the middle of operations on it.
1940// TODO(rossberg): actual behaviour not specified consistently at the moment,
1941// just make sure that we do not crash.
1942function TestReentrantFix(f) {
1943  TestWithProxies(f, Object.freeze)
1944  TestWithProxies(f, Object.seal)
1945  TestWithProxies(f, Object.preventExtensions)
1946}
1947
1948TestReentrantFix(function(create, freeze) {
1949  var handler = {
1950    get get() { freeze(p); return undefined },
1951    fix: function() { return {} }
1952  }
1953  var p = create(handler)
1954  // Freeze while getting get trap.
1955  try { p.x } catch (e) { assertInstanceof(e, Error) }
1956})
1957
1958TestReentrantFix(function(create, freeze) {
1959  var handler = {
1960    get: function() { freeze(p); return 3 },
1961    fix: function() { return {} }
1962  }
1963  var p = create(handler)
1964  // Freeze while executing get trap.
1965  try { p.x } catch (e) { assertInstanceof(e, Error) }
1966})
1967
1968TestReentrantFix(function(create, freeze) {
1969  var handler = {
1970    getPropertyDescriptor: function() { freeze(p); return undefined },
1971    fix: function() { return {} }
1972  }
1973  var p = create(handler)
1974  // Freeze while executing default get trap.
1975  try { p.x } catch (e) { assertInstanceof(e, Error) }
1976})
1977
1978TestReentrantFix(function(create, freeze) {
1979  var handler = {
1980    getPropertyDescriptor: function() { freeze(p); return {get: function(){}} },
1981    fix: function() { return {} }
1982  }
1983  var p = create(handler)
1984  var o = Object.create(p)
1985  // Freeze while getting a property from prototype.
1986  try { o.x } catch (e) { assertInstanceof(e, Error) }
1987})
1988
1989TestReentrantFix(function(create, freeze) {
1990  var handler = {
1991    get set() { freeze(p); return undefined },
1992    fix: function() { return {} }
1993  }
1994  var p = create(handler)
1995  // Freeze while getting set trap.
1996  try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
1997})
1998
1999TestReentrantFix(function(create, freeze) {
2000  var handler = {
2001    set: function() { freeze(p); return true },
2002    fix: function() { return {} }
2003  }
2004  var p = create(handler)
2005  // Freeze while executing set trap.
2006  try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
2007})
2008
2009TestReentrantFix(function(create, freeze) {
2010  var handler = {
2011    getOwnPropertyDescriptor: function() { freeze(p); return undefined },
2012    fix: function() { return {} }
2013  }
2014  var p = create(handler)
2015  // Freeze while executing default set trap.
2016  try { p.x } catch (e) { assertInstanceof(e, Error) }
2017})
2018
2019TestReentrantFix(function(create, freeze) {
2020  var handler = {
2021    getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
2022    fix: function() { return {} }
2023  }
2024  var p = create(handler)
2025  var o = Object.create(p)
2026  // Freeze while setting a property in prototype, dropping the property!
2027  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
2028})
2029
2030TestReentrantFix(function(create, freeze) {
2031  var handler = {
2032    getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
2033    fix: function() { return {x: {get: function(){}}} }
2034  }
2035  var p = create(handler)
2036  var o = Object.create(p)
2037  // Freeze while setting a property in prototype, making it read-only!
2038  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
2039})
2040
2041TestReentrantFix(function(create, freeze) {
2042  var handler = {
2043    get fix() { freeze(p); return function(){} }
2044  }
2045  var p = create(handler)
2046  // Freeze while getting fix trap.
2047  try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
2048  p = create(handler)
2049  try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
2050  p = create(handler)
2051  try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
2052})
2053
2054TestReentrantFix(function(create, freeze) {
2055  var handler = {
2056    fix: function() { freeze(p); return {} }
2057  }
2058  var p = create(handler)
2059  // Freeze while executing fix trap.
2060  try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
2061  p = create(handler)
2062  try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
2063  p = create(handler)
2064  try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
2065})
2066
2067
2068
2069// String conversion (Object.prototype.toString,
2070//                    Object.prototype.toLocaleString,
2071//                    Function.prototype.toString)
2072
2073var key
2074
2075function TestToString(handler) {
2076  var p = Proxy.create(handler)
2077  key = ""
2078  assertEquals("[object Object]", Object.prototype.toString.call(p))
2079  assertEquals("", key)
2080  assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
2081  assertEquals("toString", key)
2082
2083  var f = Proxy.createFunction(handler, function() {})
2084  key = ""
2085  assertEquals("[object Function]", Object.prototype.toString.call(f))
2086  assertEquals("", key)
2087  assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
2088  assertEquals("toString", key)
2089  assertDoesNotThrow(function(){ Function.prototype.toString.call(f) })
2090
2091  var o = Object.create(p)
2092  key = ""
2093  assertEquals("[object Object]", Object.prototype.toString.call(o))
2094  assertEquals("", key)
2095  assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
2096  assertEquals("toString", key)
2097}
2098
2099TestToString({
2100  get: function(r, k) { key = k; return function() { return "my_proxy" } }
2101})
2102
2103TestToString({
2104  get: function(r, k) { return this.get2(r, k) },
2105  get2: function(r, k) { key = k; return function() { return "my_proxy" } }
2106})
2107
2108TestToString(Proxy.create({
2109  get: function(pr, pk) {
2110    return function(r, k) { key = k; return function() { return "my_proxy" } }
2111  }
2112}))
2113
2114
2115function TestToStringThrow(handler) {
2116  var p = Proxy.create(handler)
2117  assertEquals("[object Object]", Object.prototype.toString.call(p))
2118  assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn")
2119
2120  var f = Proxy.createFunction(handler, function() {})
2121  assertEquals("[object Function]", Object.prototype.toString.call(f))
2122  assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn")
2123
2124  var o = Object.create(p)
2125  assertEquals("[object Object]", Object.prototype.toString.call(o))
2126  assertThrows(function(){ Object.prototype.toLocaleString.call(o) }, "myexn")
2127}
2128
2129TestToStringThrow({
2130  get: function(r, k) { throw "myexn" }
2131})
2132
2133TestToStringThrow({
2134  get: function(r, k) { return function() { throw "myexn" } }
2135})
2136
2137TestToStringThrow({
2138  get: function(r, k) { return this.get2(r, k) },
2139  get2: function(r, k) { throw "myexn" }
2140})
2141
2142TestToStringThrow(Proxy.create({
2143  get: function(pr, pk) { throw "myexn" }
2144}))
2145
2146TestToStringThrow(Proxy.create({
2147  get: function(pr, pk) {
2148    return function(r, k) { throw "myexn" }
2149  }
2150}))
2151
2152
2153
2154// Value conversion (Object.prototype.toValue)
2155
2156function TestValueOf(handler) {
2157  TestWithProxies(TestValueOf2, handler)
2158}
2159
2160function TestValueOf2(create, handler) {
2161  var p = create(handler)
2162  assertSame(p, Object.prototype.valueOf.call(p))
2163}
2164
2165TestValueOf({})
2166
2167
2168
2169// Enumerability (Object.prototype.propertyIsEnumerable)
2170
2171var key
2172
2173function TestIsEnumerable(handler) {
2174  TestWithProxies(TestIsEnumerable2, handler)
2175}
2176
2177function TestIsEnumerable2(create, handler) {
2178  var p = create(handler)
2179  assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
2180  assertEquals("a", key)
2181  assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
2182  assertEquals("2", key)
2183  assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
2184  assertEquals("z", key)
2185
2186  var o = Object.create(p)
2187  key = ""
2188  assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
2189  assertEquals("", key)  // trap not invoked
2190}
2191
2192TestIsEnumerable({
2193  getOwnPropertyDescriptor: function(k) {
2194    key = k; return {enumerable: k < "z", configurable: true}
2195  },
2196})
2197
2198TestIsEnumerable({
2199  getOwnPropertyDescriptor: function(k) {
2200    return this.getOwnPropertyDescriptor2(k)
2201  },
2202  getOwnPropertyDescriptor2: function(k) {
2203    key = k; return {enumerable: k < "z", configurable: true}
2204  },
2205})
2206
2207TestIsEnumerable({
2208  getOwnPropertyDescriptor: function(k) {
2209    key = k; return {get enumerable() { return k < "z" }, configurable: true}
2210  },
2211})
2212
2213TestIsEnumerable(Proxy.create({
2214  get: function(pr, pk) {
2215    return function(k) {
2216      key = k; return {enumerable: k < "z", configurable: true}
2217    }
2218  }
2219}))
2220
2221
2222function TestIsEnumerableThrow(handler) {
2223  TestWithProxies(TestIsEnumerableThrow2, handler)
2224}
2225
2226function TestIsEnumerableThrow2(create, handler) {
2227  var p = create(handler)
2228  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") },
2229    "myexn")
2230  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) },
2231    "myexn")
2232}
2233
2234TestIsEnumerableThrow({
2235  getOwnPropertyDescriptor: function(k) { throw "myexn" }
2236})
2237
2238TestIsEnumerableThrow({
2239  getOwnPropertyDescriptor: function(k) {
2240    return this.getOwnPropertyDescriptor2(k)
2241  },
2242  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
2243})
2244
2245TestIsEnumerableThrow({
2246  getOwnPropertyDescriptor: function(k) {
2247    return {get enumerable() { throw "myexn" }, configurable: true}
2248  },
2249})
2250
2251TestIsEnumerableThrow(Proxy.create({
2252  get: function(pr, pk) { throw "myexn" }
2253}))
2254
2255TestIsEnumerableThrow(Proxy.create({
2256  get: function(pr, pk) {
2257    return function(k) { throw "myexn" }
2258  }
2259}))
2260
2261
2262
2263// Constructor functions with proxy prototypes.
2264
2265function TestConstructorWithProxyPrototype() {
2266  TestWithProxies(TestConstructorWithProxyPrototype2, {})
2267}
2268
2269function TestConstructorWithProxyPrototype2(create, handler) {
2270  function C() {};
2271  C.prototype = create(handler);
2272
2273  var o = new C;
2274  assertSame(C.prototype, o.__proto__);
2275  assertSame(C.prototype, Object.getPrototypeOf(o));
2276}
2277
2278TestConstructorWithProxyPrototype();
2279