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 rec
576var key
577var val
578
579function TestSetForDerived(trap) {
580  TestWithProxies(TestSetForDerived2, trap)
581}
582
583function TestSetForDerived2(create, trap) {
584  var p = create({getPropertyDescriptor: trap, getOwnPropertyDescriptor: trap})
585  var o = Object.create(p, {x: {value: 88, writable: true},
586                            '1': {value: 89, writable: true}})
587
588  key = ""
589  assertEquals(48, o.x = 48)
590  assertEquals("", key)  // trap not invoked
591  assertEquals(48, o.x)
592
593  assertEquals(47, o[1] = 47)
594  assertEquals("", key)  // trap not invoked
595  assertEquals(47, o[1])
596
597  assertEquals(49, o.y = 49)
598  assertEquals("y", key)
599  assertEquals(49, o.y)
600
601  assertEquals(50, o[2] = 50)
602  assertEquals("2", key)
603  assertEquals(50, o[2])
604
605  assertEquals(44, o.p_writable = 44)
606  assertEquals("p_writable", key)
607  assertEquals(44, o.p_writable)
608
609  assertEquals(45, o.p_nonwritable = 45)
610  assertEquals("p_nonwritable", key)
611  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonwritable"))
612
613  assertThrows(function(){ "use strict"; o.p_nonwritable = 45 }, TypeError)
614  assertEquals("p_nonwritable", key)
615  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonwritable"))
616
617  val = ""
618  assertEquals(46, o.p_setter = 46)
619  assertEquals("p_setter", key)
620  assertSame(o, rec)
621  assertEquals(46, val)  // written to parent
622  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter"))
623
624  val = ""
625  assertEquals(47, o.p_nosetter = 47)
626  assertEquals("p_nosetter", key)
627  assertEquals("", val)  // not written at all
628  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter"));
629
630  key = ""
631  assertThrows(function(){ "use strict"; o.p_nosetter = 50 }, TypeError)
632  assertEquals("p_nosetter", key)
633  assertEquals("", val)  // not written at all
634  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nosetter"));
635
636  assertThrows(function(){ o.p_nonconf = 53 }, TypeError)
637  assertEquals("p_nonconf", key)
638  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_nonconf"));
639
640  assertThrows(function(){ o.p_throw = 51 }, "myexn")
641  assertEquals("p_throw", key)
642  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_throw"));
643
644  assertThrows(function(){ o.p_setterthrow = 52 }, "myexn")
645  assertEquals("p_setterthrow", key)
646  assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setterthrow"));
647}
648
649
650TestSetForDerived(
651  function(k) {
652    // TODO(yangguo): issue 2398 - throwing an error causes formatting of
653    // the message string, which can be observable through this handler.
654    // We ignore keys that occur when formatting the message string.
655    if (k == "toString" || k == "valueOf") return;
656
657    key = k;
658    switch (k) {
659      case "p_writable": return {writable: true, configurable: true}
660      case "p_nonwritable": return {writable: false, configurable: true}
661      case "p_setter": return {
662        set: function(x) { rec = this; val = x },
663        configurable: true
664      }
665      case "p_nosetter": return {
666        get: function() { return 1 },
667        configurable: true
668      }
669      case "p_nonconf": return {}
670      case "p_throw": throw "myexn"
671      case "p_setterthrow": return {set: function(x) { throw "myexn" }}
672      default: return undefined
673    }
674  }
675)
676
677
678// Evil proxy-induced side-effects shouldn't crash.
679// TODO(rossberg): proper behaviour isn't really spec'ed yet, so ignore results.
680
681TestWithProxies(function(create) {
682  var calls = 0
683  var handler = {
684    getPropertyDescriptor: function() {
685      ++calls
686      return (calls % 2 == 1)
687        ? {get: function() { return 5 }, configurable: true}
688        : {set: function() { return false }, configurable: true}
689    }
690  }
691  var p = create(handler)
692  var o = Object.create(p)
693  // Make proxy prototype property read-only after CanPut check.
694  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
695})
696
697TestWithProxies(function(create) {
698  var handler = {
699    getPropertyDescriptor: function() {
700      Object.defineProperty(o, "x", {get: function() { return 5 }});
701      return {set: function() {}}
702    }
703  }
704  var p = create(handler)
705  var o = Object.create(p)
706  // Make object property read-only after CanPut check.
707  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
708})
709
710
711
712// TODO(rossberg): TestSetReject, returning false
713// TODO(rossberg): TestGetProperty, TestSetProperty
714
715
716
717// Property definition (Object.defineProperty and Object.defineProperties).
718
719var key
720var desc
721
722function TestDefine(handler) {
723  TestWithProxies(TestDefine2, handler)
724}
725
726function TestDefine2(create, handler) {
727  var p = create(handler)
728  assertEquals(p, Object.defineProperty(p, "a", {value: 44}))
729  assertEquals("a", key)
730  assertEquals(1, Object.getOwnPropertyNames(desc).length)
731  assertEquals(44, desc.value)
732
733  assertEquals(p, Object.defineProperty(p, "b", {value: 45, writable: false}))
734  assertEquals("b", key)
735  assertEquals(2, Object.getOwnPropertyNames(desc).length)
736  assertEquals(45, desc.value)
737  assertEquals(false, desc.writable)
738
739  assertEquals(p, Object.defineProperty(p, "c", {value: 46, enumerable: false}))
740  assertEquals("c", key)
741  assertEquals(2, Object.getOwnPropertyNames(desc).length)
742  assertEquals(46, desc.value)
743  assertEquals(false, desc.enumerable)
744
745  assertEquals(p, Object.defineProperty(p, 101, {value: 47, enumerable: false}))
746  assertEquals("101", key)
747  assertEquals(2, Object.getOwnPropertyNames(desc).length)
748  assertEquals(47, desc.value)
749  assertEquals(false, desc.enumerable)
750
751  var attributes = {configurable: true, mine: 66, minetoo: 23}
752  assertEquals(p, Object.defineProperty(p, "d", attributes))
753  assertEquals("d", key)
754  // Modifying the attributes object after the fact should have no effect.
755  attributes.configurable = false
756  attributes.mine = 77
757  delete attributes.minetoo
758  assertEquals(3, Object.getOwnPropertyNames(desc).length)
759  assertEquals(true, desc.configurable)
760  assertEquals(66, desc.mine)
761  assertEquals(23, desc.minetoo)
762
763  assertEquals(p, Object.defineProperty(p, "e", {get: function(){ return 5 }}))
764  assertEquals("e", key)
765  assertEquals(1, Object.getOwnPropertyNames(desc).length)
766  assertEquals(5, desc.get())
767
768  assertEquals(p, Object.defineProperty(p, "zzz", {}))
769  assertEquals("zzz", key)
770  assertEquals(0, Object.getOwnPropertyNames(desc).length)
771
772  var d = create({
773    get: function(r, k) { return (k === "value") ? 77 : void 0 },
774    getOwnPropertyNames: function() { return ["value"] },
775    enumerate: function() { return ["value"] }
776  })
777  assertEquals(1, Object.getOwnPropertyNames(d).length)
778  assertEquals(77, d.value)
779  assertEquals(p, Object.defineProperty(p, "p", d))
780  assertEquals("p", key)
781  assertEquals(1, Object.getOwnPropertyNames(desc).length)
782  assertEquals(77, desc.value)
783
784  var props = {
785    '11': {},
786    blub: {get: function() { return true }},
787    '': {get value() { return 20 }},
788    last: {value: 21, configurable: true, mine: "eyes"}
789  }
790  Object.defineProperty(props, "hidden", {value: "hidden", enumerable: false})
791  assertEquals(p, Object.defineProperties(p, props))
792  assertEquals("last", key)
793  assertEquals(2, Object.getOwnPropertyNames(desc).length)
794  assertEquals(21, desc.value)
795  assertEquals(true, desc.configurable)
796  assertEquals(undefined, desc.mine)  // Arguably a bug in the spec...
797
798  var props = {bla: {get value() { throw "myexn" }}}
799  assertThrows(function(){ Object.defineProperties(p, props) }, "myexn")
800}
801
802TestDefine({
803  defineProperty: function(k, d) { key = k; desc = d; return true }
804})
805
806TestDefine({
807  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
808  defineProperty2: function(k, d) { key = k; desc = d; return true }
809})
810
811TestDefine(Proxy.create({
812  get: function(pr, pk) {
813    return function(k, d) { key = k; desc = d; return true }
814  }
815}))
816
817
818function TestDefineThrow(handler) {
819  TestWithProxies(TestDefineThrow2, handler)
820}
821
822function TestDefineThrow2(create, handler) {
823  var p = create(handler)
824  assertThrows(function(){ Object.defineProperty(p, "a", {value: 44})}, "myexn")
825  assertThrows(function(){ Object.defineProperty(p, 0, {value: 44})}, "myexn")
826
827  var d1 = create({
828    get: function(r, k) { throw "myexn" },
829    getOwnPropertyNames: function() { return ["value"] }
830  })
831  assertThrows(function(){ Object.defineProperty(p, "p", d1) }, "myexn")
832  var d2 = create({
833    get: function(r, k) { return 77 },
834    getOwnPropertyNames: function() { throw "myexn" }
835  })
836  assertThrows(function(){ Object.defineProperty(p, "p", d2) }, "myexn")
837
838  var props = {bla: {get value() { throw "otherexn" }}}
839  assertThrows(function(){ Object.defineProperties(p, props) }, "otherexn")
840}
841
842TestDefineThrow({
843  defineProperty: function(k, d) { throw "myexn" }
844})
845
846TestDefineThrow({
847  defineProperty: function(k, d) { return this.defineProperty2(k, d) },
848  defineProperty2: function(k, d) { throw "myexn" }
849})
850
851TestDefineThrow(Proxy.create({
852  get: function(pr, pk) { throw "myexn" }
853}))
854
855TestDefineThrow(Proxy.create({
856  get: function(pr, pk) {
857    return function(k, d) { throw "myexn" }
858  }
859}))
860
861
862
863// Property deletion (delete).
864
865var key
866
867function TestDelete(handler) {
868  TestWithProxies(TestDelete2, handler)
869}
870
871function TestDelete2(create, handler) {
872  var p = create(handler)
873  assertEquals(true, delete p.a)
874  assertEquals("a", key)
875  assertEquals(true, delete p["b"])
876  assertEquals("b", key)
877  assertEquals(true, delete p[1])
878  assertEquals("1", key)
879
880  assertEquals(false, delete p.z1)
881  assertEquals("z1", key)
882  assertEquals(false, delete p["z2"])
883  assertEquals("z2", key);
884
885  (function() {
886    "use strict"
887    assertEquals(true, delete p.c)
888    assertEquals("c", key)
889    assertEquals(true, delete p["d"])
890    assertEquals("d", key)
891    assertEquals(true, delete p[2])
892    assertEquals("2", key)
893
894    assertThrows(function(){ delete p.z3 }, TypeError)
895    assertEquals("z3", key)
896    assertThrows(function(){ delete p["z4"] }, TypeError)
897    assertEquals("z4", key)
898  })()
899}
900
901TestDelete({
902  delete: function(k) { key = k; return k < "z" }
903})
904
905TestDelete({
906  delete: function(k) { return this.delete2(k) },
907  delete2: function(k) { key = k; return k < "z" }
908})
909
910TestDelete(Proxy.create({
911  get: function(pr, pk) {
912    return function(k) { key = k; return k < "z" }
913  }
914}))
915
916
917function TestDeleteThrow(handler) {
918  TestWithProxies(TestDeleteThrow2, handler)
919}
920
921function TestDeleteThrow2(create, handler) {
922  var p = create(handler)
923  assertThrows(function(){ delete p.a }, "myexn")
924  assertThrows(function(){ delete p["b"] }, "myexn");
925  assertThrows(function(){ delete p[3] }, "myexn");
926
927  (function() {
928    "use strict"
929    assertThrows(function(){ delete p.c }, "myexn")
930    assertThrows(function(){ delete p["d"] }, "myexn")
931    assertThrows(function(){ delete p[4] }, "myexn");
932  })()
933}
934
935TestDeleteThrow({
936  delete: function(k) { throw "myexn" }
937})
938
939TestDeleteThrow({
940  delete: function(k) { return this.delete2(k) },
941  delete2: function(k) { throw "myexn" }
942})
943
944TestDeleteThrow(Proxy.create({
945  get: function(pr, pk) { throw "myexn" }
946}))
947
948TestDeleteThrow(Proxy.create({
949  get: function(pr, pk) {
950    return function(k) { throw "myexn" }
951  }
952}))
953
954
955
956// Property descriptors (Object.getOwnPropertyDescriptor).
957
958function TestDescriptor(handler) {
959  TestWithProxies(TestDescriptor2, handler)
960}
961
962function TestDescriptor2(create, handler) {
963  var p = create(handler)
964  var descs = [
965    {configurable: true},
966    {value: 34, enumerable: true, configurable: true},
967    {value: 3, writable: false, mine: "eyes", configurable: true},
968    {get value() { return 20 }, get configurable() { return true }},
969    {get: function() { "get" }, set: function() { "set" }, configurable: true}
970  ]
971  for (var i = 0; i < descs.length; ++i) {
972    assertEquals(p, Object.defineProperty(p, i, descs[i]))
973    var desc = Object.getOwnPropertyDescriptor(p, i)
974    for (prop in descs[i]) {
975      // TODO(rossberg): Ignore user attributes as long as the spec isn't
976      // fixed suitably.
977      if (prop != "mine") assertEquals(descs[i][prop], desc[prop])
978    }
979    assertEquals(undefined, Object.getOwnPropertyDescriptor(p, "absent"))
980  }
981}
982
983TestDescriptor({
984  defineProperty: function(k, d) { this["__" + k] = d; return true },
985  getOwnPropertyDescriptor: function(k) { return this["__" + k] }
986})
987
988TestDescriptor({
989  defineProperty: function(k, d) { this["__" + k] = d; return true },
990  getOwnPropertyDescriptor: function(k) {
991    return this.getOwnPropertyDescriptor2(k)
992  },
993  getOwnPropertyDescriptor2: function(k) { return this["__" + k] }
994})
995
996
997function TestDescriptorThrow(handler) {
998  TestWithProxies(TestDescriptorThrow2, handler)
999}
1000
1001function TestDescriptorThrow2(create, handler) {
1002  var p = create(handler)
1003  assertThrows(function(){ Object.getOwnPropertyDescriptor(p, "a") }, "myexn")
1004}
1005
1006TestDescriptorThrow({
1007  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1008})
1009
1010TestDescriptorThrow({
1011  getOwnPropertyDescriptor: function(k) {
1012    return this.getOwnPropertyDescriptor2(k)
1013  },
1014  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1015})
1016
1017
1018
1019// Comparison.
1020
1021function TestComparison(eq) {
1022  TestWithProxies(TestComparison2, eq)
1023}
1024
1025function TestComparison2(create, eq) {
1026  var p1 = create({})
1027  var p2 = create({})
1028
1029  assertTrue(eq(p1, p1))
1030  assertTrue(eq(p2, p2))
1031  assertTrue(!eq(p1, p2))
1032  assertTrue(!eq(p1, {}))
1033  assertTrue(!eq({}, p2))
1034  assertTrue(!eq({}, {}))
1035}
1036
1037TestComparison(function(o1, o2) { return o1 == o2 })
1038TestComparison(function(o1, o2) { return o1 === o2 })
1039TestComparison(function(o1, o2) { return !(o1 != o2) })
1040TestComparison(function(o1, o2) { return !(o1 !== o2) })
1041
1042
1043
1044// Type (typeof).
1045
1046function TestTypeof() {
1047  assertEquals("object", typeof Proxy.create({}))
1048  assertTrue(typeof Proxy.create({}) == "object")
1049  assertTrue("object" == typeof Proxy.create({}))
1050
1051  assertEquals("function", typeof Proxy.createFunction({}, function() {}))
1052  assertTrue(typeof Proxy.createFunction({}, function() {}) == "function")
1053  assertTrue("function" == typeof Proxy.createFunction({}, function() {}))
1054}
1055
1056TestTypeof()
1057
1058
1059
1060// Membership test (in).
1061
1062var key
1063
1064function TestIn(handler) {
1065  TestWithProxies(TestIn2, handler)
1066}
1067
1068function TestIn2(create, handler) {
1069  var p = create(handler)
1070  assertTrue("a" in p)
1071  assertEquals("a", key)
1072  assertTrue(99 in p)
1073  assertEquals("99", key)
1074  assertFalse("z" in p)
1075  assertEquals("z", key)
1076
1077  assertEquals(2, ("a" in p) ? 2 : 0)
1078  assertEquals(0, !("a" in p) ? 2 : 0)
1079  assertEquals(0, ("zzz" in p) ? 2 : 0)
1080  assertEquals(2, !("zzz" in p) ? 2 : 0)
1081
1082  // Test compilation in conditionals.
1083  if ("b" in p) {
1084  } else {
1085    assertTrue(false)
1086  }
1087  assertEquals("b", key)
1088
1089  if ("zz" in p) {
1090    assertTrue(false)
1091  }
1092  assertEquals("zz", key)
1093
1094  if (!("c" in p)) {
1095    assertTrue(false)
1096  }
1097  assertEquals("c", key)
1098
1099  if (!("zzz" in p)) {
1100  } else {
1101    assertTrue(false)
1102  }
1103  assertEquals("zzz", key)
1104}
1105
1106TestIn({
1107  has: function(k) { key = k; return k < "z" }
1108})
1109
1110TestIn({
1111  has: function(k) { return this.has2(k) },
1112  has2: function(k) { key = k; return k < "z" }
1113})
1114
1115TestIn({
1116  getPropertyDescriptor: function(k) {
1117    key = k; return k < "z" ? {value: 42} : void 0
1118  }
1119})
1120
1121TestIn({
1122  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1123  getPropertyDescriptor2: function(k) {
1124    key = k; return k < "z" ? {value: 42} : void 0
1125  }
1126})
1127
1128TestIn({
1129  getPropertyDescriptor: function(k) {
1130    key = k; return k < "z" ? {get value() { return 42 }} : void 0
1131  }
1132})
1133
1134TestIn({
1135  has: undefined,
1136  getPropertyDescriptor: function(k) {
1137    key = k; return k < "z" ? {value: 42} : void 0
1138  }
1139})
1140
1141TestIn(Proxy.create({
1142  get: function(pr, pk) {
1143    return function(k) { key = k; return k < "z" }
1144  }
1145}))
1146
1147
1148function TestInThrow(handler) {
1149  TestWithProxies(TestInThrow2, handler)
1150}
1151
1152function TestInThrow2(create, handler) {
1153  var p = create(handler)
1154  assertThrows(function(){ return "a" in o }, "myexn")
1155  assertThrows(function(){ return 99 in o }, "myexn")
1156  assertThrows(function(){ return !("a" in o) }, "myexn")
1157  assertThrows(function(){ return ("a" in o) ? 2 : 3 }, "myexn")
1158  assertThrows(function(){ if ("b" in o) {} }, "myexn")
1159  assertThrows(function(){ if (!("b" in o)) {} }, "myexn")
1160  assertThrows(function(){ if ("zzz" in o) {} }, "myexn")
1161}
1162
1163TestInThrow({
1164  has: function(k) { throw "myexn" }
1165})
1166
1167TestInThrow({
1168  has: function(k) { return this.has2(k) },
1169  has2: function(k) { throw "myexn" }
1170})
1171
1172TestInThrow({
1173  getPropertyDescriptor: function(k) { throw "myexn" }
1174})
1175
1176TestInThrow({
1177  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1178  getPropertyDescriptor2: function(k) { throw "myexn" }
1179})
1180
1181TestInThrow({
1182  has: undefined,
1183  getPropertyDescriptor: function(k) { throw "myexn" }
1184})
1185
1186TestInThrow(Proxy.create({
1187  get: function(pr, pk) { throw "myexn" }
1188}))
1189
1190TestInThrow(Proxy.create({
1191  get: function(pr, pk) {
1192    return function(k) { throw "myexn" }
1193  }
1194}))
1195
1196
1197function TestInForDerived(handler) {
1198  TestWithProxies(TestInForDerived2, handler)
1199}
1200
1201function TestInForDerived2(create, handler) {
1202  var p = create(handler)
1203  var o = Object.create(p)
1204
1205  assertTrue("a" in o)
1206  assertEquals("a", key)
1207  assertTrue(99 in o)
1208  assertEquals("99", key)
1209  assertFalse("z" in o)
1210  assertEquals("z", key)
1211
1212  assertEquals(2, ("a" in o) ? 2 : 0)
1213  assertEquals(0, !("a" in o) ? 2 : 0)
1214  assertEquals(0, ("zzz" in o) ? 2 : 0)
1215  assertEquals(2, !("zzz" in o) ? 2 : 0)
1216
1217  if ("b" in o) {
1218  } else {
1219    assertTrue(false)
1220  }
1221  assertEquals("b", key)
1222
1223  if ("zz" in o) {
1224    assertTrue(false)
1225  }
1226  assertEquals("zz", key)
1227
1228  if (!("c" in o)) {
1229    assertTrue(false)
1230  }
1231  assertEquals("c", key)
1232
1233  if (!("zzz" in o)) {
1234  } else {
1235    assertTrue(false)
1236  }
1237  assertEquals("zzz", key)
1238}
1239
1240TestInForDerived({
1241  getPropertyDescriptor: function(k) {
1242    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1243  }
1244})
1245
1246TestInForDerived({
1247  getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
1248  getPropertyDescriptor2: function(k) {
1249    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1250  }
1251})
1252
1253TestInForDerived({
1254  getPropertyDescriptor: function(k) {
1255    key = k;
1256    return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
1257  }
1258})
1259
1260/* TODO(rossberg): this will work once we implement the newest proposal
1261 * regarding default traps for getPropertyDescriptor.
1262TestInForDerived({
1263  getOwnPropertyDescriptor: function(k) {
1264    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1265  }
1266})
1267
1268TestInForDerived({
1269  getOwnPropertyDescriptor: function(k) {
1270    return this.getOwnPropertyDescriptor2(k)
1271  },
1272  getOwnPropertyDescriptor2: function(k) {
1273    key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1274  }
1275})
1276
1277TestInForDerived({
1278  getOwnPropertyDescriptor: function(k) {
1279    key = k;
1280    return k < "z" ? {get value() { return 42 }, configurable: true} : void 0
1281  }
1282})
1283*/
1284
1285TestInForDerived(Proxy.create({
1286  get: function(pr, pk) {
1287    return function(k) {
1288      key = k; return k < "z" ? {value: 42, configurable: true} : void 0
1289    }
1290  }
1291}))
1292
1293
1294
1295// Property descriptor conversion.
1296
1297var descget
1298
1299function TestDescriptorGetOrder(handler) {
1300  var p = Proxy.create(handler)
1301  var o = Object.create(p, {b: {value: 0}})
1302  TestDescriptorGetOrder2(function(n) { return p[n] }, "vV")
1303  TestDescriptorGetOrder2(function(n) { return n in p }, "")
1304  TestDescriptorGetOrder2(function(n) { return o[n] }, "vV")
1305  TestDescriptorGetOrder2(function(n) { return n in o }, "eEcCvVwWgs")
1306}
1307
1308function TestDescriptorGetOrder2(f, access) {
1309  descget = ""
1310  assertTrue(f("a"))
1311  assertEquals(access, descget)
1312  descget = ""
1313  assertTrue(f(99))
1314  assertEquals(access, descget)
1315  descget = ""
1316  assertFalse(!!f("z"))
1317  assertEquals("", descget)
1318}
1319
1320TestDescriptorGetOrder({
1321  getPropertyDescriptor: function(k) {
1322    if (k >= "z") return void 0
1323    // Return a proxy as property descriptor, so that we can log accesses.
1324    return Proxy.create({
1325      get: function(r, attr) {
1326        descget += attr[0].toUpperCase()
1327        return true
1328      },
1329      has: function(attr) {
1330        descget += attr[0]
1331        switch (attr) {
1332          case "writable":
1333          case "enumerable":
1334          case "configurable":
1335          case "value":
1336            return true
1337          case "get":
1338          case "set":
1339            return false
1340          default:
1341            assertUnreachable()
1342        }
1343      }
1344    })
1345  }
1346})
1347
1348
1349
1350// Own Properties (Object.prototype.hasOwnProperty).
1351
1352var key
1353
1354function TestHasOwn(handler) {
1355  TestWithProxies(TestHasOwn2, handler)
1356}
1357
1358function TestHasOwn2(create, handler) {
1359  var p = create(handler)
1360  assertTrue(Object.prototype.hasOwnProperty.call(p, "a"))
1361  assertEquals("a", key)
1362  assertTrue(Object.prototype.hasOwnProperty.call(p, 99))
1363  assertEquals("99", key)
1364  assertFalse(Object.prototype.hasOwnProperty.call(p, "z"))
1365  assertEquals("z", key)
1366}
1367
1368TestHasOwn({
1369  hasOwn: function(k) { key = k; return k < "z" }
1370})
1371
1372TestHasOwn({
1373  hasOwn: function(k) { return this.hasOwn2(k) },
1374  hasOwn2: function(k) { key = k; return k < "z" }
1375})
1376
1377TestHasOwn({
1378  getOwnPropertyDescriptor: function(k) {
1379    key = k; return k < "z" ? {value: 42} : void 0
1380  }
1381})
1382
1383TestHasOwn({
1384  getOwnPropertyDescriptor: function(k) {
1385    return this.getOwnPropertyDescriptor2(k)
1386  },
1387  getOwnPropertyDescriptor2: function(k) {
1388    key = k; return k < "z" ? {value: 42} : void 0
1389  }
1390})
1391
1392TestHasOwn({
1393  getOwnPropertyDescriptor: function(k) {
1394    key = k; return k < "z" ? {get value() { return 42 }} : void 0
1395  }
1396})
1397
1398TestHasOwn({
1399  hasOwn: undefined,
1400  getOwnPropertyDescriptor: function(k) {
1401    key = k; return k < "z" ? {value: 42} : void 0
1402  }
1403})
1404
1405TestHasOwn(Proxy.create({
1406  get: function(pr, pk) {
1407    return function(k) { key = k; return k < "z" }
1408  }
1409}))
1410
1411
1412function TestHasOwnThrow(handler) {
1413  TestWithProxies(TestHasOwnThrow2, handler)
1414}
1415
1416function TestHasOwnThrow2(create, handler) {
1417  var p = create(handler)
1418  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, "a")},
1419    "myexn")
1420  assertThrows(function(){ Object.prototype.hasOwnProperty.call(p, 99)},
1421    "myexn")
1422}
1423
1424TestHasOwnThrow({
1425  hasOwn: function(k) { throw "myexn" }
1426})
1427
1428TestHasOwnThrow({
1429  hasOwn: function(k) { return this.hasOwn2(k) },
1430  hasOwn2: function(k) { throw "myexn" }
1431})
1432
1433TestHasOwnThrow({
1434  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1435})
1436
1437TestHasOwnThrow({
1438  getOwnPropertyDescriptor: function(k) {
1439    return this.getOwnPropertyDescriptor2(k)
1440  },
1441  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1442})
1443
1444TestHasOwnThrow({
1445  hasOwn: undefined,
1446  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1447})
1448
1449TestHasOwnThrow(Proxy.create({
1450  get: function(pr, pk) { throw "myexn" }
1451}))
1452
1453TestHasOwnThrow(Proxy.create({
1454  get: function(pr, pk) {
1455    return function(k) { throw "myexn" }
1456  }
1457}))
1458
1459
1460
1461// Instanceof (instanceof)
1462
1463function TestProxyInstanceof() {
1464  var o1 = {}
1465  var p1 = Proxy.create({})
1466  var p2 = Proxy.create({}, o1)
1467  var p3 = Proxy.create({}, p2)
1468  var o2 = Object.create(p2)
1469
1470  var f0 = function() {}
1471  f0.prototype = o1
1472  var f1 = function() {}
1473  f1.prototype = p1
1474  var f2 = function() {}
1475  f2.prototype = p2
1476  var f3 = function() {}
1477  f3.prototype = o2
1478
1479  assertTrue(o1 instanceof Object)
1480  assertFalse(o1 instanceof f0)
1481  assertFalse(o1 instanceof f1)
1482  assertFalse(o1 instanceof f2)
1483  assertFalse(o1 instanceof f3)
1484  assertFalse(p1 instanceof Object)
1485  assertFalse(p1 instanceof f0)
1486  assertFalse(p1 instanceof f1)
1487  assertFalse(p1 instanceof f2)
1488  assertFalse(p1 instanceof f3)
1489  assertTrue(p2 instanceof Object)
1490  assertTrue(p2 instanceof f0)
1491  assertFalse(p2 instanceof f1)
1492  assertFalse(p2 instanceof f2)
1493  assertFalse(p2 instanceof f3)
1494  assertTrue(p3 instanceof Object)
1495  assertTrue(p3 instanceof f0)
1496  assertFalse(p3 instanceof f1)
1497  assertTrue(p3 instanceof f2)
1498  assertFalse(p3 instanceof f3)
1499  assertTrue(o2 instanceof Object)
1500  assertTrue(o2 instanceof f0)
1501  assertFalse(o2 instanceof f1)
1502  assertTrue(o2 instanceof f2)
1503  assertFalse(o2 instanceof f3)
1504
1505  var f = Proxy.createFunction({}, function() {})
1506  assertTrue(f instanceof Function)
1507}
1508
1509TestProxyInstanceof()
1510
1511
1512function TestInstanceofProxy() {
1513  var o0 = Object.create(null)
1514  var o1 = {}
1515  var o2 = Object.create(o0)
1516  var o3 = Object.create(o1)
1517  var o4 = Object.create(o2)
1518  var o5 = Object.create(o3)
1519
1520  function handler(o) { return {get: function() { return o } } }
1521  var f0 = Proxy.createFunction(handler(o0), function() {})
1522  var f1 = Proxy.createFunction(handler(o1), function() {})
1523  var f2 = Proxy.createFunction(handler(o2), function() {})
1524  var f3 = Proxy.createFunction(handler(o3), function() {})
1525  var f4 = Proxy.createFunction(handler(o4), function() {})
1526  var f5 = Proxy.createFunction(handler(o4), function() {})
1527
1528  assertFalse(null instanceof f0)
1529  assertFalse(o0 instanceof f0)
1530  assertFalse(o0 instanceof f1)
1531  assertFalse(o0 instanceof f2)
1532  assertFalse(o0 instanceof f3)
1533  assertFalse(o0 instanceof f4)
1534  assertFalse(o0 instanceof f5)
1535  assertFalse(o1 instanceof f0)
1536  assertFalse(o1 instanceof f1)
1537  assertFalse(o1 instanceof f2)
1538  assertFalse(o1 instanceof f3)
1539  assertFalse(o1 instanceof f4)
1540  assertFalse(o1 instanceof f5)
1541  assertTrue(o2 instanceof f0)
1542  assertFalse(o2 instanceof f1)
1543  assertFalse(o2 instanceof f2)
1544  assertFalse(o2 instanceof f3)
1545  assertFalse(o2 instanceof f4)
1546  assertFalse(o2 instanceof f5)
1547  assertFalse(o3 instanceof f0)
1548  assertTrue(o3 instanceof f1)
1549  assertFalse(o3 instanceof f2)
1550  assertFalse(o3 instanceof f3)
1551  assertFalse(o3 instanceof f4)
1552  assertFalse(o3 instanceof f5)
1553  assertTrue(o4 instanceof f0)
1554  assertFalse(o4 instanceof f1)
1555  assertTrue(o4 instanceof f2)
1556  assertFalse(o4 instanceof f3)
1557  assertFalse(o4 instanceof f4)
1558  assertFalse(o4 instanceof f5)
1559  assertFalse(o5 instanceof f0)
1560  assertTrue(o5 instanceof f1)
1561  assertFalse(o5 instanceof f2)
1562  assertTrue(o5 instanceof f3)
1563  assertFalse(o5 instanceof f4)
1564  assertFalse(o5 instanceof f5)
1565
1566  var f = Proxy.createFunction({}, function() {})
1567  var ff = Proxy.createFunction(handler(Function), function() {})
1568  assertTrue(f instanceof Function)
1569  assertFalse(f instanceof ff)
1570}
1571
1572TestInstanceofProxy()
1573
1574
1575
1576// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
1577
1578function TestPrototype() {
1579  var o1 = {}
1580  var p1 = Proxy.create({})
1581  var p2 = Proxy.create({}, o1)
1582  var p3 = Proxy.create({}, p2)
1583  var p4 = Proxy.create({}, null)
1584  var o2 = Object.create(p3)
1585
1586  assertSame(Object.getPrototypeOf(o1), Object.prototype)
1587  assertSame(Object.getPrototypeOf(p1), null)
1588  assertSame(Object.getPrototypeOf(p2), o1)
1589  assertSame(Object.getPrototypeOf(p3), p2)
1590  assertSame(Object.getPrototypeOf(p4), null)
1591  assertSame(Object.getPrototypeOf(o2), p3)
1592
1593  assertTrue(Object.prototype.isPrototypeOf(o1))
1594  assertFalse(Object.prototype.isPrototypeOf(p1))
1595  assertTrue(Object.prototype.isPrototypeOf(p2))
1596  assertTrue(Object.prototype.isPrototypeOf(p3))
1597  assertFalse(Object.prototype.isPrototypeOf(p4))
1598  assertTrue(Object.prototype.isPrototypeOf(o2))
1599  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o1))
1600  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
1601  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
1602  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
1603  assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4))
1604  assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o2))
1605  assertFalse(Object.prototype.isPrototypeOf.call(o1, o1))
1606  assertFalse(Object.prototype.isPrototypeOf.call(o1, p1))
1607  assertTrue(Object.prototype.isPrototypeOf.call(o1, p2))
1608  assertTrue(Object.prototype.isPrototypeOf.call(o1, p3))
1609  assertFalse(Object.prototype.isPrototypeOf.call(o1, p4))
1610  assertTrue(Object.prototype.isPrototypeOf.call(o1, o2))
1611  assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
1612  assertFalse(Object.prototype.isPrototypeOf.call(p1, o1))
1613  assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
1614  assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
1615  assertFalse(Object.prototype.isPrototypeOf.call(p1, p4))
1616  assertFalse(Object.prototype.isPrototypeOf.call(p1, o2))
1617  assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
1618  assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
1619  assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
1620  assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
1621  assertTrue(Object.prototype.isPrototypeOf.call(p2, o2))
1622  assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
1623  assertTrue(Object.prototype.isPrototypeOf.call(p3, o2))
1624  assertFalse(Object.prototype.isPrototypeOf.call(o2, o1))
1625  assertFalse(Object.prototype.isPrototypeOf.call(o2, p1))
1626  assertFalse(Object.prototype.isPrototypeOf.call(o2, p2))
1627  assertFalse(Object.prototype.isPrototypeOf.call(o2, p3))
1628  assertFalse(Object.prototype.isPrototypeOf.call(o2, p4))
1629  assertFalse(Object.prototype.isPrototypeOf.call(o2, o2))
1630
1631  var f = Proxy.createFunction({}, function() {})
1632  assertSame(Object.getPrototypeOf(f), Function.prototype)
1633  assertTrue(Object.prototype.isPrototypeOf(f))
1634  assertTrue(Object.prototype.isPrototypeOf.call(Function.prototype, f))
1635}
1636
1637TestPrototype()
1638
1639
1640
1641// Property names (Object.getOwnPropertyNames, Object.keys).
1642
1643function TestPropertyNames(names, handler) {
1644  TestWithProxies(TestPropertyNames2, handler, names)
1645}
1646
1647function TestPropertyNames2(create, handler, names) {
1648  var p = create(handler)
1649  assertArrayEquals(names, Object.getOwnPropertyNames(p))
1650}
1651
1652TestPropertyNames([], {
1653  getOwnPropertyNames: function() { return [] }
1654})
1655
1656TestPropertyNames(["a", "zz", " ", "0", "toString"], {
1657  getOwnPropertyNames: function() { return ["a", "zz", " ", 0, "toString"] }
1658})
1659
1660TestPropertyNames(["throw", "function "], {
1661  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1662  getOwnPropertyNames2: function() { return ["throw", "function "] }
1663})
1664
1665TestPropertyNames(["[object Object]"], {
1666  get getOwnPropertyNames() {
1667    return function() { return [{}] }
1668  }
1669})
1670
1671
1672function TestPropertyNamesThrow(handler) {
1673  TestWithProxies(TestPropertyNamesThrow2, handler)
1674}
1675
1676function TestPropertyNamesThrow2(create, handler) {
1677  var p = create(handler)
1678  assertThrows(function(){ Object.getOwnPropertyNames(p) }, "myexn")
1679}
1680
1681TestPropertyNamesThrow({
1682  getOwnPropertyNames: function() { throw "myexn" }
1683})
1684
1685TestPropertyNamesThrow({
1686  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1687  getOwnPropertyNames2: function() { throw "myexn" }
1688})
1689
1690
1691function TestKeys(names, handler) {
1692  TestWithProxies(TestKeys2, handler, names)
1693}
1694
1695function TestKeys2(create, handler, names) {
1696  var p = create(handler)
1697  assertArrayEquals(names, Object.keys(p))
1698}
1699
1700TestKeys([], {
1701  keys: function() { return [] }
1702})
1703
1704TestKeys(["a", "zz", " ", "0", "toString"], {
1705  keys: function() { return ["a", "zz", " ", 0, "toString"] }
1706})
1707
1708TestKeys(["throw", "function "], {
1709  keys: function() { return this.keys2() },
1710  keys2: function() { return ["throw", "function "] }
1711})
1712
1713TestKeys(["[object Object]"], {
1714  get keys() {
1715    return function() { return [{}] }
1716  }
1717})
1718
1719TestKeys(["a", "0"], {
1720  getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
1721  getOwnPropertyDescriptor: function(k) {
1722    return k == "" ? undefined : {enumerable: k.length == 1}
1723  }
1724})
1725
1726TestKeys(["23", "zz", ""], {
1727  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1728  getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] },
1729  getOwnPropertyDescriptor: function(k) {
1730    return this.getOwnPropertyDescriptor2(k)
1731  },
1732  getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} }
1733})
1734
1735TestKeys(["a", "b", "c", "5"], {
1736  get getOwnPropertyNames() {
1737    return function() { return ["0", 4, "a", "b", "c", 5, "ety"] }
1738  },
1739  get getOwnPropertyDescriptor() {
1740    return function(k) {
1741      return k == "ety" ? undefined : {enumerable: k >= "44"}
1742    }
1743  }
1744})
1745
1746TestKeys([], {
1747  get getOwnPropertyNames() {
1748    return function() { return ["a", "b", "c"] }
1749  },
1750  getOwnPropertyDescriptor: function(k) { return {} }
1751})
1752
1753
1754function TestKeysThrow(handler) {
1755  TestWithProxies(TestKeysThrow2, handler)
1756}
1757
1758function TestKeysThrow2(create, handler) {
1759  var p = create(handler)
1760  assertThrows(function(){ Object.keys(p) }, "myexn")
1761}
1762
1763TestKeysThrow({
1764  keys: function() { throw "myexn" }
1765})
1766
1767TestKeysThrow({
1768  keys: function() { return this.keys2() },
1769  keys2: function() { throw "myexn" }
1770})
1771
1772TestKeysThrow({
1773  getOwnPropertyNames: function() { throw "myexn" },
1774  getOwnPropertyDescriptor: function(k) { return true }
1775})
1776
1777TestKeysThrow({
1778  getOwnPropertyNames: function() { return [1, 2] },
1779  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1780})
1781
1782TestKeysThrow({
1783  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1784  getOwnPropertyNames2: function() { throw "myexn" },
1785})
1786
1787TestKeysThrow({
1788  getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
1789  getOwnPropertyNames2: function() { return [1, 2] },
1790  getOwnPropertyDescriptor: function(k) {
1791    return this.getOwnPropertyDescriptor2(k)
1792  },
1793  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
1794})
1795
1796TestKeysThrow({
1797  get getOwnPropertyNames() { throw "myexn" }
1798})
1799
1800TestKeysThrow({
1801  get getOwnPropertyNames() {
1802    return function() { throw "myexn" }
1803  },
1804})
1805
1806TestKeysThrow([], {
1807  get getOwnPropertyNames() {
1808    return function() { return [1, 2] }
1809  },
1810  getOwnPropertyDescriptor: function(k) { throw "myexn" }
1811})
1812
1813
1814
1815// Fixing (Object.freeze, Object.seal, Object.preventExtensions,
1816//         Object.isFrozen, Object.isSealed, Object.isExtensible)
1817
1818function TestFix(names, handler) {
1819  var proto = {p: 77}
1820  var assertFixing = function(o, s, f, e) {
1821    assertEquals(s, Object.isSealed(o))
1822    assertEquals(f, Object.isFrozen(o))
1823    assertEquals(e, Object.isExtensible(o))
1824  }
1825
1826  var p1 = Proxy.create(handler, proto)
1827  assertFixing(p1, false, false, true)
1828  Object.seal(p1)
1829  assertFixing(p1, true, names.length === 0, false)
1830  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p1).sort())
1831  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1832                    Object.keys(p1).sort())
1833  assertEquals(proto, Object.getPrototypeOf(p1))
1834  assertEquals(77, p1.p)
1835  for (var n in p1) {
1836    var desc = Object.getOwnPropertyDescriptor(p1, n)
1837    if (desc !== undefined) assertFalse(desc.configurable)
1838  }
1839
1840  var p2 = Proxy.create(handler, proto)
1841  assertFixing(p2, false, false, true)
1842  Object.freeze(p2)
1843  assertFixing(p2, true, true, false)
1844  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p2).sort())
1845  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1846                    Object.keys(p2).sort())
1847  assertEquals(proto, Object.getPrototypeOf(p2))
1848  assertEquals(77, p2.p)
1849  for (var n in p2) {
1850    var desc = Object.getOwnPropertyDescriptor(p2, n)
1851    if (desc !== undefined) assertFalse(desc.writable)
1852    if (desc !== undefined) assertFalse(desc.configurable)
1853  }
1854
1855  var p3 = Proxy.create(handler, proto)
1856  assertFixing(p3, false, false, true)
1857  Object.preventExtensions(p3)
1858  assertFixing(p3, names.length === 0, names.length === 0, false)
1859  assertArrayEquals(names.sort(), Object.getOwnPropertyNames(p3).sort())
1860  assertArrayEquals(names.filter(function(x) {return x < "z"}).sort(),
1861                    Object.keys(p3).sort())
1862  assertEquals(proto, Object.getPrototypeOf(p3))
1863  assertEquals(77, p3.p)
1864
1865  var p = Proxy.create(handler, proto)
1866  var o = Object.create(p)
1867  assertFixing(p, false, false, true)
1868  assertFixing(o, false, false, true)
1869  Object.freeze(o)
1870  assertFixing(p, false, false, true)
1871  assertFixing(o, true, true, false)
1872}
1873
1874TestFix([], {
1875  fix: function() { return {} }
1876})
1877
1878TestFix(["a", "b", "c", "3", "zz"], {
1879  fix: function() {
1880    return {
1881      a: {value: "a", writable: true, configurable: false, enumerable: true},
1882      b: {value: 33, writable: false, configurable: false, enumerable: true},
1883      c: {value: 0, writable: true, configurable: true, enumerable: true},
1884      '3': {value: true, writable: false, configurable: true, enumerable: true},
1885      zz: {value: 0, enumerable: false}
1886    }
1887  }
1888})
1889
1890TestFix(["a"], {
1891  fix: function() { return this.fix2() },
1892  fix2: function() {
1893    return {a: {value: 4, writable: true, configurable: true, enumerable: true}}
1894  }
1895})
1896
1897TestFix(["b"], {
1898  get fix() {
1899    return function() {
1900      return {b: {configurable: true, writable: true, enumerable: true}}
1901    }
1902  }
1903})
1904
1905
1906function TestFixFunction(fix) {
1907  var f1 = Proxy.createFunction({
1908    fix: function() { return {} }
1909  }, function() {})
1910  fix(f1)
1911  assertEquals(0, f1.length)
1912
1913  var f2 = Proxy.createFunction({
1914    fix: function() { return {length: {value: 3}} }
1915  }, function() {})
1916  fix(f2)
1917  assertEquals(3, f2.length)
1918
1919  var f3 = Proxy.createFunction({
1920    fix: function() { return {length: {value: "huh"}} }
1921  }, function() {})
1922  fix(f3)
1923  assertEquals(0, f1.length)
1924}
1925
1926TestFixFunction(Object.seal)
1927TestFixFunction(Object.freeze)
1928TestFixFunction(Object.preventExtensions)
1929
1930
1931function TestFixThrow(handler) {
1932  TestWithProxies(TestFixThrow2, handler)
1933}
1934
1935function TestFixThrow2(create, handler) {
1936  var p = create(handler, {})
1937  assertThrows(function(){ Object.seal(p) }, "myexn")
1938  assertThrows(function(){ Object.freeze(p) }, "myexn")
1939  assertThrows(function(){ Object.preventExtensions(p) }, "myexn")
1940}
1941
1942TestFixThrow({
1943  fix: function() { throw "myexn" }
1944})
1945
1946TestFixThrow({
1947  fix: function() { return this.fix2() },
1948  fix2: function() { throw "myexn" }
1949})
1950
1951TestFixThrow({
1952  get fix() { throw "myexn" }
1953})
1954
1955TestFixThrow({
1956  get fix() {
1957    return function() { throw "myexn" }
1958  }
1959})
1960
1961
1962// Freeze a proxy in the middle of operations on it.
1963// TODO(rossberg): actual behaviour not specified consistently at the moment,
1964// just make sure that we do not crash.
1965function TestReentrantFix(f) {
1966  TestWithProxies(f, Object.freeze)
1967  TestWithProxies(f, Object.seal)
1968  TestWithProxies(f, Object.preventExtensions)
1969}
1970
1971TestReentrantFix(function(create, freeze) {
1972  var handler = {
1973    get get() { freeze(p); return undefined },
1974    fix: function() { return {} }
1975  }
1976  var p = create(handler)
1977  // Freeze while getting get trap.
1978  try { p.x } catch (e) { assertInstanceof(e, Error) }
1979})
1980
1981TestReentrantFix(function(create, freeze) {
1982  var handler = {
1983    get: function() { freeze(p); return 3 },
1984    fix: function() { return {} }
1985  }
1986  var p = create(handler)
1987  // Freeze while executing get trap.
1988  try { p.x } catch (e) { assertInstanceof(e, Error) }
1989})
1990
1991TestReentrantFix(function(create, freeze) {
1992  var handler = {
1993    getPropertyDescriptor: function() { freeze(p); return undefined },
1994    fix: function() { return {} }
1995  }
1996  var p = create(handler)
1997  // Freeze while executing default get trap.
1998  try { p.x } catch (e) { assertInstanceof(e, Error) }
1999})
2000
2001TestReentrantFix(function(create, freeze) {
2002  var handler = {
2003    getPropertyDescriptor: function() { freeze(p); return {get: function(){}} },
2004    fix: function() { return {} }
2005  }
2006  var p = create(handler)
2007  var o = Object.create(p)
2008  // Freeze while getting a property from prototype.
2009  try { o.x } catch (e) { assertInstanceof(e, Error) }
2010})
2011
2012TestReentrantFix(function(create, freeze) {
2013  var handler = {
2014    get set() { freeze(p); return undefined },
2015    fix: function() { return {} }
2016  }
2017  var p = create(handler)
2018  // Freeze while getting set trap.
2019  try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
2020})
2021
2022TestReentrantFix(function(create, freeze) {
2023  var handler = {
2024    set: function() { freeze(p); return true },
2025    fix: function() { return {} }
2026  }
2027  var p = create(handler)
2028  // Freeze while executing set trap.
2029  try { p.x = 4 } catch (e) { assertInstanceof(e, Error) }
2030})
2031
2032TestReentrantFix(function(create, freeze) {
2033  var handler = {
2034    getOwnPropertyDescriptor: function() { freeze(p); return undefined },
2035    fix: function() { return {} }
2036  }
2037  var p = create(handler)
2038  // Freeze while executing default set trap.
2039  try { p.x } catch (e) { assertInstanceof(e, Error) }
2040})
2041
2042TestReentrantFix(function(create, freeze) {
2043  var handler = {
2044    getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
2045    fix: function() { return {} }
2046  }
2047  var p = create(handler)
2048  var o = Object.create(p)
2049  // Freeze while setting a property in prototype, dropping the property!
2050  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
2051})
2052
2053TestReentrantFix(function(create, freeze) {
2054  var handler = {
2055    getPropertyDescriptor: function() { freeze(p); return {set: function(){}} },
2056    fix: function() { return {x: {get: function(){}}} }
2057  }
2058  var p = create(handler)
2059  var o = Object.create(p)
2060  // Freeze while setting a property in prototype, making it read-only!
2061  try { o.x = 4 } catch (e) { assertInstanceof(e, Error) }
2062})
2063
2064TestReentrantFix(function(create, freeze) {
2065  var handler = {
2066    get fix() { freeze(p); return function(){} }
2067  }
2068  var p = create(handler)
2069  // Freeze while getting fix trap.
2070  try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
2071  p = create(handler)
2072  try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
2073  p = create(handler)
2074  try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
2075})
2076
2077TestReentrantFix(function(create, freeze) {
2078  var handler = {
2079    fix: function() { freeze(p); return {} }
2080  }
2081  var p = create(handler)
2082  // Freeze while executing fix trap.
2083  try { Object.freeze(p) } catch (e) { assertInstanceof(e, Error) }
2084  p = create(handler)
2085  try { Object.seal(p) } catch (e) { assertInstanceof(e, Error) }
2086  p = create(handler)
2087  try { Object.preventExtensions(p) } catch (e) { assertInstanceof(e, Error) }
2088})
2089
2090
2091
2092// String conversion (Object.prototype.toString,
2093//                    Object.prototype.toLocaleString,
2094//                    Function.prototype.toString)
2095
2096var key
2097
2098function TestToString(handler) {
2099  var p = Proxy.create(handler)
2100  key = ""
2101  assertEquals("[object Object]", Object.prototype.toString.call(p))
2102  assertEquals("", key)
2103  assertEquals("my_proxy", Object.prototype.toLocaleString.call(p))
2104  assertEquals("toString", key)
2105
2106  var f = Proxy.createFunction(handler, function() {})
2107  key = ""
2108  assertEquals("[object Function]", Object.prototype.toString.call(f))
2109  assertEquals("", key)
2110  assertEquals("my_proxy", Object.prototype.toLocaleString.call(f))
2111  assertEquals("toString", key)
2112  assertDoesNotThrow(function(){ Function.prototype.toString.call(f) })
2113
2114  var o = Object.create(p)
2115  key = ""
2116  assertEquals("[object Object]", Object.prototype.toString.call(o))
2117  assertEquals("", key)
2118  assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
2119  assertEquals("toString", key)
2120}
2121
2122TestToString({
2123  get: function(r, k) { key = k; return function() { return "my_proxy" } }
2124})
2125
2126TestToString({
2127  get: function(r, k) { return this.get2(r, k) },
2128  get2: function(r, k) { key = k; return function() { return "my_proxy" } }
2129})
2130
2131TestToString(Proxy.create({
2132  get: function(pr, pk) {
2133    return function(r, k) { key = k; return function() { return "my_proxy" } }
2134  }
2135}))
2136
2137
2138function TestToStringThrow(handler) {
2139  var p = Proxy.create(handler)
2140  assertEquals("[object Object]", Object.prototype.toString.call(p))
2141  assertThrows(function(){ Object.prototype.toLocaleString.call(p) }, "myexn")
2142
2143  var f = Proxy.createFunction(handler, function() {})
2144  assertEquals("[object Function]", Object.prototype.toString.call(f))
2145  assertThrows(function(){ Object.prototype.toLocaleString.call(f) }, "myexn")
2146
2147  var o = Object.create(p)
2148  assertEquals("[object Object]", Object.prototype.toString.call(o))
2149  assertThrows(function(){ Object.prototype.toLocaleString.call(o) }, "myexn")
2150}
2151
2152TestToStringThrow({
2153  get: function(r, k) { throw "myexn" }
2154})
2155
2156TestToStringThrow({
2157  get: function(r, k) { return function() { throw "myexn" } }
2158})
2159
2160TestToStringThrow({
2161  get: function(r, k) { return this.get2(r, k) },
2162  get2: function(r, k) { throw "myexn" }
2163})
2164
2165TestToStringThrow(Proxy.create({
2166  get: function(pr, pk) { throw "myexn" }
2167}))
2168
2169TestToStringThrow(Proxy.create({
2170  get: function(pr, pk) {
2171    return function(r, k) { throw "myexn" }
2172  }
2173}))
2174
2175
2176
2177// Value conversion (Object.prototype.toValue)
2178
2179function TestValueOf(handler) {
2180  TestWithProxies(TestValueOf2, handler)
2181}
2182
2183function TestValueOf2(create, handler) {
2184  var p = create(handler)
2185  assertSame(p, Object.prototype.valueOf.call(p))
2186}
2187
2188TestValueOf({})
2189
2190
2191
2192// Enumerability (Object.prototype.propertyIsEnumerable)
2193
2194var key
2195
2196function TestIsEnumerable(handler) {
2197  TestWithProxies(TestIsEnumerable2, handler)
2198}
2199
2200function TestIsEnumerable2(create, handler) {
2201  var p = create(handler)
2202  assertTrue(Object.prototype.propertyIsEnumerable.call(p, "a"))
2203  assertEquals("a", key)
2204  assertTrue(Object.prototype.propertyIsEnumerable.call(p, 2))
2205  assertEquals("2", key)
2206  assertFalse(Object.prototype.propertyIsEnumerable.call(p, "z"))
2207  assertEquals("z", key)
2208
2209  var o = Object.create(p)
2210  key = ""
2211  assertFalse(Object.prototype.propertyIsEnumerable.call(o, "a"))
2212  assertEquals("", key)  // trap not invoked
2213}
2214
2215TestIsEnumerable({
2216  getOwnPropertyDescriptor: function(k) {
2217    key = k; return {enumerable: k < "z", configurable: true}
2218  },
2219})
2220
2221TestIsEnumerable({
2222  getOwnPropertyDescriptor: function(k) {
2223    return this.getOwnPropertyDescriptor2(k)
2224  },
2225  getOwnPropertyDescriptor2: function(k) {
2226    key = k; return {enumerable: k < "z", configurable: true}
2227  },
2228})
2229
2230TestIsEnumerable({
2231  getOwnPropertyDescriptor: function(k) {
2232    key = k; return {get enumerable() { return k < "z" }, configurable: true}
2233  },
2234})
2235
2236TestIsEnumerable(Proxy.create({
2237  get: function(pr, pk) {
2238    return function(k) {
2239      key = k; return {enumerable: k < "z", configurable: true}
2240    }
2241  }
2242}))
2243
2244
2245function TestIsEnumerableThrow(handler) {
2246  TestWithProxies(TestIsEnumerableThrow2, handler)
2247}
2248
2249function TestIsEnumerableThrow2(create, handler) {
2250  var p = create(handler)
2251  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, "a") },
2252    "myexn")
2253  assertThrows(function(){ Object.prototype.propertyIsEnumerable.call(p, 11) },
2254    "myexn")
2255}
2256
2257TestIsEnumerableThrow({
2258  getOwnPropertyDescriptor: function(k) { throw "myexn" }
2259})
2260
2261TestIsEnumerableThrow({
2262  getOwnPropertyDescriptor: function(k) {
2263    return this.getOwnPropertyDescriptor2(k)
2264  },
2265  getOwnPropertyDescriptor2: function(k) { throw "myexn" }
2266})
2267
2268TestIsEnumerableThrow({
2269  getOwnPropertyDescriptor: function(k) {
2270    return {get enumerable() { throw "myexn" }, configurable: true}
2271  },
2272})
2273
2274TestIsEnumerableThrow(Proxy.create({
2275  get: function(pr, pk) { throw "myexn" }
2276}))
2277
2278TestIsEnumerableThrow(Proxy.create({
2279  get: function(pr, pk) {
2280    return function(k) { throw "myexn" }
2281  }
2282}))
2283
2284
2285
2286// Constructor functions with proxy prototypes.
2287
2288function TestConstructorWithProxyPrototype() {
2289  TestWithProxies(TestConstructorWithProxyPrototype2, {})
2290}
2291
2292function TestConstructorWithProxyPrototype2(create, handler) {
2293  function C() {};
2294  C.prototype = create(handler);
2295
2296  var o = new C;
2297  assertSame(C.prototype, Object.getPrototypeOf(o));
2298}
2299
2300TestConstructorWithProxyPrototype();
2301